123b47e0bSJérôme Duval /* 2fdad31e6SMichael Lotz * Copyright 2004-2011, Haiku. 323b47e0bSJérôme Duval * Distributed under the terms of the MIT License. 423b47e0bSJérôme Duval * 523b47e0bSJérôme Duval * Authors: 6d246d9beSStefano Ceccherini * Stefano Ceccherini (stefano.ceccherini@gmail.com) 7d246d9beSStefano Ceccherini * Jérôme Duval 8d246d9beSStefano Ceccherini * Axel Dörfler, axeld@pinc-software.de 9167f43a2SStephan Aßmus * Clemens Zeidler, haiku@clemens-zeidler.de 10239fd643SStephan Aßmus * Stephan Aßmus, superstippi@gmx.de 1123b47e0bSJérôme Duval */ 1233efb919SStefano Ceccherini 1333efb919SStefano Ceccherini 1461d7deeeSJérôme Duval #include "MouseInputDevice.h" 15b6a7b204SAxel Dörfler 16b6a7b204SAxel Dörfler #include <errno.h> 17b6a7b204SAxel Dörfler #include <new> 18b6a7b204SAxel Dörfler #include <stdio.h> 19b6a7b204SAxel Dörfler #include <stdlib.h> 20b6a7b204SAxel Dörfler #include <unistd.h> 2161d7deeeSJérôme Duval 225125eae2SStephan Aßmus #include <Autolock.h> 23c2fbfb71SJérôme Duval #include <Debug.h> 2433efb919SStefano Ceccherini #include <Directory.h> 2533efb919SStefano Ceccherini #include <Entry.h> 26167f43a2SStephan Aßmus #include <File.h> 27167f43a2SStephan Aßmus #include <FindDirectory.h> 2833efb919SStefano Ceccherini #include <NodeMonitor.h> 2933efb919SStefano Ceccherini #include <Path.h> 3033efb919SStefano Ceccherini #include <String.h> 3161604e48SAxel Dörfler #include <View.h> 3261604e48SAxel Dörfler 332c494653SAxel Dörfler #include <kb_mouse_settings.h> 342c494653SAxel Dörfler #include <keyboard_mouse_driver.h> 352c494653SAxel Dörfler #include <touchpad_settings.h> 3633efb919SStefano Ceccherini 37b6a7b204SAxel Dörfler 38e01a0431SStephan Aßmus #undef TRACE 39b6a7b204SAxel Dörfler //#define TRACE_MOUSE_DEVICE 40b6a7b204SAxel Dörfler #ifdef TRACE_MOUSE_DEVICE 41e01a0431SStephan Aßmus 42e01a0431SStephan Aßmus class FunctionTracer { 43e01a0431SStephan Aßmus public: 44e01a0431SStephan Aßmus FunctionTracer(const void* pointer, const char* className, 45e01a0431SStephan Aßmus const char* functionName, 46e01a0431SStephan Aßmus int32& depth) 47e01a0431SStephan Aßmus : fFunctionName(), 48e01a0431SStephan Aßmus fPrepend(), 49e01a0431SStephan Aßmus fFunctionDepth(depth), 50e01a0431SStephan Aßmus fPointer(pointer) 51e01a0431SStephan Aßmus { 52e01a0431SStephan Aßmus fFunctionDepth++; 53e01a0431SStephan Aßmus fPrepend.Append(' ', fFunctionDepth * 2); 54e01a0431SStephan Aßmus fFunctionName << className << "::" << functionName << "()"; 55e01a0431SStephan Aßmus 56e01a0431SStephan Aßmus debug_printf("%p -> %s%s {\n", fPointer, fPrepend.String(), 57e01a0431SStephan Aßmus fFunctionName.String()); 58e01a0431SStephan Aßmus } 59e01a0431SStephan Aßmus 60e01a0431SStephan Aßmus ~FunctionTracer() 61e01a0431SStephan Aßmus { 62e01a0431SStephan Aßmus debug_printf("%p -> %s}\n", fPointer, fPrepend.String()); 63e01a0431SStephan Aßmus fFunctionDepth--; 64e01a0431SStephan Aßmus } 65e01a0431SStephan Aßmus 66e01a0431SStephan Aßmus private: 67e01a0431SStephan Aßmus BString fFunctionName; 68e01a0431SStephan Aßmus BString fPrepend; 69e01a0431SStephan Aßmus int32& fFunctionDepth; 70e01a0431SStephan Aßmus const void* fPointer; 71e01a0431SStephan Aßmus }; 72e01a0431SStephan Aßmus 73e01a0431SStephan Aßmus 74e01a0431SStephan Aßmus static int32 sFunctionDepth = -1; 75e01a0431SStephan Aßmus # define MD_CALLED(x...) FunctionTracer _ft(this, "MouseDevice", \ 76e01a0431SStephan Aßmus __FUNCTION__, sFunctionDepth) 77e01a0431SStephan Aßmus # define MID_CALLED(x...) FunctionTracer _ft(this, "MouseInputDevice", \ 78e01a0431SStephan Aßmus __FUNCTION__, sFunctionDepth) 79e02ed691SRene Gollent # define TRACE(x...) do { BString _to; \ 80e01a0431SStephan Aßmus _to.Append(' ', (sFunctionDepth + 1) * 2); \ 81e01a0431SStephan Aßmus debug_printf("%p -> %s", this, _to.String()); \ 82e02ed691SRene Gollent debug_printf(x); } while (0) 83e01a0431SStephan Aßmus # define LOG_EVENT(text...) do {} while (0) 845125eae2SStephan Aßmus # define LOG_ERR(text...) TRACE(text) 853aa69c78SStefano Ceccherini #else 86e01a0431SStephan Aßmus # define TRACE(x...) do {} while (0) 87e01a0431SStephan Aßmus # define MD_CALLED(x...) TRACE(x) 88e01a0431SStephan Aßmus # define MID_CALLED(x...) TRACE(x) 896e094221SStephan Aßmus # define LOG_ERR(x...) debug_printf(x) 906e094221SStephan Aßmus # define LOG_EVENT(x...) TRACE(x) 913aa69c78SStefano Ceccherini #endif 923aa69c78SStefano Ceccherini 93e01a0431SStephan Aßmus 9433efb919SStefano Ceccherini const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4; 9533efb919SStefano Ceccherini const static char* kMouseDevicesDirectory = "/dev/input/mouse"; 96167f43a2SStephan Aßmus const static char* kTouchpadDevicesDirectory = "/dev/input/touchpad"; 9733efb919SStefano Ceccherini 9833efb919SStefano Ceccherini 9961604e48SAxel Dörfler class MouseDevice { 10061604e48SAxel Dörfler public: 1015125eae2SStephan Aßmus MouseDevice(MouseInputDevice& target, 1025125eae2SStephan Aßmus const char* path); 10361604e48SAxel Dörfler ~MouseDevice(); 10433efb919SStefano Ceccherini 10561604e48SAxel Dörfler status_t Start(); 10661604e48SAxel Dörfler void Stop(); 10761604e48SAxel Dörfler 10861604e48SAxel Dörfler status_t UpdateSettings(); 109167f43a2SStephan Aßmus status_t UpdateTouchpadSettings(const BMessage* message); 11061604e48SAxel Dörfler 11161604e48SAxel Dörfler const char* Path() const { return fPath.String(); } 11261604e48SAxel Dörfler input_device_ref* DeviceRef() { return &fDeviceRef; } 11361604e48SAxel Dörfler 11461604e48SAxel Dörfler private: 1155125eae2SStephan Aßmus char* _BuildShortName() const; 11661604e48SAxel Dörfler 1175125eae2SStephan Aßmus static status_t _ControlThreadEntry(void* arg); 1185125eae2SStephan Aßmus void _ControlThread(); 1195125eae2SStephan Aßmus void _ControlThreadCleanup(); 1205125eae2SStephan Aßmus void _UpdateSettings(); 1215125eae2SStephan Aßmus 122167f43a2SStephan Aßmus status_t _GetTouchpadSettingsPath(BPath& path); 123167f43a2SStephan Aßmus status_t _ReadTouchpadSettingsMsg(BMessage* message); 124167f43a2SStephan Aßmus status_t _UpdateTouchpadSettings(); 125167f43a2SStephan Aßmus 1265125eae2SStephan Aßmus BMessage* _BuildMouseMessage(uint32 what, 1275125eae2SStephan Aßmus uint64 when, uint32 buttons, 12861604e48SAxel Dörfler int32 deltaX, int32 deltaY) const; 1295125eae2SStephan Aßmus void _ComputeAcceleration( 1305125eae2SStephan Aßmus const mouse_movement& movements, 1316e094221SStephan Aßmus int32& deltaX, int32& deltaY, 1326e094221SStephan Aßmus float& historyDeltaX, 1336e094221SStephan Aßmus float& historyDeltaY) const; 13461604e48SAxel Dörfler uint32 _RemapButtons(uint32 buttons) const; 13561604e48SAxel Dörfler 13661604e48SAxel Dörfler private: 137c5555ad3SStephan Aßmus MouseInputDevice& fTarget; 13861604e48SAxel Dörfler BString fPath; 13961604e48SAxel Dörfler int fDevice; 14061604e48SAxel Dörfler 14161604e48SAxel Dörfler input_device_ref fDeviceRef; 14261604e48SAxel Dörfler mouse_settings fSettings; 14361604e48SAxel Dörfler bool fDeviceRemapsButtons; 14461604e48SAxel Dörfler 14561604e48SAxel Dörfler thread_id fThread; 14661604e48SAxel Dörfler volatile bool fActive; 1475125eae2SStephan Aßmus volatile bool fUpdateSettings; 148167f43a2SStephan Aßmus 149167f43a2SStephan Aßmus bool fIsTouchpad; 150167f43a2SStephan Aßmus touchpad_settings fTouchpadSettings; 151167f43a2SStephan Aßmus BMessage* fTouchpadSettingsMessage; 152167f43a2SStephan Aßmus BLocker fTouchpadSettingsLock; 1530dbc4befSStefano Ceccherini }; 1540dbc4befSStefano Ceccherini 1550dbc4befSStefano Ceccherini 15661604e48SAxel Dörfler extern "C" BInputServerDevice* 15761d7deeeSJérôme Duval instantiate_input_device() 15861d7deeeSJérôme Duval { 159d246d9beSStefano Ceccherini return new(std::nothrow) MouseInputDevice(); 16061d7deeeSJérôme Duval } 16161d7deeeSJérôme Duval 16261d7deeeSJérôme Duval 16361604e48SAxel Dörfler // #pragma mark - 16461604e48SAxel Dörfler 16561604e48SAxel Dörfler 166c5555ad3SStephan Aßmus MouseDevice::MouseDevice(MouseInputDevice& target, const char* driverPath) 16761604e48SAxel Dörfler : 16861604e48SAxel Dörfler fTarget(target), 169c5555ad3SStephan Aßmus fPath(driverPath), 17061604e48SAxel Dörfler fDevice(-1), 171e01a0431SStephan Aßmus fDeviceRemapsButtons(false), 17261604e48SAxel Dörfler fThread(-1), 1735125eae2SStephan Aßmus fActive(false), 174167f43a2SStephan Aßmus fUpdateSettings(false), 175167f43a2SStephan Aßmus fIsTouchpad(false), 176167f43a2SStephan Aßmus fTouchpadSettingsMessage(NULL), 177167f43a2SStephan Aßmus fTouchpadSettingsLock("Touchpad settings lock") 17861d7deeeSJérôme Duval { 179e01a0431SStephan Aßmus MD_CALLED(); 180e01a0431SStephan Aßmus 18161604e48SAxel Dörfler fDeviceRef.name = _BuildShortName(); 18261604e48SAxel Dörfler fDeviceRef.type = B_POINTING_DEVICE; 18361604e48SAxel Dörfler fDeviceRef.cookie = this; 18461604e48SAxel Dörfler 18561604e48SAxel Dörfler #ifdef HAIKU_TARGET_PLATFORM_HAIKU 1865bbf7f1bSAdrien Destugues for (int i = 0; i < B_MAX_MOUSE_BUTTONS; i++) 1875bbf7f1bSAdrien Destugues fSettings.map.button[i] = B_MOUSE_BUTTON(i + 1); 1883aa69c78SStefano Ceccherini #endif 18961604e48SAxel Dörfler }; 19061d7deeeSJérôme Duval 19161d7deeeSJérôme Duval 19261604e48SAxel Dörfler MouseDevice::~MouseDevice() 19361d7deeeSJérôme Duval { 194e01a0431SStephan Aßmus MD_CALLED(); 195e01a0431SStephan Aßmus TRACE("delete\n"); 196e01a0431SStephan Aßmus 19761604e48SAxel Dörfler if (fActive) 19861604e48SAxel Dörfler Stop(); 19961d7deeeSJérôme Duval 20061604e48SAxel Dörfler free(fDeviceRef.name); 201167f43a2SStephan Aßmus delete fTouchpadSettingsMessage; 20261d7deeeSJérôme Duval } 20361d7deeeSJérôme Duval 20461d7deeeSJérôme Duval 20561d7deeeSJérôme Duval status_t 20661604e48SAxel Dörfler MouseDevice::Start() 20753d77642SJérôme Duval { 208e01a0431SStephan Aßmus MD_CALLED(); 209e01a0431SStephan Aßmus 21061604e48SAxel Dörfler fDevice = open(fPath.String(), O_RDWR); 2115125eae2SStephan Aßmus // let the control thread handle any error on opening the device 21233efb919SStefano Ceccherini 21333efb919SStefano Ceccherini char threadName[B_OS_NAME_LENGTH]; 21461604e48SAxel Dörfler snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", fDeviceRef.name); 21533efb919SStefano Ceccherini 2165125eae2SStephan Aßmus fThread = spawn_thread(_ControlThreadEntry, threadName, 21761604e48SAxel Dörfler kMouseThreadPriority, (void*)this); 2184c0af4a8SStefano Ceccherini 21933efb919SStefano Ceccherini status_t status; 220fdad31e6SMichael Lotz if (fThread < 0) 22161604e48SAxel Dörfler status = fThread; 22261604e48SAxel Dörfler else { 22361604e48SAxel Dörfler fActive = true; 22461604e48SAxel Dörfler status = resume_thread(fThread); 22561604e48SAxel Dörfler } 22633efb919SStefano Ceccherini 22761604e48SAxel Dörfler if (status < B_OK) { 22861604e48SAxel Dörfler LOG_ERR("%s: can't spawn/resume watching thread: %s\n", 22961604e48SAxel Dörfler fDeviceRef.name, strerror(status)); 230fdad31e6SMichael Lotz if (fDevice >= 0) 231167f43a2SStephan Aßmus close(fDevice); 23214a12accSFredrik Holmqvist 23361604e48SAxel Dörfler return status; 23461604e48SAxel Dörfler } 23561604e48SAxel Dörfler 2369195fe6eSStephan Aßmus return fDevice >= 0 ? B_OK : B_ERROR; 23761d7deeeSJérôme Duval } 23861d7deeeSJérôme Duval 23961d7deeeSJérôme Duval 240c2fbfb71SJérôme Duval void 24161604e48SAxel Dörfler MouseDevice::Stop() 24261604e48SAxel Dörfler { 243e01a0431SStephan Aßmus MD_CALLED(); 2441ccc2f2dSJérôme Duval 24561604e48SAxel Dörfler fActive = false; 24661604e48SAxel Dörfler // this will stop the thread as soon as it reads the next packet 24761604e48SAxel Dörfler 248e01a0431SStephan Aßmus close(fDevice); 249e01a0431SStephan Aßmus fDevice = -1; 250e01a0431SStephan Aßmus 251fdad31e6SMichael Lotz if (fThread >= 0) { 25261604e48SAxel Dörfler // unblock the thread, which might wait on a semaphore. 25361604e48SAxel Dörfler suspend_thread(fThread); 25461604e48SAxel Dörfler resume_thread(fThread); 25561604e48SAxel Dörfler 25661604e48SAxel Dörfler status_t dummy; 25761604e48SAxel Dörfler wait_for_thread(fThread, &dummy); 25861604e48SAxel Dörfler } 25961604e48SAxel Dörfler } 26061604e48SAxel Dörfler 26161604e48SAxel Dörfler 26242b505fbSAxel Dörfler status_t 26342b505fbSAxel Dörfler MouseDevice::UpdateSettings() 26442b505fbSAxel Dörfler { 265e01a0431SStephan Aßmus MD_CALLED(); 26642b505fbSAxel Dörfler 2675125eae2SStephan Aßmus if (fThread < 0) 2685125eae2SStephan Aßmus return B_ERROR; 26942b505fbSAxel Dörfler 270167f43a2SStephan Aßmus // trigger updating the settings in the control thread 2715125eae2SStephan Aßmus fUpdateSettings = true; 272167f43a2SStephan Aßmus 273167f43a2SStephan Aßmus return B_OK; 274167f43a2SStephan Aßmus } 275167f43a2SStephan Aßmus 276167f43a2SStephan Aßmus 277167f43a2SStephan Aßmus status_t 278167f43a2SStephan Aßmus MouseDevice::UpdateTouchpadSettings(const BMessage* message) 279167f43a2SStephan Aßmus { 280167f43a2SStephan Aßmus if (!fIsTouchpad) 281167f43a2SStephan Aßmus return B_BAD_TYPE; 282167f43a2SStephan Aßmus if (fThread < 0) 283167f43a2SStephan Aßmus return B_ERROR; 284167f43a2SStephan Aßmus 285167f43a2SStephan Aßmus BAutolock _(fTouchpadSettingsLock); 286167f43a2SStephan Aßmus 287167f43a2SStephan Aßmus // trigger updating the settings in the control thread 288167f43a2SStephan Aßmus fUpdateSettings = true; 289167f43a2SStephan Aßmus 290167f43a2SStephan Aßmus delete fTouchpadSettingsMessage; 291167f43a2SStephan Aßmus fTouchpadSettingsMessage = new BMessage(*message); 292fdad31e6SMichael Lotz if (fTouchpadSettingsMessage == NULL) 293fdad31e6SMichael Lotz return B_NO_MEMORY; 29442b505fbSAxel Dörfler 29542b505fbSAxel Dörfler return B_OK; 2965125eae2SStephan Aßmus } 29742b505fbSAxel Dörfler 2985125eae2SStephan Aßmus 2995125eae2SStephan Aßmus char* 3005125eae2SStephan Aßmus MouseDevice::_BuildShortName() const 3015125eae2SStephan Aßmus { 302ffd6c2f4SAdrien Destugues // TODO It would be simpler and better to use B_GET_DEVICE_NAME, but... 303ffd6c2f4SAdrien Destugues // - This is currently called before the device is open 304ffd6c2f4SAdrien Destugues // - We need to implement that in our input drivers first 3055125eae2SStephan Aßmus BString string(fPath); 306ffd6c2f4SAdrien Destugues BString deviceName; 3075125eae2SStephan Aßmus BString name; 3085125eae2SStephan Aßmus 3095125eae2SStephan Aßmus int32 slash = string.FindLast("/"); 310ffd6c2f4SAdrien Destugues string.CopyInto(deviceName, slash + 1, string.Length() - slash); 311ffd6c2f4SAdrien Destugues // FIXME the device name may be more than just a number (for example 312ffd6c2f4SAdrien Destugues // ibm_trackpoint_0) 313ffd6c2f4SAdrien Destugues int32 index = atoi(deviceName.String()) + 1; 3145125eae2SStephan Aßmus 3155125eae2SStephan Aßmus int32 previousSlash = string.FindLast("/", slash); 3165125eae2SStephan Aßmus string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1); 3175125eae2SStephan Aßmus 3185125eae2SStephan Aßmus if (name == "ps2") 3195125eae2SStephan Aßmus name = "PS/2"; 320155b8260SPhilippe Houdoin 321ffd6c2f4SAdrien Destugues if (name.Length() <= 4) 322155b8260SPhilippe Houdoin name.ToUpper(); 3235125eae2SStephan Aßmus else 3245125eae2SStephan Aßmus name.Capitalize(); 3255125eae2SStephan Aßmus 326f32bcfd5SAdrien Destugues // Check the whole string for "touchpad" because it's a different directory 327f32bcfd5SAdrien Destugues // FIXME use MS_IS_TOUCHPAD ioctl instead (or fIsTouchpad which caches its 328f32bcfd5SAdrien Destugues // result) but this can only be done after the control thread is running 329f32bcfd5SAdrien Destugues if (string.FindFirst("touchpad") >= 0) { 330167f43a2SStephan Aßmus name << " Touchpad "; 331ffd6c2f4SAdrien Destugues } else if (deviceName.FindFirst("trackpoint") >= 0) { 332ffd6c2f4SAdrien Destugues // That's always PS/2, so don't keep the bus name 333ffd6c2f4SAdrien Destugues name = "Trackpoint "; 334167f43a2SStephan Aßmus } else { 335ffd6c2f4SAdrien Destugues if (deviceName.FindFirst("intelli") >= 0) 336cc442411SStephan Aßmus name.Prepend("Extended "); 337cc442411SStephan Aßmus 338167f43a2SStephan Aßmus name << " Mouse "; 339167f43a2SStephan Aßmus } 340167f43a2SStephan Aßmus name << index; 3415125eae2SStephan Aßmus 3425125eae2SStephan Aßmus return strdup(name.String()); 3435125eae2SStephan Aßmus } 3445125eae2SStephan Aßmus 3455125eae2SStephan Aßmus 3465125eae2SStephan Aßmus // #pragma mark - control thread 3475125eae2SStephan Aßmus 3485125eae2SStephan Aßmus 3495125eae2SStephan Aßmus status_t 3505125eae2SStephan Aßmus MouseDevice::_ControlThreadEntry(void* arg) 3515125eae2SStephan Aßmus { 3525125eae2SStephan Aßmus MouseDevice* device = (MouseDevice*)arg; 3535125eae2SStephan Aßmus device->_ControlThread(); 3545125eae2SStephan Aßmus return B_OK; 35542b505fbSAxel Dörfler } 35642b505fbSAxel Dörfler 35742b505fbSAxel Dörfler 35861604e48SAxel Dörfler void 3595125eae2SStephan Aßmus MouseDevice::_ControlThread() 36061604e48SAxel Dörfler { 361167f43a2SStephan Aßmus MD_CALLED(); 362167f43a2SStephan Aßmus 3635125eae2SStephan Aßmus if (fDevice < 0) { 3645125eae2SStephan Aßmus _ControlThreadCleanup(); 3655125eae2SStephan Aßmus // TOAST! 3665125eae2SStephan Aßmus return; 3675125eae2SStephan Aßmus } 3685125eae2SStephan Aßmus 369167f43a2SStephan Aßmus // touchpad settings 370167f43a2SStephan Aßmus if (ioctl(fDevice, MS_IS_TOUCHPAD, NULL) == B_OK) { 371167f43a2SStephan Aßmus TRACE("is touchpad %s\n", fPath.String()); 372167f43a2SStephan Aßmus fIsTouchpad = true; 373167f43a2SStephan Aßmus 374167f43a2SStephan Aßmus fTouchpadSettings = kDefaultTouchpadSettings; 375167f43a2SStephan Aßmus 376167f43a2SStephan Aßmus BPath path; 377167f43a2SStephan Aßmus status_t status = _GetTouchpadSettingsPath(path); 378167f43a2SStephan Aßmus BFile settingsFile(path.Path(), B_READ_ONLY); 379167f43a2SStephan Aßmus if (status == B_OK && settingsFile.InitCheck() == B_OK) { 380167f43a2SStephan Aßmus if (settingsFile.Read(&fTouchpadSettings, sizeof(touchpad_settings)) 381167f43a2SStephan Aßmus != sizeof(touchpad_settings)) { 382167f43a2SStephan Aßmus TRACE("failed to load settings\n"); 383167f43a2SStephan Aßmus } 384167f43a2SStephan Aßmus } 385167f43a2SStephan Aßmus _UpdateTouchpadSettings(); 386167f43a2SStephan Aßmus } 387167f43a2SStephan Aßmus 3885125eae2SStephan Aßmus _UpdateSettings(); 3895125eae2SStephan Aßmus 39061604e48SAxel Dörfler uint32 lastButtons = 0; 3916e094221SStephan Aßmus float historyDeltaX = 0.0; 3926e094221SStephan Aßmus float historyDeltaY = 0.0; 39361604e48SAxel Dörfler 3947d1d7033SStephan Aßmus static const bigtime_t kTransferDelay = 1000000 / 125; 3957d1d7033SStephan Aßmus // 125 transfers per second should be more than enough 3965994d47aSStephan Aßmus #define USE_REGULAR_INTERVAL 1 3977d1d7033SStephan Aßmus #if USE_REGULAR_INTERVAL 3987d1d7033SStephan Aßmus bigtime_t nextTransferTime = system_time() + kTransferDelay; 3997d1d7033SStephan Aßmus #endif 4007d1d7033SStephan Aßmus 40161604e48SAxel Dörfler while (fActive) { 40261604e48SAxel Dörfler mouse_movement movements; 4037d1d7033SStephan Aßmus 4047d1d7033SStephan Aßmus #if USE_REGULAR_INTERVAL 4057d1d7033SStephan Aßmus snooze_until(nextTransferTime, B_SYSTEM_TIMEBASE); 4067d1d7033SStephan Aßmus nextTransferTime += kTransferDelay; 4077d1d7033SStephan Aßmus #endif 4087d1d7033SStephan Aßmus 409308e87fcSRene Gollent if (ioctl(fDevice, MS_READ, &movements, sizeof(movements)) != B_OK) { 410308e87fcSRene Gollent LOG_ERR("Mouse device exiting, %s\n", strerror(errno)); 4115125eae2SStephan Aßmus _ControlThreadCleanup(); 412c5555ad3SStephan Aßmus // TOAST! 41361604e48SAxel Dörfler return; 414c5555ad3SStephan Aßmus } 41561604e48SAxel Dörfler 4165125eae2SStephan Aßmus // take care of updating the settings first, if necessary 4175125eae2SStephan Aßmus if (fUpdateSettings) { 4185125eae2SStephan Aßmus fUpdateSettings = false; 419167f43a2SStephan Aßmus if (fIsTouchpad) { 420167f43a2SStephan Aßmus BAutolock _(fTouchpadSettingsLock); 4213bf47305SAxel Dörfler if (fTouchpadSettingsMessage != NULL) { 422167f43a2SStephan Aßmus _ReadTouchpadSettingsMsg(fTouchpadSettingsMessage); 423167f43a2SStephan Aßmus _UpdateTouchpadSettings(); 424167f43a2SStephan Aßmus delete fTouchpadSettingsMessage; 425167f43a2SStephan Aßmus fTouchpadSettingsMessage = NULL; 426167f43a2SStephan Aßmus } else 427167f43a2SStephan Aßmus _UpdateSettings(); 428167f43a2SStephan Aßmus } else 429167f43a2SStephan Aßmus _UpdateSettings(); 4305125eae2SStephan Aßmus } 4315125eae2SStephan Aßmus 43261604e48SAxel Dörfler uint32 buttons = lastButtons ^ movements.buttons; 43361604e48SAxel Dörfler 43461604e48SAxel Dörfler uint32 remappedButtons = _RemapButtons(movements.buttons); 43561604e48SAxel Dörfler int32 deltaX, deltaY; 4366e094221SStephan Aßmus _ComputeAcceleration(movements, deltaX, deltaY, historyDeltaX, 4376e094221SStephan Aßmus historyDeltaY); 43861604e48SAxel Dörfler 4396e094221SStephan Aßmus LOG_EVENT("%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld, " 4406e094221SStephan Aßmus "wheel_x:%ld, wheel_y:%ld\n", 4416e094221SStephan Aßmus fDeviceRef.name, movements.buttons, 4426e094221SStephan Aßmus movements.xdelta, movements.ydelta, movements.clicks, 4436e094221SStephan Aßmus movements.wheel_xdelta, movements.wheel_ydelta); 4446e094221SStephan Aßmus LOG_EVENT("%s: x: %ld, y: %ld (%.4f, %.4f)\n", fDeviceRef.name, 4456e094221SStephan Aßmus deltaX, deltaY, historyDeltaX, historyDeltaY); 44661604e48SAxel Dörfler 44761604e48SAxel Dörfler // Send single messages for each event 44861604e48SAxel Dörfler 44961604e48SAxel Dörfler if (buttons != 0) { 45061604e48SAxel Dörfler bool pressedButton = (buttons & movements.buttons) > 0; 45161604e48SAxel Dörfler BMessage* message = _BuildMouseMessage( 45261604e48SAxel Dörfler pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP, 45361604e48SAxel Dörfler movements.timestamp, remappedButtons, deltaX, deltaY); 45461604e48SAxel Dörfler if (message != NULL) { 45561604e48SAxel Dörfler if (pressedButton) { 45661604e48SAxel Dörfler message->AddInt32("clicks", movements.clicks); 457e01a0431SStephan Aßmus LOG_EVENT("B_MOUSE_DOWN\n"); 45861604e48SAxel Dörfler } else 459e01a0431SStephan Aßmus LOG_EVENT("B_MOUSE_UP\n"); 46061604e48SAxel Dörfler 46161604e48SAxel Dörfler fTarget.EnqueueMessage(message); 46261604e48SAxel Dörfler lastButtons = movements.buttons; 46361604e48SAxel Dörfler } 46461604e48SAxel Dörfler } 46561604e48SAxel Dörfler 46645f11ce8SStephan Aßmus if (movements.xdelta != 0 || movements.ydelta != 0) { 46745f11ce8SStephan Aßmus BMessage* message = _BuildMouseMessage(B_MOUSE_MOVED, 46845f11ce8SStephan Aßmus movements.timestamp, remappedButtons, deltaX, deltaY); 46945f11ce8SStephan Aßmus if (message != NULL) 47045f11ce8SStephan Aßmus fTarget.EnqueueMessage(message); 47145f11ce8SStephan Aßmus } 47245f11ce8SStephan Aßmus 473fdad31e6SMichael Lotz if (movements.wheel_ydelta != 0 || movements.wheel_xdelta != 0) { 474c5555ad3SStephan Aßmus BMessage* message = new BMessage(B_MOUSE_WHEEL_CHANGED); 47561604e48SAxel Dörfler if (message == NULL) 47661604e48SAxel Dörfler continue; 47761604e48SAxel Dörfler 47861604e48SAxel Dörfler if (message->AddInt64("when", movements.timestamp) == B_OK 4793bf47305SAxel Dörfler && message->AddFloat("be:wheel_delta_x", 4803bf47305SAxel Dörfler movements.wheel_xdelta) == B_OK 4813bf47305SAxel Dörfler && message->AddFloat("be:wheel_delta_y", 4823bf47305SAxel Dörfler movements.wheel_ydelta) == B_OK) 48361604e48SAxel Dörfler fTarget.EnqueueMessage(message); 48461604e48SAxel Dörfler else 48561604e48SAxel Dörfler delete message; 48661604e48SAxel Dörfler } 4877d1d7033SStephan Aßmus 4887d1d7033SStephan Aßmus #if !USE_REGULAR_INTERVAL 4897d1d7033SStephan Aßmus snooze(kTransferDelay); 4907d1d7033SStephan Aßmus #endif 49161604e48SAxel Dörfler } 49261604e48SAxel Dörfler } 49361604e48SAxel Dörfler 49461604e48SAxel Dörfler 4955125eae2SStephan Aßmus void 4965125eae2SStephan Aßmus MouseDevice::_ControlThreadCleanup() 49761604e48SAxel Dörfler { 4985125eae2SStephan Aßmus // NOTE: Only executed when the control thread detected an error 4995125eae2SStephan Aßmus // and from within the control thread! 5005125eae2SStephan Aßmus 5015125eae2SStephan Aßmus if (fActive) { 5025125eae2SStephan Aßmus fThread = -1; 5035125eae2SStephan Aßmus fTarget._RemoveDevice(fPath.String()); 5045125eae2SStephan Aßmus } else { 5055125eae2SStephan Aßmus // In case active is already false, another thread 5065125eae2SStephan Aßmus // waits for this thread to quit, and may already hold 507fdad31e6SMichael Lotz // locks that _RemoveDevice() wants to acquire. In other 5085125eae2SStephan Aßmus // words, the device is already being removed, so we simply 5095125eae2SStephan Aßmus // quit here. 5105125eae2SStephan Aßmus } 5115125eae2SStephan Aßmus } 5125125eae2SStephan Aßmus 5135125eae2SStephan Aßmus 5145125eae2SStephan Aßmus void 5155125eae2SStephan Aßmus MouseDevice::_UpdateSettings() 5165125eae2SStephan Aßmus { 5175125eae2SStephan Aßmus MD_CALLED(); 5185125eae2SStephan Aßmus // retrieve current values 5195125eae2SStephan Aßmus 5205125eae2SStephan Aßmus if (get_mouse_map(&fSettings.map) != B_OK) 5215125eae2SStephan Aßmus LOG_ERR("error when get_mouse_map\n"); 5225125eae2SStephan Aßmus else { 5235125eae2SStephan Aßmus fDeviceRemapsButtons 5245125eae2SStephan Aßmus = ioctl(fDevice, MS_SET_MAP, &fSettings.map) == B_OK; 5255125eae2SStephan Aßmus } 5265125eae2SStephan Aßmus 5275125eae2SStephan Aßmus if (get_click_speed(&fSettings.click_speed) != B_OK) 5285125eae2SStephan Aßmus LOG_ERR("error when get_click_speed\n"); 5295125eae2SStephan Aßmus else 5305125eae2SStephan Aßmus ioctl(fDevice, MS_SET_CLICKSPEED, &fSettings.click_speed); 5315125eae2SStephan Aßmus 532*68d1b97eSAugustin Cavalier if (get_mouse_speed(fDeviceRef.name, &fSettings.accel.speed) != B_OK) 5335125eae2SStephan Aßmus LOG_ERR("error when get_mouse_speed\n"); 5345125eae2SStephan Aßmus else { 535*68d1b97eSAugustin Cavalier if (get_mouse_acceleration(fDeviceRef.name, &fSettings.accel.accel_factor) != B_OK) 5365125eae2SStephan Aßmus LOG_ERR("error when get_mouse_acceleration\n"); 5375125eae2SStephan Aßmus else { 5385125eae2SStephan Aßmus mouse_accel accel; 5395125eae2SStephan Aßmus ioctl(fDevice, MS_GET_ACCEL, &accel); 5405125eae2SStephan Aßmus accel.speed = fSettings.accel.speed; 5415125eae2SStephan Aßmus accel.accel_factor = fSettings.accel.accel_factor; 5425125eae2SStephan Aßmus ioctl(fDevice, MS_SET_ACCEL, &fSettings.accel); 5435125eae2SStephan Aßmus } 5445125eae2SStephan Aßmus } 5455125eae2SStephan Aßmus 546*68d1b97eSAugustin Cavalier if (get_mouse_type(fDeviceRef.name, &fSettings.type) != B_OK) 5475125eae2SStephan Aßmus LOG_ERR("error when get_mouse_type\n"); 5485125eae2SStephan Aßmus else 5495125eae2SStephan Aßmus ioctl(fDevice, MS_SET_TYPE, &fSettings.type); 55061604e48SAxel Dörfler } 55161604e48SAxel Dörfler 55261604e48SAxel Dörfler 553167f43a2SStephan Aßmus status_t 554167f43a2SStephan Aßmus MouseDevice::_GetTouchpadSettingsPath(BPath& path) 555167f43a2SStephan Aßmus { 556167f43a2SStephan Aßmus status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); 557167f43a2SStephan Aßmus if (status < B_OK) 558167f43a2SStephan Aßmus return status; 559167f43a2SStephan Aßmus return path.Append(TOUCHPAD_SETTINGS_FILE); 560167f43a2SStephan Aßmus } 561167f43a2SStephan Aßmus 562167f43a2SStephan Aßmus 563167f43a2SStephan Aßmus status_t 564167f43a2SStephan Aßmus MouseDevice::_ReadTouchpadSettingsMsg(BMessage* message) 565167f43a2SStephan Aßmus { 5663bf47305SAxel Dörfler message->FindBool("scroll_twofinger", &fTouchpadSettings.scroll_twofinger); 567fc548b41SAxel Dörfler message->FindBool("scroll_twofinger_horizontal", 568fc548b41SAxel Dörfler &fTouchpadSettings.scroll_twofinger_horizontal); 569167f43a2SStephan Aßmus message->FindFloat("scroll_rightrange", 5703bf47305SAxel Dörfler &fTouchpadSettings.scroll_rightrange); 571167f43a2SStephan Aßmus message->FindFloat("scroll_bottomrange", 5723bf47305SAxel Dörfler &fTouchpadSettings.scroll_bottomrange); 5733bf47305SAxel Dörfler 574167f43a2SStephan Aßmus message->FindInt16("scroll_xstepsize", 5753bf47305SAxel Dörfler (int16*)&fTouchpadSettings.scroll_xstepsize); 576167f43a2SStephan Aßmus message->FindInt16("scroll_ystepsize", 5773bf47305SAxel Dörfler (int16*)&fTouchpadSettings.scroll_ystepsize); 578167f43a2SStephan Aßmus message->FindInt8("scroll_acceleration", 5793bf47305SAxel Dörfler (int8*)&fTouchpadSettings.scroll_acceleration); 580167f43a2SStephan Aßmus message->FindInt8("tapgesture_sensibility", 5813bf47305SAxel Dörfler (int8*)&fTouchpadSettings.tapgesture_sensibility); 582167f43a2SStephan Aßmus 583167f43a2SStephan Aßmus return B_OK; 584167f43a2SStephan Aßmus } 585167f43a2SStephan Aßmus 586167f43a2SStephan Aßmus 587167f43a2SStephan Aßmus status_t 588167f43a2SStephan Aßmus MouseDevice::_UpdateTouchpadSettings() 589167f43a2SStephan Aßmus { 590167f43a2SStephan Aßmus if (fIsTouchpad) { 591167f43a2SStephan Aßmus ioctl(fDevice, MS_SET_TOUCHPAD_SETTINGS, &fTouchpadSettings); 592167f43a2SStephan Aßmus return B_OK; 593167f43a2SStephan Aßmus } 594167f43a2SStephan Aßmus return B_ERROR; 595167f43a2SStephan Aßmus } 596167f43a2SStephan Aßmus 597167f43a2SStephan Aßmus 59861604e48SAxel Dörfler BMessage* 59961604e48SAxel Dörfler MouseDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, 60061604e48SAxel Dörfler int32 deltaX, int32 deltaY) const 60161604e48SAxel Dörfler { 60261604e48SAxel Dörfler BMessage* message = new BMessage(what); 60361604e48SAxel Dörfler if (message == NULL) 60461604e48SAxel Dörfler return NULL; 60561604e48SAxel Dörfler 60661604e48SAxel Dörfler if (message->AddInt64("when", when) < B_OK 60761604e48SAxel Dörfler || message->AddInt32("buttons", buttons) < B_OK 60861604e48SAxel Dörfler || message->AddInt32("x", deltaX) < B_OK 60961604e48SAxel Dörfler || message->AddInt32("y", deltaY) < B_OK) { 61061604e48SAxel Dörfler delete message; 61161604e48SAxel Dörfler return NULL; 61261604e48SAxel Dörfler } 61361604e48SAxel Dörfler 61461604e48SAxel Dörfler return message; 61561604e48SAxel Dörfler } 61661604e48SAxel Dörfler 61761604e48SAxel Dörfler 61861604e48SAxel Dörfler void 61961604e48SAxel Dörfler MouseDevice::_ComputeAcceleration(const mouse_movement& movements, 6206e094221SStephan Aßmus int32& _deltaX, int32& _deltaY, float& historyDeltaX, 6216e094221SStephan Aßmus float& historyDeltaY) const 62261604e48SAxel Dörfler { 62342b505fbSAxel Dörfler // basic mouse speed 6246e094221SStephan Aßmus float deltaX = (float)movements.xdelta * fSettings.accel.speed / 65536.0 6256e094221SStephan Aßmus + historyDeltaX; 6266e094221SStephan Aßmus float deltaY = (float)movements.ydelta * fSettings.accel.speed / 65536.0 6276e094221SStephan Aßmus + historyDeltaY; 62842b505fbSAxel Dörfler 62942b505fbSAxel Dörfler // acceleration 63042b505fbSAxel Dörfler double acceleration = 1; 63142b505fbSAxel Dörfler if (fSettings.accel.accel_factor) { 632fafab827SAxel Dörfler acceleration = 1 + sqrt(deltaX * deltaX + deltaY * deltaY) 63374ef1621SAxel Dörfler * fSettings.accel.accel_factor / 524288.0; 63442b505fbSAxel Dörfler } 63542b505fbSAxel Dörfler 6366e094221SStephan Aßmus deltaX *= acceleration; 6376e094221SStephan Aßmus deltaY *= acceleration; 63842b505fbSAxel Dörfler 6396e094221SStephan Aßmus if (deltaX >= 0) 6406e094221SStephan Aßmus _deltaX = (int32)floorf(deltaX); 641fafab827SAxel Dörfler else 6426e094221SStephan Aßmus _deltaX = (int32)ceilf(deltaX); 6436e094221SStephan Aßmus 6446e094221SStephan Aßmus if (deltaY >= 0) 6456e094221SStephan Aßmus _deltaY = (int32)floorf(deltaY); 6466e094221SStephan Aßmus else 6476e094221SStephan Aßmus _deltaY = (int32)ceilf(deltaY); 6486e094221SStephan Aßmus 6496e094221SStephan Aßmus historyDeltaX = deltaX - _deltaX; 6506e094221SStephan Aßmus historyDeltaY = deltaY - _deltaY; 65161604e48SAxel Dörfler } 65261604e48SAxel Dörfler 65333efb919SStefano Ceccherini 65423b47e0bSJérôme Duval uint32 65561604e48SAxel Dörfler MouseDevice::_RemapButtons(uint32 buttons) const 65623b47e0bSJérôme Duval { 65761604e48SAxel Dörfler if (fDeviceRemapsButtons) 65823b47e0bSJérôme Duval return buttons; 65923b47e0bSJérôme Duval 66061604e48SAxel Dörfler uint32 newButtons = 0; 66123b47e0bSJérôme Duval for (int32 i = 0; buttons; i++) { 66223b47e0bSJérôme Duval if (buttons & 0x1) { 66321631085SStephan Aßmus #if defined(HAIKU_TARGET_PLATFORM_HAIKU) || defined(HAIKU_TARGET_PLATFORM_DANO) 66461604e48SAxel Dörfler newButtons |= fSettings.map.button[i]; 66523b47e0bSJérôme Duval #else 66623b47e0bSJérôme Duval if (i == 0) 66761604e48SAxel Dörfler newButtons |= fSettings.map.left; 66823b47e0bSJérôme Duval if (i == 1) 66961604e48SAxel Dörfler newButtons |= fSettings.map.right; 67023b47e0bSJérôme Duval if (i == 2) 67161604e48SAxel Dörfler newButtons |= fSettings.map.middle; 67223b47e0bSJérôme Duval #endif 67323b47e0bSJérôme Duval } 67423b47e0bSJérôme Duval buttons >>= 1; 67523b47e0bSJérôme Duval } 67623b47e0bSJérôme Duval 67761604e48SAxel Dörfler return newButtons; 67823b47e0bSJérôme Duval } 67923b47e0bSJérôme Duval 68023b47e0bSJérôme Duval 68161604e48SAxel Dörfler // #pragma mark - 68261604e48SAxel Dörfler 68361604e48SAxel Dörfler 68461604e48SAxel Dörfler MouseInputDevice::MouseInputDevice() 685b6a7b204SAxel Dörfler : 6865125eae2SStephan Aßmus fDevices(2, true), 6875125eae2SStephan Aßmus fDeviceListLock("MouseInputDevice list") 68861604e48SAxel Dörfler { 689e01a0431SStephan Aßmus MID_CALLED(); 69061604e48SAxel Dörfler 691c5555ad3SStephan Aßmus StartMonitoringDevice(kMouseDevicesDirectory); 692167f43a2SStephan Aßmus StartMonitoringDevice(kTouchpadDevicesDirectory); 6939dd2d40eSStephan Aßmus _RecursiveScan(kMouseDevicesDirectory); 694167f43a2SStephan Aßmus _RecursiveScan(kTouchpadDevicesDirectory); 69561604e48SAxel Dörfler } 69661604e48SAxel Dörfler 69761604e48SAxel Dörfler 69861604e48SAxel Dörfler MouseInputDevice::~MouseInputDevice() 69961604e48SAxel Dörfler { 700e01a0431SStephan Aßmus MID_CALLED(); 701e01a0431SStephan Aßmus 702167f43a2SStephan Aßmus StopMonitoringDevice(kTouchpadDevicesDirectory); 703b6a7b204SAxel Dörfler StopMonitoringDevice(kMouseDevicesDirectory); 704e01a0431SStephan Aßmus fDevices.MakeEmpty(); 70561604e48SAxel Dörfler } 70661604e48SAxel Dörfler 70761604e48SAxel Dörfler 70861604e48SAxel Dörfler status_t 70961604e48SAxel Dörfler MouseInputDevice::InitCheck() 71061604e48SAxel Dörfler { 711e01a0431SStephan Aßmus MID_CALLED(); 712e01a0431SStephan Aßmus 713d246d9beSStefano Ceccherini return BInputServerDevice::InitCheck(); 71461604e48SAxel Dörfler } 71561604e48SAxel Dörfler 71661604e48SAxel Dörfler 71761604e48SAxel Dörfler status_t 71861604e48SAxel Dörfler MouseInputDevice::Start(const char* name, void* cookie) 71961604e48SAxel Dörfler { 720e01a0431SStephan Aßmus MID_CALLED(); 721e01a0431SStephan Aßmus 72261604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 72361604e48SAxel Dörfler 72461604e48SAxel Dörfler return device->Start(); 72561604e48SAxel Dörfler } 72661604e48SAxel Dörfler 72761604e48SAxel Dörfler 72861604e48SAxel Dörfler status_t 72961604e48SAxel Dörfler MouseInputDevice::Stop(const char* name, void* cookie) 73061604e48SAxel Dörfler { 731e01a0431SStephan Aßmus TRACE("%s(%s)\n", __PRETTY_FUNCTION__, name); 73261604e48SAxel Dörfler 733e01a0431SStephan Aßmus MouseDevice* device = (MouseDevice*)cookie; 73461604e48SAxel Dörfler device->Stop(); 735e01a0431SStephan Aßmus 73661604e48SAxel Dörfler return B_OK; 73761604e48SAxel Dörfler } 73861604e48SAxel Dörfler 73961604e48SAxel Dörfler 74061604e48SAxel Dörfler status_t 74161604e48SAxel Dörfler MouseInputDevice::Control(const char* name, void* cookie, 74261604e48SAxel Dörfler uint32 command, BMessage* message) 74361604e48SAxel Dörfler { 744e01a0431SStephan Aßmus TRACE("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command); 745e01a0431SStephan Aßmus 74661604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 74761604e48SAxel Dörfler 74861604e48SAxel Dörfler if (command == B_NODE_MONITOR) 74961604e48SAxel Dörfler return _HandleMonitor(message); 75061604e48SAxel Dörfler 751167f43a2SStephan Aßmus if (command == MS_SET_TOUCHPAD_SETTINGS) 752167f43a2SStephan Aßmus return device->UpdateTouchpadSettings(message); 753167f43a2SStephan Aßmus 75461604e48SAxel Dörfler if (command >= B_MOUSE_TYPE_CHANGED 75561604e48SAxel Dörfler && command <= B_MOUSE_ACCELERATION_CHANGED) 75661604e48SAxel Dörfler return device->UpdateSettings(); 75761604e48SAxel Dörfler 75861604e48SAxel Dörfler return B_BAD_VALUE; 75961604e48SAxel Dörfler } 76061604e48SAxel Dörfler 76161604e48SAxel Dörfler 76261604e48SAxel Dörfler status_t 76361604e48SAxel Dörfler MouseInputDevice::_HandleMonitor(BMessage* message) 76461604e48SAxel Dörfler { 765e01a0431SStephan Aßmus MID_CALLED(); 76661604e48SAxel Dörfler 767b6a7b204SAxel Dörfler const char* path; 76861604e48SAxel Dörfler int32 opcode; 769b6a7b204SAxel Dörfler if (message->FindInt32("opcode", &opcode) != B_OK 770c5555ad3SStephan Aßmus || (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED) 771b6a7b204SAxel Dörfler || message->FindString("path", &path) != B_OK) 77261604e48SAxel Dörfler return B_BAD_VALUE; 77361604e48SAxel Dörfler 77461604e48SAxel Dörfler if (opcode == B_ENTRY_CREATED) 775b6a7b204SAxel Dörfler return _AddDevice(path); 77661604e48SAxel Dörfler 777c5555ad3SStephan Aßmus #if 0 778b6a7b204SAxel Dörfler return _RemoveDevice(path); 779c5555ad3SStephan Aßmus #else 780c5555ad3SStephan Aßmus // Don't handle B_ENTRY_REMOVED, let the control thread take care of it. 781c5555ad3SStephan Aßmus return B_OK; 782c5555ad3SStephan Aßmus #endif 78361604e48SAxel Dörfler } 78461604e48SAxel Dörfler 78561604e48SAxel Dörfler 78661604e48SAxel Dörfler void 78761604e48SAxel Dörfler MouseInputDevice::_RecursiveScan(const char* directory) 78861604e48SAxel Dörfler { 789e01a0431SStephan Aßmus MID_CALLED(); 79061604e48SAxel Dörfler 79161604e48SAxel Dörfler BEntry entry; 79261604e48SAxel Dörfler BDirectory dir(directory); 79361604e48SAxel Dörfler while (dir.GetNextEntry(&entry) == B_OK) { 79461604e48SAxel Dörfler BPath path; 79561604e48SAxel Dörfler entry.GetPath(&path); 79661604e48SAxel Dörfler 79761604e48SAxel Dörfler if (!strcmp(path.Leaf(), "serial")) { 79861604e48SAxel Dörfler // skip serial 79961604e48SAxel Dörfler continue; 80061604e48SAxel Dörfler } 80161604e48SAxel Dörfler 80261604e48SAxel Dörfler if (entry.IsDirectory()) 80361604e48SAxel Dörfler _RecursiveScan(path.Path()); 80461604e48SAxel Dörfler else 80561604e48SAxel Dörfler _AddDevice(path.Path()); 80661604e48SAxel Dörfler } 80761604e48SAxel Dörfler } 80861604e48SAxel Dörfler 809e01a0431SStephan Aßmus 810e01a0431SStephan Aßmus MouseDevice* 8115125eae2SStephan Aßmus MouseInputDevice::_FindDevice(const char* path) const 812e01a0431SStephan Aßmus { 813e01a0431SStephan Aßmus MID_CALLED(); 814e01a0431SStephan Aßmus 815e01a0431SStephan Aßmus for (int32 i = fDevices.CountItems() - 1; i >= 0; i--) { 816e01a0431SStephan Aßmus MouseDevice* device = fDevices.ItemAt(i); 817e01a0431SStephan Aßmus if (strcmp(device->Path(), path) == 0) 818e01a0431SStephan Aßmus return device; 819e01a0431SStephan Aßmus } 820e01a0431SStephan Aßmus 821e01a0431SStephan Aßmus return NULL; 822e01a0431SStephan Aßmus } 823e01a0431SStephan Aßmus 824e01a0431SStephan Aßmus 825e01a0431SStephan Aßmus status_t 826e01a0431SStephan Aßmus MouseInputDevice::_AddDevice(const char* path) 827e01a0431SStephan Aßmus { 828e01a0431SStephan Aßmus MID_CALLED(); 829e01a0431SStephan Aßmus 8305125eae2SStephan Aßmus BAutolock _(fDeviceListLock); 8315125eae2SStephan Aßmus 832e01a0431SStephan Aßmus _RemoveDevice(path); 833e01a0431SStephan Aßmus 834e01a0431SStephan Aßmus MouseDevice* device = new(std::nothrow) MouseDevice(*this, path); 835fdad31e6SMichael Lotz if (device == NULL) { 836e01a0431SStephan Aßmus TRACE("No memory\n"); 837e01a0431SStephan Aßmus return B_NO_MEMORY; 838e01a0431SStephan Aßmus } 839e01a0431SStephan Aßmus 840e01a0431SStephan Aßmus if (!fDevices.AddItem(device)) { 841e01a0431SStephan Aßmus TRACE("No memory in list\n"); 842e01a0431SStephan Aßmus delete device; 843e01a0431SStephan Aßmus return B_NO_MEMORY; 844e01a0431SStephan Aßmus } 845e01a0431SStephan Aßmus 846e01a0431SStephan Aßmus input_device_ref* devices[2]; 847e01a0431SStephan Aßmus devices[0] = device->DeviceRef(); 848e01a0431SStephan Aßmus devices[1] = NULL; 849e01a0431SStephan Aßmus 850e01a0431SStephan Aßmus TRACE("adding path: %s, name: %s\n", path, devices[0]->name); 851e01a0431SStephan Aßmus 852e01a0431SStephan Aßmus return RegisterDevices(devices); 853e01a0431SStephan Aßmus } 854e01a0431SStephan Aßmus 855e01a0431SStephan Aßmus 856e01a0431SStephan Aßmus status_t 857e01a0431SStephan Aßmus MouseInputDevice::_RemoveDevice(const char* path) 858e01a0431SStephan Aßmus { 859e01a0431SStephan Aßmus MID_CALLED(); 860e01a0431SStephan Aßmus 8615125eae2SStephan Aßmus BAutolock _(fDeviceListLock); 8625125eae2SStephan Aßmus 863e01a0431SStephan Aßmus MouseDevice* device = _FindDevice(path); 864e01a0431SStephan Aßmus if (device == NULL) { 865e01a0431SStephan Aßmus TRACE("%s not found\n", path); 866e01a0431SStephan Aßmus return B_ENTRY_NOT_FOUND; 867e01a0431SStephan Aßmus } 868e01a0431SStephan Aßmus 869e01a0431SStephan Aßmus input_device_ref* devices[2]; 870e01a0431SStephan Aßmus devices[0] = device->DeviceRef(); 871e01a0431SStephan Aßmus devices[1] = NULL; 872e01a0431SStephan Aßmus 873e01a0431SStephan Aßmus TRACE("removing path: %s, name: %s\n", path, devices[0]->name); 874e01a0431SStephan Aßmus 875e01a0431SStephan Aßmus UnregisterDevices(devices); 876e01a0431SStephan Aßmus 877e01a0431SStephan Aßmus fDevices.RemoveItem(device); 878e01a0431SStephan Aßmus 879e01a0431SStephan Aßmus return B_OK; 880e01a0431SStephan Aßmus } 881