123b47e0bSJérôme Duval /* 2*fdad31e6SMichael 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 18661604e48SAxel Dörfler fSettings.map.button[0] = B_PRIMARY_MOUSE_BUTTON; 18761604e48SAxel Dörfler fSettings.map.button[1] = B_SECONDARY_MOUSE_BUTTON; 18861604e48SAxel Dörfler fSettings.map.button[2] = B_TERTIARY_MOUSE_BUTTON; 1893aa69c78SStefano Ceccherini #endif 19061604e48SAxel Dörfler }; 19161d7deeeSJérôme Duval 19261d7deeeSJérôme Duval 19361604e48SAxel Dörfler MouseDevice::~MouseDevice() 19461d7deeeSJérôme Duval { 195e01a0431SStephan Aßmus MD_CALLED(); 196e01a0431SStephan Aßmus TRACE("delete\n"); 197e01a0431SStephan Aßmus 19861604e48SAxel Dörfler if (fActive) 19961604e48SAxel Dörfler Stop(); 20061d7deeeSJérôme Duval 20161604e48SAxel Dörfler free(fDeviceRef.name); 202167f43a2SStephan Aßmus delete fTouchpadSettingsMessage; 20361d7deeeSJérôme Duval } 20461d7deeeSJérôme Duval 20561d7deeeSJérôme Duval 20661d7deeeSJérôme Duval status_t 20761604e48SAxel Dörfler MouseDevice::Start() 20853d77642SJérôme Duval { 209e01a0431SStephan Aßmus MD_CALLED(); 210e01a0431SStephan Aßmus 21161604e48SAxel Dörfler fDevice = open(fPath.String(), O_RDWR); 2125125eae2SStephan Aßmus // let the control thread handle any error on opening the device 21333efb919SStefano Ceccherini 21433efb919SStefano Ceccherini char threadName[B_OS_NAME_LENGTH]; 21561604e48SAxel Dörfler snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", fDeviceRef.name); 21633efb919SStefano Ceccherini 2175125eae2SStephan Aßmus fThread = spawn_thread(_ControlThreadEntry, threadName, 21861604e48SAxel Dörfler kMouseThreadPriority, (void*)this); 2194c0af4a8SStefano Ceccherini 22033efb919SStefano Ceccherini status_t status; 221*fdad31e6SMichael Lotz if (fThread < 0) 22261604e48SAxel Dörfler status = fThread; 22361604e48SAxel Dörfler else { 22461604e48SAxel Dörfler fActive = true; 22561604e48SAxel Dörfler status = resume_thread(fThread); 22661604e48SAxel Dörfler } 22733efb919SStefano Ceccherini 22861604e48SAxel Dörfler if (status < B_OK) { 22961604e48SAxel Dörfler LOG_ERR("%s: can't spawn/resume watching thread: %s\n", 23061604e48SAxel Dörfler fDeviceRef.name, strerror(status)); 231*fdad31e6SMichael Lotz if (fDevice >= 0) 232167f43a2SStephan Aßmus close(fDevice); 23314a12accSFredrik Holmqvist 23461604e48SAxel Dörfler return status; 23561604e48SAxel Dörfler } 23661604e48SAxel Dörfler 2379195fe6eSStephan Aßmus return fDevice >= 0 ? B_OK : B_ERROR; 23861d7deeeSJérôme Duval } 23961d7deeeSJérôme Duval 24061d7deeeSJérôme Duval 241c2fbfb71SJérôme Duval void 24261604e48SAxel Dörfler MouseDevice::Stop() 24361604e48SAxel Dörfler { 244e01a0431SStephan Aßmus MD_CALLED(); 2451ccc2f2dSJérôme Duval 24661604e48SAxel Dörfler fActive = false; 24761604e48SAxel Dörfler // this will stop the thread as soon as it reads the next packet 24861604e48SAxel Dörfler 249e01a0431SStephan Aßmus close(fDevice); 250e01a0431SStephan Aßmus fDevice = -1; 251e01a0431SStephan Aßmus 252*fdad31e6SMichael Lotz if (fThread >= 0) { 25361604e48SAxel Dörfler // unblock the thread, which might wait on a semaphore. 25461604e48SAxel Dörfler suspend_thread(fThread); 25561604e48SAxel Dörfler resume_thread(fThread); 25661604e48SAxel Dörfler 25761604e48SAxel Dörfler status_t dummy; 25861604e48SAxel Dörfler wait_for_thread(fThread, &dummy); 25961604e48SAxel Dörfler } 26061604e48SAxel Dörfler } 26161604e48SAxel Dörfler 26261604e48SAxel Dörfler 26342b505fbSAxel Dörfler status_t 26442b505fbSAxel Dörfler MouseDevice::UpdateSettings() 26542b505fbSAxel Dörfler { 266e01a0431SStephan Aßmus MD_CALLED(); 26742b505fbSAxel Dörfler 2685125eae2SStephan Aßmus if (fThread < 0) 2695125eae2SStephan Aßmus return B_ERROR; 27042b505fbSAxel Dörfler 271167f43a2SStephan Aßmus // trigger updating the settings in the control thread 2725125eae2SStephan Aßmus fUpdateSettings = true; 273167f43a2SStephan Aßmus 274167f43a2SStephan Aßmus return B_OK; 275167f43a2SStephan Aßmus } 276167f43a2SStephan Aßmus 277167f43a2SStephan Aßmus 278167f43a2SStephan Aßmus status_t 279167f43a2SStephan Aßmus MouseDevice::UpdateTouchpadSettings(const BMessage* message) 280167f43a2SStephan Aßmus { 281167f43a2SStephan Aßmus if (!fIsTouchpad) 282167f43a2SStephan Aßmus return B_BAD_TYPE; 283167f43a2SStephan Aßmus if (fThread < 0) 284167f43a2SStephan Aßmus return B_ERROR; 285167f43a2SStephan Aßmus 286167f43a2SStephan Aßmus BAutolock _(fTouchpadSettingsLock); 287167f43a2SStephan Aßmus 288167f43a2SStephan Aßmus // trigger updating the settings in the control thread 289167f43a2SStephan Aßmus fUpdateSettings = true; 290167f43a2SStephan Aßmus 291167f43a2SStephan Aßmus delete fTouchpadSettingsMessage; 292167f43a2SStephan Aßmus fTouchpadSettingsMessage = new BMessage(*message); 293*fdad31e6SMichael Lotz if (fTouchpadSettingsMessage == NULL) 294*fdad31e6SMichael Lotz return B_NO_MEMORY; 29542b505fbSAxel Dörfler 29642b505fbSAxel Dörfler return B_OK; 2975125eae2SStephan Aßmus } 29842b505fbSAxel Dörfler 2995125eae2SStephan Aßmus 3005125eae2SStephan Aßmus char* 3015125eae2SStephan Aßmus MouseDevice::_BuildShortName() const 3025125eae2SStephan Aßmus { 3035125eae2SStephan Aßmus BString string(fPath); 3045125eae2SStephan Aßmus BString name; 3055125eae2SStephan Aßmus 3065125eae2SStephan Aßmus int32 slash = string.FindLast("/"); 3075125eae2SStephan Aßmus string.CopyInto(name, slash + 1, string.Length() - slash); 3085125eae2SStephan Aßmus int32 index = atoi(name.String()) + 1; 3095125eae2SStephan Aßmus 3105125eae2SStephan Aßmus int32 previousSlash = string.FindLast("/", slash); 3115125eae2SStephan Aßmus string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1); 3125125eae2SStephan Aßmus 3135125eae2SStephan Aßmus if (name == "ps2") 3145125eae2SStephan Aßmus name = "PS/2"; 315155b8260SPhilippe Houdoin 316155b8260SPhilippe Houdoin if (name.Length() < 4) 317155b8260SPhilippe Houdoin name.ToUpper(); 3185125eae2SStephan Aßmus else 3195125eae2SStephan Aßmus name.Capitalize(); 3205125eae2SStephan Aßmus 321167f43a2SStephan Aßmus if (string.FindFirst("touchpad") >= 0) { 322167f43a2SStephan Aßmus name << " Touchpad "; 323167f43a2SStephan Aßmus } else { 324cc442411SStephan Aßmus if (string.FindFirst("intelli") >= 0) 325cc442411SStephan Aßmus name.Prepend("Extended "); 326cc442411SStephan Aßmus 327167f43a2SStephan Aßmus name << " Mouse "; 328167f43a2SStephan Aßmus } 329167f43a2SStephan Aßmus name << index; 3305125eae2SStephan Aßmus 3315125eae2SStephan Aßmus return strdup(name.String()); 3325125eae2SStephan Aßmus } 3335125eae2SStephan Aßmus 3345125eae2SStephan Aßmus 3355125eae2SStephan Aßmus // #pragma mark - control thread 3365125eae2SStephan Aßmus 3375125eae2SStephan Aßmus 3385125eae2SStephan Aßmus status_t 3395125eae2SStephan Aßmus MouseDevice::_ControlThreadEntry(void* arg) 3405125eae2SStephan Aßmus { 3415125eae2SStephan Aßmus MouseDevice* device = (MouseDevice*)arg; 3425125eae2SStephan Aßmus device->_ControlThread(); 3435125eae2SStephan Aßmus return B_OK; 34442b505fbSAxel Dörfler } 34542b505fbSAxel Dörfler 34642b505fbSAxel Dörfler 34761604e48SAxel Dörfler void 3485125eae2SStephan Aßmus MouseDevice::_ControlThread() 34961604e48SAxel Dörfler { 350167f43a2SStephan Aßmus MD_CALLED(); 351167f43a2SStephan Aßmus 3525125eae2SStephan Aßmus if (fDevice < 0) { 3535125eae2SStephan Aßmus _ControlThreadCleanup(); 3545125eae2SStephan Aßmus // TOAST! 3555125eae2SStephan Aßmus return; 3565125eae2SStephan Aßmus } 3575125eae2SStephan Aßmus 358167f43a2SStephan Aßmus // touchpad settings 359167f43a2SStephan Aßmus if (ioctl(fDevice, MS_IS_TOUCHPAD, NULL) == B_OK) { 360167f43a2SStephan Aßmus TRACE("is touchpad %s\n", fPath.String()); 361167f43a2SStephan Aßmus fIsTouchpad = true; 362167f43a2SStephan Aßmus 363167f43a2SStephan Aßmus fTouchpadSettings = kDefaultTouchpadSettings; 364167f43a2SStephan Aßmus 365167f43a2SStephan Aßmus BPath path; 366167f43a2SStephan Aßmus status_t status = _GetTouchpadSettingsPath(path); 367167f43a2SStephan Aßmus BFile settingsFile(path.Path(), B_READ_ONLY); 368167f43a2SStephan Aßmus if (status == B_OK && settingsFile.InitCheck() == B_OK) { 369167f43a2SStephan Aßmus if (settingsFile.Read(&fTouchpadSettings, sizeof(touchpad_settings)) 370167f43a2SStephan Aßmus != sizeof(touchpad_settings)) { 371167f43a2SStephan Aßmus TRACE("failed to load settings\n"); 372167f43a2SStephan Aßmus } 373167f43a2SStephan Aßmus } 374167f43a2SStephan Aßmus _UpdateTouchpadSettings(); 375167f43a2SStephan Aßmus } 376167f43a2SStephan Aßmus 3775125eae2SStephan Aßmus _UpdateSettings(); 3785125eae2SStephan Aßmus 37961604e48SAxel Dörfler uint32 lastButtons = 0; 3806e094221SStephan Aßmus float historyDeltaX = 0.0; 3816e094221SStephan Aßmus float historyDeltaY = 0.0; 38261604e48SAxel Dörfler 3837d1d7033SStephan Aßmus static const bigtime_t kTransferDelay = 1000000 / 125; 3847d1d7033SStephan Aßmus // 125 transfers per second should be more than enough 3855994d47aSStephan Aßmus #define USE_REGULAR_INTERVAL 1 3867d1d7033SStephan Aßmus #if USE_REGULAR_INTERVAL 3877d1d7033SStephan Aßmus bigtime_t nextTransferTime = system_time() + kTransferDelay; 3887d1d7033SStephan Aßmus #endif 3897d1d7033SStephan Aßmus 39061604e48SAxel Dörfler while (fActive) { 39161604e48SAxel Dörfler mouse_movement movements; 3927d1d7033SStephan Aßmus 3937d1d7033SStephan Aßmus #if USE_REGULAR_INTERVAL 3947d1d7033SStephan Aßmus snooze_until(nextTransferTime, B_SYSTEM_TIMEBASE); 3957d1d7033SStephan Aßmus nextTransferTime += kTransferDelay; 3967d1d7033SStephan Aßmus #endif 3977d1d7033SStephan Aßmus 398308e87fcSRene Gollent if (ioctl(fDevice, MS_READ, &movements, sizeof(movements)) != B_OK) { 399308e87fcSRene Gollent LOG_ERR("Mouse device exiting, %s\n", strerror(errno)); 4005125eae2SStephan Aßmus _ControlThreadCleanup(); 401c5555ad3SStephan Aßmus // TOAST! 40261604e48SAxel Dörfler return; 403c5555ad3SStephan Aßmus } 40461604e48SAxel Dörfler 4055125eae2SStephan Aßmus // take care of updating the settings first, if necessary 4065125eae2SStephan Aßmus if (fUpdateSettings) { 4075125eae2SStephan Aßmus fUpdateSettings = false; 408167f43a2SStephan Aßmus if (fIsTouchpad) { 409167f43a2SStephan Aßmus BAutolock _(fTouchpadSettingsLock); 4103bf47305SAxel Dörfler if (fTouchpadSettingsMessage != NULL) { 411167f43a2SStephan Aßmus _ReadTouchpadSettingsMsg(fTouchpadSettingsMessage); 412167f43a2SStephan Aßmus _UpdateTouchpadSettings(); 413167f43a2SStephan Aßmus delete fTouchpadSettingsMessage; 414167f43a2SStephan Aßmus fTouchpadSettingsMessage = NULL; 415167f43a2SStephan Aßmus } else 416167f43a2SStephan Aßmus _UpdateSettings(); 417167f43a2SStephan Aßmus } else 418167f43a2SStephan Aßmus _UpdateSettings(); 4195125eae2SStephan Aßmus } 4205125eae2SStephan Aßmus 42161604e48SAxel Dörfler uint32 buttons = lastButtons ^ movements.buttons; 42261604e48SAxel Dörfler 42361604e48SAxel Dörfler uint32 remappedButtons = _RemapButtons(movements.buttons); 42461604e48SAxel Dörfler int32 deltaX, deltaY; 4256e094221SStephan Aßmus _ComputeAcceleration(movements, deltaX, deltaY, historyDeltaX, 4266e094221SStephan Aßmus historyDeltaY); 42761604e48SAxel Dörfler 4286e094221SStephan Aßmus LOG_EVENT("%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld, " 4296e094221SStephan Aßmus "wheel_x:%ld, wheel_y:%ld\n", 4306e094221SStephan Aßmus fDeviceRef.name, movements.buttons, 4316e094221SStephan Aßmus movements.xdelta, movements.ydelta, movements.clicks, 4326e094221SStephan Aßmus movements.wheel_xdelta, movements.wheel_ydelta); 4336e094221SStephan Aßmus LOG_EVENT("%s: x: %ld, y: %ld (%.4f, %.4f)\n", fDeviceRef.name, 4346e094221SStephan Aßmus deltaX, deltaY, historyDeltaX, historyDeltaY); 43561604e48SAxel Dörfler 43661604e48SAxel Dörfler // Send single messages for each event 43761604e48SAxel Dörfler 43861604e48SAxel Dörfler if (buttons != 0) { 43961604e48SAxel Dörfler bool pressedButton = (buttons & movements.buttons) > 0; 44061604e48SAxel Dörfler BMessage* message = _BuildMouseMessage( 44161604e48SAxel Dörfler pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP, 44261604e48SAxel Dörfler movements.timestamp, remappedButtons, deltaX, deltaY); 44361604e48SAxel Dörfler if (message != NULL) { 44461604e48SAxel Dörfler if (pressedButton) { 44561604e48SAxel Dörfler message->AddInt32("clicks", movements.clicks); 446e01a0431SStephan Aßmus LOG_EVENT("B_MOUSE_DOWN\n"); 44761604e48SAxel Dörfler } else 448e01a0431SStephan Aßmus LOG_EVENT("B_MOUSE_UP\n"); 44961604e48SAxel Dörfler 45061604e48SAxel Dörfler fTarget.EnqueueMessage(message); 45161604e48SAxel Dörfler lastButtons = movements.buttons; 45261604e48SAxel Dörfler } 45361604e48SAxel Dörfler } 45461604e48SAxel Dörfler 45545f11ce8SStephan Aßmus if (movements.xdelta != 0 || movements.ydelta != 0) { 45645f11ce8SStephan Aßmus BMessage* message = _BuildMouseMessage(B_MOUSE_MOVED, 45745f11ce8SStephan Aßmus movements.timestamp, remappedButtons, deltaX, deltaY); 45845f11ce8SStephan Aßmus if (message != NULL) 45945f11ce8SStephan Aßmus fTarget.EnqueueMessage(message); 46045f11ce8SStephan Aßmus } 46145f11ce8SStephan Aßmus 462*fdad31e6SMichael Lotz if (movements.wheel_ydelta != 0 || movements.wheel_xdelta != 0) { 463c5555ad3SStephan Aßmus BMessage* message = new BMessage(B_MOUSE_WHEEL_CHANGED); 46461604e48SAxel Dörfler if (message == NULL) 46561604e48SAxel Dörfler continue; 46661604e48SAxel Dörfler 46761604e48SAxel Dörfler if (message->AddInt64("when", movements.timestamp) == B_OK 4683bf47305SAxel Dörfler && message->AddFloat("be:wheel_delta_x", 4693bf47305SAxel Dörfler movements.wheel_xdelta) == B_OK 4703bf47305SAxel Dörfler && message->AddFloat("be:wheel_delta_y", 4713bf47305SAxel Dörfler movements.wheel_ydelta) == B_OK) 47261604e48SAxel Dörfler fTarget.EnqueueMessage(message); 47361604e48SAxel Dörfler else 47461604e48SAxel Dörfler delete message; 47561604e48SAxel Dörfler } 4767d1d7033SStephan Aßmus 4777d1d7033SStephan Aßmus #if !USE_REGULAR_INTERVAL 4787d1d7033SStephan Aßmus snooze(kTransferDelay); 4797d1d7033SStephan Aßmus #endif 48061604e48SAxel Dörfler } 48161604e48SAxel Dörfler } 48261604e48SAxel Dörfler 48361604e48SAxel Dörfler 4845125eae2SStephan Aßmus void 4855125eae2SStephan Aßmus MouseDevice::_ControlThreadCleanup() 48661604e48SAxel Dörfler { 4875125eae2SStephan Aßmus // NOTE: Only executed when the control thread detected an error 4885125eae2SStephan Aßmus // and from within the control thread! 4895125eae2SStephan Aßmus 4905125eae2SStephan Aßmus if (fActive) { 4915125eae2SStephan Aßmus fThread = -1; 4925125eae2SStephan Aßmus fTarget._RemoveDevice(fPath.String()); 4935125eae2SStephan Aßmus } else { 4945125eae2SStephan Aßmus // In case active is already false, another thread 4955125eae2SStephan Aßmus // waits for this thread to quit, and may already hold 496*fdad31e6SMichael Lotz // locks that _RemoveDevice() wants to acquire. In other 4975125eae2SStephan Aßmus // words, the device is already being removed, so we simply 4985125eae2SStephan Aßmus // quit here. 4995125eae2SStephan Aßmus } 5005125eae2SStephan Aßmus } 5015125eae2SStephan Aßmus 5025125eae2SStephan Aßmus 5035125eae2SStephan Aßmus void 5045125eae2SStephan Aßmus MouseDevice::_UpdateSettings() 5055125eae2SStephan Aßmus { 5065125eae2SStephan Aßmus MD_CALLED(); 5075125eae2SStephan Aßmus 5085125eae2SStephan Aßmus // retrieve current values 5095125eae2SStephan Aßmus 5105125eae2SStephan Aßmus if (get_mouse_map(&fSettings.map) != B_OK) 5115125eae2SStephan Aßmus LOG_ERR("error when get_mouse_map\n"); 5125125eae2SStephan Aßmus else { 5135125eae2SStephan Aßmus fDeviceRemapsButtons 5145125eae2SStephan Aßmus = ioctl(fDevice, MS_SET_MAP, &fSettings.map) == B_OK; 5155125eae2SStephan Aßmus } 5165125eae2SStephan Aßmus 5175125eae2SStephan Aßmus if (get_click_speed(&fSettings.click_speed) != B_OK) 5185125eae2SStephan Aßmus LOG_ERR("error when get_click_speed\n"); 5195125eae2SStephan Aßmus else 5205125eae2SStephan Aßmus ioctl(fDevice, MS_SET_CLICKSPEED, &fSettings.click_speed); 5215125eae2SStephan Aßmus 5225125eae2SStephan Aßmus if (get_mouse_speed(&fSettings.accel.speed) != B_OK) 5235125eae2SStephan Aßmus LOG_ERR("error when get_mouse_speed\n"); 5245125eae2SStephan Aßmus else { 5255125eae2SStephan Aßmus if (get_mouse_acceleration(&fSettings.accel.accel_factor) != B_OK) 5265125eae2SStephan Aßmus LOG_ERR("error when get_mouse_acceleration\n"); 5275125eae2SStephan Aßmus else { 5285125eae2SStephan Aßmus mouse_accel accel; 5295125eae2SStephan Aßmus ioctl(fDevice, MS_GET_ACCEL, &accel); 5305125eae2SStephan Aßmus accel.speed = fSettings.accel.speed; 5315125eae2SStephan Aßmus accel.accel_factor = fSettings.accel.accel_factor; 5325125eae2SStephan Aßmus ioctl(fDevice, MS_SET_ACCEL, &fSettings.accel); 5335125eae2SStephan Aßmus } 5345125eae2SStephan Aßmus } 5355125eae2SStephan Aßmus 5365125eae2SStephan Aßmus if (get_mouse_type(&fSettings.type) != B_OK) 5375125eae2SStephan Aßmus LOG_ERR("error when get_mouse_type\n"); 5385125eae2SStephan Aßmus else 5395125eae2SStephan Aßmus ioctl(fDevice, MS_SET_TYPE, &fSettings.type); 54061604e48SAxel Dörfler } 54161604e48SAxel Dörfler 54261604e48SAxel Dörfler 543167f43a2SStephan Aßmus status_t 544167f43a2SStephan Aßmus MouseDevice::_GetTouchpadSettingsPath(BPath& path) 545167f43a2SStephan Aßmus { 546167f43a2SStephan Aßmus status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); 547167f43a2SStephan Aßmus if (status < B_OK) 548167f43a2SStephan Aßmus return status; 549167f43a2SStephan Aßmus return path.Append(TOUCHPAD_SETTINGS_FILE); 550167f43a2SStephan Aßmus } 551167f43a2SStephan Aßmus 552167f43a2SStephan Aßmus 553167f43a2SStephan Aßmus status_t 554167f43a2SStephan Aßmus MouseDevice::_ReadTouchpadSettingsMsg(BMessage* message) 555167f43a2SStephan Aßmus { 5563bf47305SAxel Dörfler message->FindBool("scroll_twofinger", &fTouchpadSettings.scroll_twofinger); 557fc548b41SAxel Dörfler message->FindBool("scroll_twofinger_horizontal", 558fc548b41SAxel Dörfler &fTouchpadSettings.scroll_twofinger_horizontal); 559167f43a2SStephan Aßmus message->FindFloat("scroll_rightrange", 5603bf47305SAxel Dörfler &fTouchpadSettings.scroll_rightrange); 561167f43a2SStephan Aßmus message->FindFloat("scroll_bottomrange", 5623bf47305SAxel Dörfler &fTouchpadSettings.scroll_bottomrange); 5633bf47305SAxel Dörfler 564167f43a2SStephan Aßmus message->FindInt16("scroll_xstepsize", 5653bf47305SAxel Dörfler (int16*)&fTouchpadSettings.scroll_xstepsize); 566167f43a2SStephan Aßmus message->FindInt16("scroll_ystepsize", 5673bf47305SAxel Dörfler (int16*)&fTouchpadSettings.scroll_ystepsize); 568167f43a2SStephan Aßmus message->FindInt8("scroll_acceleration", 5693bf47305SAxel Dörfler (int8*)&fTouchpadSettings.scroll_acceleration); 570167f43a2SStephan Aßmus message->FindInt8("tapgesture_sensibility", 5713bf47305SAxel Dörfler (int8*)&fTouchpadSettings.tapgesture_sensibility); 572167f43a2SStephan Aßmus 573167f43a2SStephan Aßmus return B_OK; 574167f43a2SStephan Aßmus } 575167f43a2SStephan Aßmus 576167f43a2SStephan Aßmus 577167f43a2SStephan Aßmus status_t 578167f43a2SStephan Aßmus MouseDevice::_UpdateTouchpadSettings() 579167f43a2SStephan Aßmus { 580167f43a2SStephan Aßmus if (fIsTouchpad) { 581167f43a2SStephan Aßmus ioctl(fDevice, MS_SET_TOUCHPAD_SETTINGS, &fTouchpadSettings); 582167f43a2SStephan Aßmus return B_OK; 583167f43a2SStephan Aßmus } 584167f43a2SStephan Aßmus return B_ERROR; 585167f43a2SStephan Aßmus } 586167f43a2SStephan Aßmus 587167f43a2SStephan Aßmus 58861604e48SAxel Dörfler BMessage* 58961604e48SAxel Dörfler MouseDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, 59061604e48SAxel Dörfler int32 deltaX, int32 deltaY) const 59161604e48SAxel Dörfler { 59261604e48SAxel Dörfler BMessage* message = new BMessage(what); 59361604e48SAxel Dörfler if (message == NULL) 59461604e48SAxel Dörfler return NULL; 59561604e48SAxel Dörfler 59661604e48SAxel Dörfler if (message->AddInt64("when", when) < B_OK 59761604e48SAxel Dörfler || message->AddInt32("buttons", buttons) < B_OK 59861604e48SAxel Dörfler || message->AddInt32("x", deltaX) < B_OK 59961604e48SAxel Dörfler || message->AddInt32("y", deltaY) < B_OK) { 60061604e48SAxel Dörfler delete message; 60161604e48SAxel Dörfler return NULL; 60261604e48SAxel Dörfler } 60361604e48SAxel Dörfler 60461604e48SAxel Dörfler return message; 60561604e48SAxel Dörfler } 60661604e48SAxel Dörfler 60761604e48SAxel Dörfler 60861604e48SAxel Dörfler void 60961604e48SAxel Dörfler MouseDevice::_ComputeAcceleration(const mouse_movement& movements, 6106e094221SStephan Aßmus int32& _deltaX, int32& _deltaY, float& historyDeltaX, 6116e094221SStephan Aßmus float& historyDeltaY) const 61261604e48SAxel Dörfler { 61342b505fbSAxel Dörfler // basic mouse speed 6146e094221SStephan Aßmus float deltaX = (float)movements.xdelta * fSettings.accel.speed / 65536.0 6156e094221SStephan Aßmus + historyDeltaX; 6166e094221SStephan Aßmus float deltaY = (float)movements.ydelta * fSettings.accel.speed / 65536.0 6176e094221SStephan Aßmus + historyDeltaY; 61842b505fbSAxel Dörfler 61942b505fbSAxel Dörfler // acceleration 62042b505fbSAxel Dörfler double acceleration = 1; 62142b505fbSAxel Dörfler if (fSettings.accel.accel_factor) { 622fafab827SAxel Dörfler acceleration = 1 + sqrt(deltaX * deltaX + deltaY * deltaY) 62374ef1621SAxel Dörfler * fSettings.accel.accel_factor / 524288.0; 62442b505fbSAxel Dörfler } 62542b505fbSAxel Dörfler 6266e094221SStephan Aßmus deltaX *= acceleration; 6276e094221SStephan Aßmus deltaY *= acceleration; 62842b505fbSAxel Dörfler 6296e094221SStephan Aßmus if (deltaX >= 0) 6306e094221SStephan Aßmus _deltaX = (int32)floorf(deltaX); 631fafab827SAxel Dörfler else 6326e094221SStephan Aßmus _deltaX = (int32)ceilf(deltaX); 6336e094221SStephan Aßmus 6346e094221SStephan Aßmus if (deltaY >= 0) 6356e094221SStephan Aßmus _deltaY = (int32)floorf(deltaY); 6366e094221SStephan Aßmus else 6376e094221SStephan Aßmus _deltaY = (int32)ceilf(deltaY); 6386e094221SStephan Aßmus 6396e094221SStephan Aßmus historyDeltaX = deltaX - _deltaX; 6406e094221SStephan Aßmus historyDeltaY = deltaY - _deltaY; 64161604e48SAxel Dörfler } 64261604e48SAxel Dörfler 64333efb919SStefano Ceccherini 64423b47e0bSJérôme Duval uint32 64561604e48SAxel Dörfler MouseDevice::_RemapButtons(uint32 buttons) const 64623b47e0bSJérôme Duval { 64761604e48SAxel Dörfler if (fDeviceRemapsButtons) 64823b47e0bSJérôme Duval return buttons; 64923b47e0bSJérôme Duval 65061604e48SAxel Dörfler uint32 newButtons = 0; 65123b47e0bSJérôme Duval for (int32 i = 0; buttons; i++) { 65223b47e0bSJérôme Duval if (buttons & 0x1) { 65321631085SStephan Aßmus #if defined(HAIKU_TARGET_PLATFORM_HAIKU) || defined(HAIKU_TARGET_PLATFORM_DANO) 65461604e48SAxel Dörfler newButtons |= fSettings.map.button[i]; 65523b47e0bSJérôme Duval #else 65623b47e0bSJérôme Duval if (i == 0) 65761604e48SAxel Dörfler newButtons |= fSettings.map.left; 65823b47e0bSJérôme Duval if (i == 1) 65961604e48SAxel Dörfler newButtons |= fSettings.map.right; 66023b47e0bSJérôme Duval if (i == 2) 66161604e48SAxel Dörfler newButtons |= fSettings.map.middle; 66223b47e0bSJérôme Duval #endif 66323b47e0bSJérôme Duval } 66423b47e0bSJérôme Duval buttons >>= 1; 66523b47e0bSJérôme Duval } 66623b47e0bSJérôme Duval 66761604e48SAxel Dörfler return newButtons; 66823b47e0bSJérôme Duval } 66923b47e0bSJérôme Duval 67023b47e0bSJérôme Duval 67161604e48SAxel Dörfler // #pragma mark - 67261604e48SAxel Dörfler 67361604e48SAxel Dörfler 67461604e48SAxel Dörfler MouseInputDevice::MouseInputDevice() 675b6a7b204SAxel Dörfler : 6765125eae2SStephan Aßmus fDevices(2, true), 6775125eae2SStephan Aßmus fDeviceListLock("MouseInputDevice list") 67861604e48SAxel Dörfler { 679e01a0431SStephan Aßmus MID_CALLED(); 68061604e48SAxel Dörfler 681c5555ad3SStephan Aßmus StartMonitoringDevice(kMouseDevicesDirectory); 682167f43a2SStephan Aßmus StartMonitoringDevice(kTouchpadDevicesDirectory); 6839dd2d40eSStephan Aßmus _RecursiveScan(kMouseDevicesDirectory); 684167f43a2SStephan Aßmus _RecursiveScan(kTouchpadDevicesDirectory); 68561604e48SAxel Dörfler } 68661604e48SAxel Dörfler 68761604e48SAxel Dörfler 68861604e48SAxel Dörfler MouseInputDevice::~MouseInputDevice() 68961604e48SAxel Dörfler { 690e01a0431SStephan Aßmus MID_CALLED(); 691e01a0431SStephan Aßmus 692167f43a2SStephan Aßmus StopMonitoringDevice(kTouchpadDevicesDirectory); 693b6a7b204SAxel Dörfler StopMonitoringDevice(kMouseDevicesDirectory); 694e01a0431SStephan Aßmus fDevices.MakeEmpty(); 69561604e48SAxel Dörfler } 69661604e48SAxel Dörfler 69761604e48SAxel Dörfler 69861604e48SAxel Dörfler status_t 69961604e48SAxel Dörfler MouseInputDevice::InitCheck() 70061604e48SAxel Dörfler { 701e01a0431SStephan Aßmus MID_CALLED(); 702e01a0431SStephan Aßmus 703d246d9beSStefano Ceccherini return BInputServerDevice::InitCheck(); 70461604e48SAxel Dörfler } 70561604e48SAxel Dörfler 70661604e48SAxel Dörfler 70761604e48SAxel Dörfler status_t 70861604e48SAxel Dörfler MouseInputDevice::Start(const char* name, void* cookie) 70961604e48SAxel Dörfler { 710e01a0431SStephan Aßmus MID_CALLED(); 711e01a0431SStephan Aßmus 71261604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 71361604e48SAxel Dörfler 71461604e48SAxel Dörfler return device->Start(); 71561604e48SAxel Dörfler } 71661604e48SAxel Dörfler 71761604e48SAxel Dörfler 71861604e48SAxel Dörfler status_t 71961604e48SAxel Dörfler MouseInputDevice::Stop(const char* name, void* cookie) 72061604e48SAxel Dörfler { 721e01a0431SStephan Aßmus TRACE("%s(%s)\n", __PRETTY_FUNCTION__, name); 72261604e48SAxel Dörfler 723e01a0431SStephan Aßmus MouseDevice* device = (MouseDevice*)cookie; 72461604e48SAxel Dörfler device->Stop(); 725e01a0431SStephan Aßmus 72661604e48SAxel Dörfler return B_OK; 72761604e48SAxel Dörfler } 72861604e48SAxel Dörfler 72961604e48SAxel Dörfler 73061604e48SAxel Dörfler status_t 73161604e48SAxel Dörfler MouseInputDevice::Control(const char* name, void* cookie, 73261604e48SAxel Dörfler uint32 command, BMessage* message) 73361604e48SAxel Dörfler { 734e01a0431SStephan Aßmus TRACE("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command); 735e01a0431SStephan Aßmus 73661604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 73761604e48SAxel Dörfler 73861604e48SAxel Dörfler if (command == B_NODE_MONITOR) 73961604e48SAxel Dörfler return _HandleMonitor(message); 74061604e48SAxel Dörfler 741167f43a2SStephan Aßmus if (command == MS_SET_TOUCHPAD_SETTINGS) 742167f43a2SStephan Aßmus return device->UpdateTouchpadSettings(message); 743167f43a2SStephan Aßmus 74461604e48SAxel Dörfler if (command >= B_MOUSE_TYPE_CHANGED 74561604e48SAxel Dörfler && command <= B_MOUSE_ACCELERATION_CHANGED) 74661604e48SAxel Dörfler return device->UpdateSettings(); 74761604e48SAxel Dörfler 74861604e48SAxel Dörfler return B_BAD_VALUE; 74961604e48SAxel Dörfler } 75061604e48SAxel Dörfler 75161604e48SAxel Dörfler 75261604e48SAxel Dörfler status_t 75361604e48SAxel Dörfler MouseInputDevice::_HandleMonitor(BMessage* message) 75461604e48SAxel Dörfler { 755e01a0431SStephan Aßmus MID_CALLED(); 75661604e48SAxel Dörfler 757b6a7b204SAxel Dörfler const char* path; 75861604e48SAxel Dörfler int32 opcode; 759b6a7b204SAxel Dörfler if (message->FindInt32("opcode", &opcode) != B_OK 760c5555ad3SStephan Aßmus || (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED) 761b6a7b204SAxel Dörfler || message->FindString("path", &path) != B_OK) 76261604e48SAxel Dörfler return B_BAD_VALUE; 76361604e48SAxel Dörfler 76461604e48SAxel Dörfler if (opcode == B_ENTRY_CREATED) 765b6a7b204SAxel Dörfler return _AddDevice(path); 76661604e48SAxel Dörfler 767c5555ad3SStephan Aßmus #if 0 768b6a7b204SAxel Dörfler return _RemoveDevice(path); 769c5555ad3SStephan Aßmus #else 770c5555ad3SStephan Aßmus // Don't handle B_ENTRY_REMOVED, let the control thread take care of it. 771c5555ad3SStephan Aßmus return B_OK; 772c5555ad3SStephan Aßmus #endif 77361604e48SAxel Dörfler } 77461604e48SAxel Dörfler 77561604e48SAxel Dörfler 77661604e48SAxel Dörfler void 77761604e48SAxel Dörfler MouseInputDevice::_RecursiveScan(const char* directory) 77861604e48SAxel Dörfler { 779e01a0431SStephan Aßmus MID_CALLED(); 78061604e48SAxel Dörfler 78161604e48SAxel Dörfler BEntry entry; 78261604e48SAxel Dörfler BDirectory dir(directory); 78361604e48SAxel Dörfler while (dir.GetNextEntry(&entry) == B_OK) { 78461604e48SAxel Dörfler BPath path; 78561604e48SAxel Dörfler entry.GetPath(&path); 78661604e48SAxel Dörfler 78761604e48SAxel Dörfler if (!strcmp(path.Leaf(), "serial")) { 78861604e48SAxel Dörfler // skip serial 78961604e48SAxel Dörfler continue; 79061604e48SAxel Dörfler } 79161604e48SAxel Dörfler 79261604e48SAxel Dörfler if (entry.IsDirectory()) 79361604e48SAxel Dörfler _RecursiveScan(path.Path()); 79461604e48SAxel Dörfler else 79561604e48SAxel Dörfler _AddDevice(path.Path()); 79661604e48SAxel Dörfler } 79761604e48SAxel Dörfler } 79861604e48SAxel Dörfler 799e01a0431SStephan Aßmus 800e01a0431SStephan Aßmus MouseDevice* 8015125eae2SStephan Aßmus MouseInputDevice::_FindDevice(const char* path) const 802e01a0431SStephan Aßmus { 803e01a0431SStephan Aßmus MID_CALLED(); 804e01a0431SStephan Aßmus 805e01a0431SStephan Aßmus for (int32 i = fDevices.CountItems() - 1; i >= 0; i--) { 806e01a0431SStephan Aßmus MouseDevice* device = fDevices.ItemAt(i); 807e01a0431SStephan Aßmus if (strcmp(device->Path(), path) == 0) 808e01a0431SStephan Aßmus return device; 809e01a0431SStephan Aßmus } 810e01a0431SStephan Aßmus 811e01a0431SStephan Aßmus return NULL; 812e01a0431SStephan Aßmus } 813e01a0431SStephan Aßmus 814e01a0431SStephan Aßmus 815e01a0431SStephan Aßmus status_t 816e01a0431SStephan Aßmus MouseInputDevice::_AddDevice(const char* path) 817e01a0431SStephan Aßmus { 818e01a0431SStephan Aßmus MID_CALLED(); 819e01a0431SStephan Aßmus 8205125eae2SStephan Aßmus BAutolock _(fDeviceListLock); 8215125eae2SStephan Aßmus 822e01a0431SStephan Aßmus _RemoveDevice(path); 823e01a0431SStephan Aßmus 824e01a0431SStephan Aßmus MouseDevice* device = new(std::nothrow) MouseDevice(*this, path); 825*fdad31e6SMichael Lotz if (device == NULL) { 826e01a0431SStephan Aßmus TRACE("No memory\n"); 827e01a0431SStephan Aßmus return B_NO_MEMORY; 828e01a0431SStephan Aßmus } 829e01a0431SStephan Aßmus 830e01a0431SStephan Aßmus if (!fDevices.AddItem(device)) { 831e01a0431SStephan Aßmus TRACE("No memory in list\n"); 832e01a0431SStephan Aßmus delete device; 833e01a0431SStephan Aßmus return B_NO_MEMORY; 834e01a0431SStephan Aßmus } 835e01a0431SStephan Aßmus 836e01a0431SStephan Aßmus input_device_ref* devices[2]; 837e01a0431SStephan Aßmus devices[0] = device->DeviceRef(); 838e01a0431SStephan Aßmus devices[1] = NULL; 839e01a0431SStephan Aßmus 840e01a0431SStephan Aßmus TRACE("adding path: %s, name: %s\n", path, devices[0]->name); 841e01a0431SStephan Aßmus 842e01a0431SStephan Aßmus return RegisterDevices(devices); 843e01a0431SStephan Aßmus } 844e01a0431SStephan Aßmus 845e01a0431SStephan Aßmus 846e01a0431SStephan Aßmus status_t 847e01a0431SStephan Aßmus MouseInputDevice::_RemoveDevice(const char* path) 848e01a0431SStephan Aßmus { 849e01a0431SStephan Aßmus MID_CALLED(); 850e01a0431SStephan Aßmus 8515125eae2SStephan Aßmus BAutolock _(fDeviceListLock); 8525125eae2SStephan Aßmus 853e01a0431SStephan Aßmus MouseDevice* device = _FindDevice(path); 854e01a0431SStephan Aßmus if (device == NULL) { 855e01a0431SStephan Aßmus TRACE("%s not found\n", path); 856e01a0431SStephan Aßmus return B_ENTRY_NOT_FOUND; 857e01a0431SStephan Aßmus } 858e01a0431SStephan Aßmus 859e01a0431SStephan Aßmus input_device_ref* devices[2]; 860e01a0431SStephan Aßmus devices[0] = device->DeviceRef(); 861e01a0431SStephan Aßmus devices[1] = NULL; 862e01a0431SStephan Aßmus 863e01a0431SStephan Aßmus TRACE("removing path: %s, name: %s\n", path, devices[0]->name); 864e01a0431SStephan Aßmus 865e01a0431SStephan Aßmus UnregisterDevices(devices); 866e01a0431SStephan Aßmus 867e01a0431SStephan Aßmus fDevices.RemoveItem(device); 868e01a0431SStephan Aßmus 869e01a0431SStephan Aßmus return B_OK; 870e01a0431SStephan Aßmus } 871