123b47e0bSJérôme Duval /* 27d1d7033SStephan Aßmus * Copyright 2004-2009, 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 33b6a7b204SAxel Dörfler #include "kb_mouse_settings.h" 34b6a7b204SAxel Dörfler #include "kb_mouse_driver.h" 35167f43a2SStephan Aßmus #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; 22161604e48SAxel Dörfler if (fThread < B_OK) 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)); 231167f43a2SStephan Aßmus close(fDevice); 23261604e48SAxel Dörfler return status; 23361604e48SAxel Dörfler } 23461604e48SAxel Dörfler 2359195fe6eSStephan Aßmus return fDevice >= 0 ? B_OK : B_ERROR; 23661d7deeeSJérôme Duval } 23761d7deeeSJérôme Duval 23861d7deeeSJérôme Duval 239c2fbfb71SJérôme Duval void 24061604e48SAxel Dörfler MouseDevice::Stop() 24161604e48SAxel Dörfler { 242e01a0431SStephan Aßmus MD_CALLED(); 2431ccc2f2dSJérôme Duval 24461604e48SAxel Dörfler fActive = false; 24561604e48SAxel Dörfler // this will stop the thread as soon as it reads the next packet 24661604e48SAxel Dörfler 247e01a0431SStephan Aßmus close(fDevice); 248e01a0431SStephan Aßmus fDevice = -1; 249e01a0431SStephan Aßmus 25061604e48SAxel Dörfler if (fThread >= B_OK) { 25161604e48SAxel Dörfler // unblock the thread, which might wait on a semaphore. 25261604e48SAxel Dörfler suspend_thread(fThread); 25361604e48SAxel Dörfler resume_thread(fThread); 25461604e48SAxel Dörfler 25561604e48SAxel Dörfler status_t dummy; 25661604e48SAxel Dörfler wait_for_thread(fThread, &dummy); 25761604e48SAxel Dörfler } 25861604e48SAxel Dörfler } 25961604e48SAxel Dörfler 26061604e48SAxel Dörfler 26142b505fbSAxel Dörfler status_t 26242b505fbSAxel Dörfler MouseDevice::UpdateSettings() 26342b505fbSAxel Dörfler { 264e01a0431SStephan Aßmus MD_CALLED(); 26542b505fbSAxel Dörfler 2665125eae2SStephan Aßmus if (fThread < 0) 2675125eae2SStephan Aßmus return B_ERROR; 26842b505fbSAxel Dörfler 269167f43a2SStephan Aßmus // trigger updating the settings in the control thread 2705125eae2SStephan Aßmus fUpdateSettings = true; 271167f43a2SStephan Aßmus 272167f43a2SStephan Aßmus return B_OK; 273167f43a2SStephan Aßmus } 274167f43a2SStephan Aßmus 275167f43a2SStephan Aßmus 276167f43a2SStephan Aßmus status_t 277167f43a2SStephan Aßmus MouseDevice::UpdateTouchpadSettings(const BMessage* message) 278167f43a2SStephan Aßmus { 279167f43a2SStephan Aßmus if (!fIsTouchpad) 280167f43a2SStephan Aßmus return B_BAD_TYPE; 281167f43a2SStephan Aßmus if (fThread < 0) 282167f43a2SStephan Aßmus return B_ERROR; 283167f43a2SStephan Aßmus 284167f43a2SStephan Aßmus BAutolock _(fTouchpadSettingsLock); 285167f43a2SStephan Aßmus 286167f43a2SStephan Aßmus // trigger updating the settings in the control thread 287167f43a2SStephan Aßmus fUpdateSettings = true; 288167f43a2SStephan Aßmus 289167f43a2SStephan Aßmus delete fTouchpadSettingsMessage; 290167f43a2SStephan Aßmus fTouchpadSettingsMessage = new BMessage(*message); 29142b505fbSAxel Dörfler 29242b505fbSAxel Dörfler return B_OK; 2935125eae2SStephan Aßmus } 29442b505fbSAxel Dörfler 2955125eae2SStephan Aßmus 2965125eae2SStephan Aßmus char* 2975125eae2SStephan Aßmus MouseDevice::_BuildShortName() const 2985125eae2SStephan Aßmus { 2995125eae2SStephan Aßmus BString string(fPath); 3005125eae2SStephan Aßmus BString name; 3015125eae2SStephan Aßmus 3025125eae2SStephan Aßmus int32 slash = string.FindLast("/"); 3035125eae2SStephan Aßmus string.CopyInto(name, slash + 1, string.Length() - slash); 3045125eae2SStephan Aßmus int32 index = atoi(name.String()) + 1; 3055125eae2SStephan Aßmus 3065125eae2SStephan Aßmus int32 previousSlash = string.FindLast("/", slash); 3075125eae2SStephan Aßmus string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1); 3085125eae2SStephan Aßmus 3095125eae2SStephan Aßmus if (name == "ps2") 3105125eae2SStephan Aßmus name = "PS/2"; 311155b8260SPhilippe Houdoin 312155b8260SPhilippe Houdoin if (name.Length() < 4) 313155b8260SPhilippe Houdoin name.ToUpper(); 3145125eae2SStephan Aßmus else 3155125eae2SStephan Aßmus name.Capitalize(); 3165125eae2SStephan Aßmus 317167f43a2SStephan Aßmus if (string.FindFirst("touchpad") >= 0) { 318167f43a2SStephan Aßmus name << " Touchpad "; 319167f43a2SStephan Aßmus } else { 320cc442411SStephan Aßmus if (string.FindFirst("intelli") >= 0) 321cc442411SStephan Aßmus name.Prepend("Extended "); 322cc442411SStephan Aßmus 323167f43a2SStephan Aßmus name << " Mouse "; 324167f43a2SStephan Aßmus } 325167f43a2SStephan Aßmus name << index; 3265125eae2SStephan Aßmus 3275125eae2SStephan Aßmus return strdup(name.String()); 3285125eae2SStephan Aßmus } 3295125eae2SStephan Aßmus 3305125eae2SStephan Aßmus 3315125eae2SStephan Aßmus // #pragma mark - control thread 3325125eae2SStephan Aßmus 3335125eae2SStephan Aßmus 3345125eae2SStephan Aßmus status_t 3355125eae2SStephan Aßmus MouseDevice::_ControlThreadEntry(void* arg) 3365125eae2SStephan Aßmus { 3375125eae2SStephan Aßmus MouseDevice* device = (MouseDevice*)arg; 3385125eae2SStephan Aßmus device->_ControlThread(); 3395125eae2SStephan Aßmus return B_OK; 34042b505fbSAxel Dörfler } 34142b505fbSAxel Dörfler 34242b505fbSAxel Dörfler 34361604e48SAxel Dörfler void 3445125eae2SStephan Aßmus MouseDevice::_ControlThread() 34561604e48SAxel Dörfler { 346167f43a2SStephan Aßmus MD_CALLED(); 347167f43a2SStephan Aßmus 3485125eae2SStephan Aßmus if (fDevice < 0) { 3495125eae2SStephan Aßmus _ControlThreadCleanup(); 3505125eae2SStephan Aßmus // TOAST! 3515125eae2SStephan Aßmus return; 3525125eae2SStephan Aßmus } 3535125eae2SStephan Aßmus 354167f43a2SStephan Aßmus // touchpad settings 355167f43a2SStephan Aßmus if (ioctl(fDevice, MS_IS_TOUCHPAD, NULL) == B_OK) { 356167f43a2SStephan Aßmus TRACE("is touchpad %s\n", fPath.String()); 357167f43a2SStephan Aßmus fIsTouchpad = true; 358167f43a2SStephan Aßmus 359167f43a2SStephan Aßmus fTouchpadSettings = kDefaultTouchpadSettings; 360167f43a2SStephan Aßmus 361167f43a2SStephan Aßmus BPath path; 362167f43a2SStephan Aßmus status_t status = _GetTouchpadSettingsPath(path); 363167f43a2SStephan Aßmus BFile settingsFile(path.Path(), B_READ_ONLY); 364167f43a2SStephan Aßmus if (status == B_OK && settingsFile.InitCheck() == B_OK) { 365167f43a2SStephan Aßmus if (settingsFile.Read(&fTouchpadSettings, sizeof(touchpad_settings)) 366167f43a2SStephan Aßmus != sizeof(touchpad_settings)) { 367167f43a2SStephan Aßmus TRACE("failed to load settings\n"); 368167f43a2SStephan Aßmus } 369167f43a2SStephan Aßmus } 370167f43a2SStephan Aßmus _UpdateTouchpadSettings(); 371167f43a2SStephan Aßmus } 372167f43a2SStephan Aßmus 3735125eae2SStephan Aßmus _UpdateSettings(); 3745125eae2SStephan Aßmus 37561604e48SAxel Dörfler uint32 lastButtons = 0; 3766e094221SStephan Aßmus float historyDeltaX = 0.0; 3776e094221SStephan Aßmus float historyDeltaY = 0.0; 37861604e48SAxel Dörfler 3797d1d7033SStephan Aßmus static const bigtime_t kTransferDelay = 1000000 / 125; 3807d1d7033SStephan Aßmus // 125 transfers per second should be more than enough 3815994d47aSStephan Aßmus #define USE_REGULAR_INTERVAL 1 3827d1d7033SStephan Aßmus #if USE_REGULAR_INTERVAL 3837d1d7033SStephan Aßmus bigtime_t nextTransferTime = system_time() + kTransferDelay; 3847d1d7033SStephan Aßmus #endif 3857d1d7033SStephan Aßmus 38661604e48SAxel Dörfler while (fActive) { 38761604e48SAxel Dörfler mouse_movement movements; 3887d1d7033SStephan Aßmus 3897d1d7033SStephan Aßmus #if USE_REGULAR_INTERVAL 3907d1d7033SStephan Aßmus snooze_until(nextTransferTime, B_SYSTEM_TIMEBASE); 3917d1d7033SStephan Aßmus nextTransferTime += kTransferDelay; 3927d1d7033SStephan Aßmus #endif 3937d1d7033SStephan Aßmus 394c5555ad3SStephan Aßmus if (ioctl(fDevice, MS_READ, &movements) != B_OK) { 3955125eae2SStephan Aßmus _ControlThreadCleanup(); 396c5555ad3SStephan Aßmus // TOAST! 39761604e48SAxel Dörfler return; 398c5555ad3SStephan Aßmus } 39961604e48SAxel Dörfler 4005125eae2SStephan Aßmus // take care of updating the settings first, if necessary 4015125eae2SStephan Aßmus if (fUpdateSettings) { 4025125eae2SStephan Aßmus fUpdateSettings = false; 403167f43a2SStephan Aßmus if (fIsTouchpad) { 404167f43a2SStephan Aßmus BAutolock _(fTouchpadSettingsLock); 4053bf47305SAxel Dörfler if (fTouchpadSettingsMessage != NULL) { 406167f43a2SStephan Aßmus _ReadTouchpadSettingsMsg(fTouchpadSettingsMessage); 407167f43a2SStephan Aßmus _UpdateTouchpadSettings(); 408167f43a2SStephan Aßmus delete fTouchpadSettingsMessage; 409167f43a2SStephan Aßmus fTouchpadSettingsMessage = NULL; 410167f43a2SStephan Aßmus } else 411167f43a2SStephan Aßmus _UpdateSettings(); 412167f43a2SStephan Aßmus } else 413167f43a2SStephan Aßmus _UpdateSettings(); 4145125eae2SStephan Aßmus } 4155125eae2SStephan Aßmus 41661604e48SAxel Dörfler uint32 buttons = lastButtons ^ movements.buttons; 41761604e48SAxel Dörfler 41861604e48SAxel Dörfler uint32 remappedButtons = _RemapButtons(movements.buttons); 41961604e48SAxel Dörfler int32 deltaX, deltaY; 4206e094221SStephan Aßmus _ComputeAcceleration(movements, deltaX, deltaY, historyDeltaX, 4216e094221SStephan Aßmus historyDeltaY); 42261604e48SAxel Dörfler 4236e094221SStephan Aßmus LOG_EVENT("%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld, " 4246e094221SStephan Aßmus "wheel_x:%ld, wheel_y:%ld\n", 4256e094221SStephan Aßmus fDeviceRef.name, movements.buttons, 4266e094221SStephan Aßmus movements.xdelta, movements.ydelta, movements.clicks, 4276e094221SStephan Aßmus movements.wheel_xdelta, movements.wheel_ydelta); 4286e094221SStephan Aßmus LOG_EVENT("%s: x: %ld, y: %ld (%.4f, %.4f)\n", fDeviceRef.name, 4296e094221SStephan Aßmus deltaX, deltaY, historyDeltaX, historyDeltaY); 43061604e48SAxel Dörfler 43161604e48SAxel Dörfler // Send single messages for each event 43261604e48SAxel Dörfler 43361604e48SAxel Dörfler if (buttons != 0) { 43461604e48SAxel Dörfler bool pressedButton = (buttons & movements.buttons) > 0; 43561604e48SAxel Dörfler BMessage* message = _BuildMouseMessage( 43661604e48SAxel Dörfler pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP, 43761604e48SAxel Dörfler movements.timestamp, remappedButtons, deltaX, deltaY); 43861604e48SAxel Dörfler if (message != NULL) { 43961604e48SAxel Dörfler if (pressedButton) { 44061604e48SAxel Dörfler message->AddInt32("clicks", movements.clicks); 441e01a0431SStephan Aßmus LOG_EVENT("B_MOUSE_DOWN\n"); 44261604e48SAxel Dörfler } else 443e01a0431SStephan Aßmus LOG_EVENT("B_MOUSE_UP\n"); 44461604e48SAxel Dörfler 44561604e48SAxel Dörfler fTarget.EnqueueMessage(message); 44661604e48SAxel Dörfler lastButtons = movements.buttons; 44761604e48SAxel Dörfler } 44861604e48SAxel Dörfler } 44961604e48SAxel Dörfler 45045f11ce8SStephan Aßmus if (movements.xdelta != 0 || movements.ydelta != 0) { 45145f11ce8SStephan Aßmus BMessage* message = _BuildMouseMessage(B_MOUSE_MOVED, 45245f11ce8SStephan Aßmus movements.timestamp, remappedButtons, deltaX, deltaY); 45345f11ce8SStephan Aßmus if (message != NULL) 45445f11ce8SStephan Aßmus fTarget.EnqueueMessage(message); 45545f11ce8SStephan Aßmus } 45645f11ce8SStephan Aßmus 45761604e48SAxel Dörfler if ((movements.wheel_ydelta != 0) || (movements.wheel_xdelta != 0)) { 458c5555ad3SStephan Aßmus BMessage* message = new BMessage(B_MOUSE_WHEEL_CHANGED); 45961604e48SAxel Dörfler if (message == NULL) 46061604e48SAxel Dörfler continue; 46161604e48SAxel Dörfler 46261604e48SAxel Dörfler if (message->AddInt64("when", movements.timestamp) == B_OK 4633bf47305SAxel Dörfler && message->AddFloat("be:wheel_delta_x", 4643bf47305SAxel Dörfler movements.wheel_xdelta) == B_OK 4653bf47305SAxel Dörfler && message->AddFloat("be:wheel_delta_y", 4663bf47305SAxel Dörfler movements.wheel_ydelta) == B_OK) 46761604e48SAxel Dörfler fTarget.EnqueueMessage(message); 46861604e48SAxel Dörfler else 46961604e48SAxel Dörfler delete message; 47061604e48SAxel Dörfler } 4717d1d7033SStephan Aßmus 4727d1d7033SStephan Aßmus #if !USE_REGULAR_INTERVAL 4737d1d7033SStephan Aßmus snooze(kTransferDelay); 4747d1d7033SStephan Aßmus #endif 47561604e48SAxel Dörfler } 47661604e48SAxel Dörfler } 47761604e48SAxel Dörfler 47861604e48SAxel Dörfler 4795125eae2SStephan Aßmus void 4805125eae2SStephan Aßmus MouseDevice::_ControlThreadCleanup() 48161604e48SAxel Dörfler { 4825125eae2SStephan Aßmus // NOTE: Only executed when the control thread detected an error 4835125eae2SStephan Aßmus // and from within the control thread! 4845125eae2SStephan Aßmus 4855125eae2SStephan Aßmus if (fActive) { 4865125eae2SStephan Aßmus fThread = -1; 4875125eae2SStephan Aßmus fTarget._RemoveDevice(fPath.String()); 4885125eae2SStephan Aßmus } else { 4895125eae2SStephan Aßmus // In case active is already false, another thread 4905125eae2SStephan Aßmus // waits for this thread to quit, and may already hold 4915125eae2SStephan Aßmus // locks that _RemoveDevice() wants to acquire. In another 4925125eae2SStephan Aßmus // words, the device is already being removed, so we simply 4935125eae2SStephan Aßmus // quit here. 4945125eae2SStephan Aßmus } 4955125eae2SStephan Aßmus } 4965125eae2SStephan Aßmus 4975125eae2SStephan Aßmus 4985125eae2SStephan Aßmus void 4995125eae2SStephan Aßmus MouseDevice::_UpdateSettings() 5005125eae2SStephan Aßmus { 5015125eae2SStephan Aßmus MD_CALLED(); 5025125eae2SStephan Aßmus 5035125eae2SStephan Aßmus // retrieve current values 5045125eae2SStephan Aßmus 5055125eae2SStephan Aßmus if (get_mouse_map(&fSettings.map) != B_OK) 5065125eae2SStephan Aßmus LOG_ERR("error when get_mouse_map\n"); 5075125eae2SStephan Aßmus else { 5085125eae2SStephan Aßmus fDeviceRemapsButtons 5095125eae2SStephan Aßmus = ioctl(fDevice, MS_SET_MAP, &fSettings.map) == B_OK; 5105125eae2SStephan Aßmus } 5115125eae2SStephan Aßmus 5125125eae2SStephan Aßmus if (get_click_speed(&fSettings.click_speed) != B_OK) 5135125eae2SStephan Aßmus LOG_ERR("error when get_click_speed\n"); 5145125eae2SStephan Aßmus else 5155125eae2SStephan Aßmus ioctl(fDevice, MS_SET_CLICKSPEED, &fSettings.click_speed); 5165125eae2SStephan Aßmus 5175125eae2SStephan Aßmus if (get_mouse_speed(&fSettings.accel.speed) != B_OK) 5185125eae2SStephan Aßmus LOG_ERR("error when get_mouse_speed\n"); 5195125eae2SStephan Aßmus else { 5205125eae2SStephan Aßmus if (get_mouse_acceleration(&fSettings.accel.accel_factor) != B_OK) 5215125eae2SStephan Aßmus LOG_ERR("error when get_mouse_acceleration\n"); 5225125eae2SStephan Aßmus else { 5235125eae2SStephan Aßmus mouse_accel accel; 5245125eae2SStephan Aßmus ioctl(fDevice, MS_GET_ACCEL, &accel); 5255125eae2SStephan Aßmus accel.speed = fSettings.accel.speed; 5265125eae2SStephan Aßmus accel.accel_factor = fSettings.accel.accel_factor; 5275125eae2SStephan Aßmus ioctl(fDevice, MS_SET_ACCEL, &fSettings.accel); 5285125eae2SStephan Aßmus } 5295125eae2SStephan Aßmus } 5305125eae2SStephan Aßmus 5315125eae2SStephan Aßmus if (get_mouse_type(&fSettings.type) != B_OK) 5325125eae2SStephan Aßmus LOG_ERR("error when get_mouse_type\n"); 5335125eae2SStephan Aßmus else 5345125eae2SStephan Aßmus ioctl(fDevice, MS_SET_TYPE, &fSettings.type); 53561604e48SAxel Dörfler } 53661604e48SAxel Dörfler 53761604e48SAxel Dörfler 538167f43a2SStephan Aßmus status_t 539167f43a2SStephan Aßmus MouseDevice::_GetTouchpadSettingsPath(BPath& path) 540167f43a2SStephan Aßmus { 541167f43a2SStephan Aßmus status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); 542167f43a2SStephan Aßmus if (status < B_OK) 543167f43a2SStephan Aßmus return status; 544167f43a2SStephan Aßmus return path.Append(TOUCHPAD_SETTINGS_FILE); 545167f43a2SStephan Aßmus } 546167f43a2SStephan Aßmus 547167f43a2SStephan Aßmus 548167f43a2SStephan Aßmus status_t 549167f43a2SStephan Aßmus MouseDevice::_ReadTouchpadSettingsMsg(BMessage* message) 550167f43a2SStephan Aßmus { 5513bf47305SAxel Dörfler message->FindBool("scroll_twofinger", &fTouchpadSettings.scroll_twofinger); 552*fc548b41SAxel Dörfler message->FindBool("scroll_twofinger_horizontal", 553*fc548b41SAxel Dörfler &fTouchpadSettings.scroll_twofinger_horizontal); 554167f43a2SStephan Aßmus message->FindFloat("scroll_rightrange", 5553bf47305SAxel Dörfler &fTouchpadSettings.scroll_rightrange); 556167f43a2SStephan Aßmus message->FindFloat("scroll_bottomrange", 5573bf47305SAxel Dörfler &fTouchpadSettings.scroll_bottomrange); 5583bf47305SAxel Dörfler 559167f43a2SStephan Aßmus message->FindInt16("scroll_xstepsize", 5603bf47305SAxel Dörfler (int16*)&fTouchpadSettings.scroll_xstepsize); 561167f43a2SStephan Aßmus message->FindInt16("scroll_ystepsize", 5623bf47305SAxel Dörfler (int16*)&fTouchpadSettings.scroll_ystepsize); 563167f43a2SStephan Aßmus message->FindInt8("scroll_acceleration", 5643bf47305SAxel Dörfler (int8*)&fTouchpadSettings.scroll_acceleration); 565167f43a2SStephan Aßmus message->FindInt8("tapgesture_sensibility", 5663bf47305SAxel Dörfler (int8*)&fTouchpadSettings.tapgesture_sensibility); 567167f43a2SStephan Aßmus 568167f43a2SStephan Aßmus return B_OK; 569167f43a2SStephan Aßmus } 570167f43a2SStephan Aßmus 571167f43a2SStephan Aßmus 572167f43a2SStephan Aßmus status_t 573167f43a2SStephan Aßmus MouseDevice::_UpdateTouchpadSettings() 574167f43a2SStephan Aßmus { 575167f43a2SStephan Aßmus if (fIsTouchpad) { 576167f43a2SStephan Aßmus ioctl(fDevice, MS_SET_TOUCHPAD_SETTINGS, &fTouchpadSettings); 577167f43a2SStephan Aßmus return B_OK; 578167f43a2SStephan Aßmus } 579167f43a2SStephan Aßmus return B_ERROR; 580167f43a2SStephan Aßmus } 581167f43a2SStephan Aßmus 582167f43a2SStephan Aßmus 58361604e48SAxel Dörfler BMessage* 58461604e48SAxel Dörfler MouseDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, 58561604e48SAxel Dörfler int32 deltaX, int32 deltaY) const 58661604e48SAxel Dörfler { 58761604e48SAxel Dörfler BMessage* message = new BMessage(what); 58861604e48SAxel Dörfler if (message == NULL) 58961604e48SAxel Dörfler return NULL; 59061604e48SAxel Dörfler 59161604e48SAxel Dörfler if (message->AddInt64("when", when) < B_OK 59261604e48SAxel Dörfler || message->AddInt32("buttons", buttons) < B_OK 59361604e48SAxel Dörfler || message->AddInt32("x", deltaX) < B_OK 59461604e48SAxel Dörfler || message->AddInt32("y", deltaY) < B_OK) { 59561604e48SAxel Dörfler delete message; 59661604e48SAxel Dörfler return NULL; 59761604e48SAxel Dörfler } 59861604e48SAxel Dörfler 59961604e48SAxel Dörfler return message; 60061604e48SAxel Dörfler } 60161604e48SAxel Dörfler 60261604e48SAxel Dörfler 60361604e48SAxel Dörfler void 60461604e48SAxel Dörfler MouseDevice::_ComputeAcceleration(const mouse_movement& movements, 6056e094221SStephan Aßmus int32& _deltaX, int32& _deltaY, float& historyDeltaX, 6066e094221SStephan Aßmus float& historyDeltaY) const 60761604e48SAxel Dörfler { 60842b505fbSAxel Dörfler // basic mouse speed 6096e094221SStephan Aßmus float deltaX = (float)movements.xdelta * fSettings.accel.speed / 65536.0 6106e094221SStephan Aßmus + historyDeltaX; 6116e094221SStephan Aßmus float deltaY = (float)movements.ydelta * fSettings.accel.speed / 65536.0 6126e094221SStephan Aßmus + historyDeltaY; 61342b505fbSAxel Dörfler 61442b505fbSAxel Dörfler // acceleration 61542b505fbSAxel Dörfler double acceleration = 1; 61642b505fbSAxel Dörfler if (fSettings.accel.accel_factor) { 617fafab827SAxel Dörfler acceleration = 1 + sqrt(deltaX * deltaX + deltaY * deltaY) 61874ef1621SAxel Dörfler * fSettings.accel.accel_factor / 524288.0; 61942b505fbSAxel Dörfler } 62042b505fbSAxel Dörfler 6216e094221SStephan Aßmus deltaX *= acceleration; 6226e094221SStephan Aßmus deltaY *= acceleration; 62342b505fbSAxel Dörfler 6246e094221SStephan Aßmus if (deltaX >= 0) 6256e094221SStephan Aßmus _deltaX = (int32)floorf(deltaX); 626fafab827SAxel Dörfler else 6276e094221SStephan Aßmus _deltaX = (int32)ceilf(deltaX); 6286e094221SStephan Aßmus 6296e094221SStephan Aßmus if (deltaY >= 0) 6306e094221SStephan Aßmus _deltaY = (int32)floorf(deltaY); 6316e094221SStephan Aßmus else 6326e094221SStephan Aßmus _deltaY = (int32)ceilf(deltaY); 6336e094221SStephan Aßmus 6346e094221SStephan Aßmus historyDeltaX = deltaX - _deltaX; 6356e094221SStephan Aßmus historyDeltaY = deltaY - _deltaY; 63661604e48SAxel Dörfler } 63761604e48SAxel Dörfler 63833efb919SStefano Ceccherini 63923b47e0bSJérôme Duval uint32 64061604e48SAxel Dörfler MouseDevice::_RemapButtons(uint32 buttons) const 64123b47e0bSJérôme Duval { 64261604e48SAxel Dörfler if (fDeviceRemapsButtons) 64323b47e0bSJérôme Duval return buttons; 64423b47e0bSJérôme Duval 64561604e48SAxel Dörfler uint32 newButtons = 0; 64623b47e0bSJérôme Duval for (int32 i = 0; buttons; i++) { 64723b47e0bSJérôme Duval if (buttons & 0x1) { 64821631085SStephan Aßmus #if defined(HAIKU_TARGET_PLATFORM_HAIKU) || defined(HAIKU_TARGET_PLATFORM_DANO) 64961604e48SAxel Dörfler newButtons |= fSettings.map.button[i]; 65023b47e0bSJérôme Duval #else 65123b47e0bSJérôme Duval if (i == 0) 65261604e48SAxel Dörfler newButtons |= fSettings.map.left; 65323b47e0bSJérôme Duval if (i == 1) 65461604e48SAxel Dörfler newButtons |= fSettings.map.right; 65523b47e0bSJérôme Duval if (i == 2) 65661604e48SAxel Dörfler newButtons |= fSettings.map.middle; 65723b47e0bSJérôme Duval #endif 65823b47e0bSJérôme Duval } 65923b47e0bSJérôme Duval buttons >>= 1; 66023b47e0bSJérôme Duval } 66123b47e0bSJérôme Duval 66261604e48SAxel Dörfler return newButtons; 66323b47e0bSJérôme Duval } 66423b47e0bSJérôme Duval 66523b47e0bSJérôme Duval 66661604e48SAxel Dörfler // #pragma mark - 66761604e48SAxel Dörfler 66861604e48SAxel Dörfler 66961604e48SAxel Dörfler MouseInputDevice::MouseInputDevice() 670b6a7b204SAxel Dörfler : 6715125eae2SStephan Aßmus fDevices(2, true), 6725125eae2SStephan Aßmus fDeviceListLock("MouseInputDevice list") 67361604e48SAxel Dörfler { 674e01a0431SStephan Aßmus MID_CALLED(); 67561604e48SAxel Dörfler 676c5555ad3SStephan Aßmus StartMonitoringDevice(kMouseDevicesDirectory); 677167f43a2SStephan Aßmus StartMonitoringDevice(kTouchpadDevicesDirectory); 6789dd2d40eSStephan Aßmus _RecursiveScan(kMouseDevicesDirectory); 679167f43a2SStephan Aßmus _RecursiveScan(kTouchpadDevicesDirectory); 68061604e48SAxel Dörfler } 68161604e48SAxel Dörfler 68261604e48SAxel Dörfler 68361604e48SAxel Dörfler MouseInputDevice::~MouseInputDevice() 68461604e48SAxel Dörfler { 685e01a0431SStephan Aßmus MID_CALLED(); 686e01a0431SStephan Aßmus 687167f43a2SStephan Aßmus StopMonitoringDevice(kTouchpadDevicesDirectory); 688b6a7b204SAxel Dörfler StopMonitoringDevice(kMouseDevicesDirectory); 689e01a0431SStephan Aßmus fDevices.MakeEmpty(); 69061604e48SAxel Dörfler } 69161604e48SAxel Dörfler 69261604e48SAxel Dörfler 69361604e48SAxel Dörfler status_t 69461604e48SAxel Dörfler MouseInputDevice::InitCheck() 69561604e48SAxel Dörfler { 696e01a0431SStephan Aßmus MID_CALLED(); 697e01a0431SStephan Aßmus 698d246d9beSStefano Ceccherini return BInputServerDevice::InitCheck(); 69961604e48SAxel Dörfler } 70061604e48SAxel Dörfler 70161604e48SAxel Dörfler 70261604e48SAxel Dörfler status_t 70361604e48SAxel Dörfler MouseInputDevice::Start(const char* name, void* cookie) 70461604e48SAxel Dörfler { 705e01a0431SStephan Aßmus MID_CALLED(); 706e01a0431SStephan Aßmus 70761604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 70861604e48SAxel Dörfler 70961604e48SAxel Dörfler return device->Start(); 71061604e48SAxel Dörfler } 71161604e48SAxel Dörfler 71261604e48SAxel Dörfler 71361604e48SAxel Dörfler status_t 71461604e48SAxel Dörfler MouseInputDevice::Stop(const char* name, void* cookie) 71561604e48SAxel Dörfler { 716e01a0431SStephan Aßmus TRACE("%s(%s)\n", __PRETTY_FUNCTION__, name); 71761604e48SAxel Dörfler 718e01a0431SStephan Aßmus MouseDevice* device = (MouseDevice*)cookie; 71961604e48SAxel Dörfler device->Stop(); 720e01a0431SStephan Aßmus 72161604e48SAxel Dörfler return B_OK; 72261604e48SAxel Dörfler } 72361604e48SAxel Dörfler 72461604e48SAxel Dörfler 72561604e48SAxel Dörfler status_t 72661604e48SAxel Dörfler MouseInputDevice::Control(const char* name, void* cookie, 72761604e48SAxel Dörfler uint32 command, BMessage* message) 72861604e48SAxel Dörfler { 729e01a0431SStephan Aßmus TRACE("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command); 730e01a0431SStephan Aßmus 73161604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 73261604e48SAxel Dörfler 73361604e48SAxel Dörfler if (command == B_NODE_MONITOR) 73461604e48SAxel Dörfler return _HandleMonitor(message); 73561604e48SAxel Dörfler 736167f43a2SStephan Aßmus if (command == MS_SET_TOUCHPAD_SETTINGS) 737167f43a2SStephan Aßmus return device->UpdateTouchpadSettings(message); 738167f43a2SStephan Aßmus 73961604e48SAxel Dörfler if (command >= B_MOUSE_TYPE_CHANGED 74061604e48SAxel Dörfler && command <= B_MOUSE_ACCELERATION_CHANGED) 74161604e48SAxel Dörfler return device->UpdateSettings(); 74261604e48SAxel Dörfler 74361604e48SAxel Dörfler return B_BAD_VALUE; 74461604e48SAxel Dörfler } 74561604e48SAxel Dörfler 74661604e48SAxel Dörfler 74761604e48SAxel Dörfler status_t 74861604e48SAxel Dörfler MouseInputDevice::_HandleMonitor(BMessage* message) 74961604e48SAxel Dörfler { 750e01a0431SStephan Aßmus MID_CALLED(); 75161604e48SAxel Dörfler 752b6a7b204SAxel Dörfler const char* path; 75361604e48SAxel Dörfler int32 opcode; 754b6a7b204SAxel Dörfler if (message->FindInt32("opcode", &opcode) != B_OK 755c5555ad3SStephan Aßmus || (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED) 756b6a7b204SAxel Dörfler || message->FindString("path", &path) != B_OK) 75761604e48SAxel Dörfler return B_BAD_VALUE; 75861604e48SAxel Dörfler 75961604e48SAxel Dörfler if (opcode == B_ENTRY_CREATED) 760b6a7b204SAxel Dörfler return _AddDevice(path); 76161604e48SAxel Dörfler 762c5555ad3SStephan Aßmus #if 0 763b6a7b204SAxel Dörfler return _RemoveDevice(path); 764c5555ad3SStephan Aßmus #else 765c5555ad3SStephan Aßmus // Don't handle B_ENTRY_REMOVED, let the control thread take care of it. 766c5555ad3SStephan Aßmus return B_OK; 767c5555ad3SStephan Aßmus #endif 76861604e48SAxel Dörfler } 76961604e48SAxel Dörfler 77061604e48SAxel Dörfler 77161604e48SAxel Dörfler void 77261604e48SAxel Dörfler MouseInputDevice::_RecursiveScan(const char* directory) 77361604e48SAxel Dörfler { 774e01a0431SStephan Aßmus MID_CALLED(); 77561604e48SAxel Dörfler 77661604e48SAxel Dörfler BEntry entry; 77761604e48SAxel Dörfler BDirectory dir(directory); 77861604e48SAxel Dörfler while (dir.GetNextEntry(&entry) == B_OK) { 77961604e48SAxel Dörfler BPath path; 78061604e48SAxel Dörfler entry.GetPath(&path); 78161604e48SAxel Dörfler 78261604e48SAxel Dörfler if (!strcmp(path.Leaf(), "serial")) { 78361604e48SAxel Dörfler // skip serial 78461604e48SAxel Dörfler continue; 78561604e48SAxel Dörfler } 78661604e48SAxel Dörfler 78761604e48SAxel Dörfler if (entry.IsDirectory()) 78861604e48SAxel Dörfler _RecursiveScan(path.Path()); 78961604e48SAxel Dörfler else 79061604e48SAxel Dörfler _AddDevice(path.Path()); 79161604e48SAxel Dörfler } 79261604e48SAxel Dörfler } 79361604e48SAxel Dörfler 794e01a0431SStephan Aßmus 795e01a0431SStephan Aßmus MouseDevice* 7965125eae2SStephan Aßmus MouseInputDevice::_FindDevice(const char* path) const 797e01a0431SStephan Aßmus { 798e01a0431SStephan Aßmus MID_CALLED(); 799e01a0431SStephan Aßmus 800e01a0431SStephan Aßmus for (int32 i = fDevices.CountItems() - 1; i >= 0; i--) { 801e01a0431SStephan Aßmus MouseDevice* device = fDevices.ItemAt(i); 802e01a0431SStephan Aßmus if (strcmp(device->Path(), path) == 0) 803e01a0431SStephan Aßmus return device; 804e01a0431SStephan Aßmus } 805e01a0431SStephan Aßmus 806e01a0431SStephan Aßmus return NULL; 807e01a0431SStephan Aßmus } 808e01a0431SStephan Aßmus 809e01a0431SStephan Aßmus 810e01a0431SStephan Aßmus status_t 811e01a0431SStephan Aßmus MouseInputDevice::_AddDevice(const char* path) 812e01a0431SStephan Aßmus { 813e01a0431SStephan Aßmus MID_CALLED(); 814e01a0431SStephan Aßmus 8155125eae2SStephan Aßmus BAutolock _(fDeviceListLock); 8165125eae2SStephan Aßmus 817e01a0431SStephan Aßmus _RemoveDevice(path); 818e01a0431SStephan Aßmus 819e01a0431SStephan Aßmus MouseDevice* device = new(std::nothrow) MouseDevice(*this, path); 820e01a0431SStephan Aßmus if (!device) { 821e01a0431SStephan Aßmus TRACE("No memory\n"); 822e01a0431SStephan Aßmus return B_NO_MEMORY; 823e01a0431SStephan Aßmus } 824e01a0431SStephan Aßmus 825e01a0431SStephan Aßmus if (!fDevices.AddItem(device)) { 826e01a0431SStephan Aßmus TRACE("No memory in list\n"); 827e01a0431SStephan Aßmus delete device; 828e01a0431SStephan Aßmus return B_NO_MEMORY; 829e01a0431SStephan Aßmus } 830e01a0431SStephan Aßmus 831e01a0431SStephan Aßmus input_device_ref* devices[2]; 832e01a0431SStephan Aßmus devices[0] = device->DeviceRef(); 833e01a0431SStephan Aßmus devices[1] = NULL; 834e01a0431SStephan Aßmus 835e01a0431SStephan Aßmus TRACE("adding path: %s, name: %s\n", path, devices[0]->name); 836e01a0431SStephan Aßmus 837e01a0431SStephan Aßmus return RegisterDevices(devices); 838e01a0431SStephan Aßmus } 839e01a0431SStephan Aßmus 840e01a0431SStephan Aßmus 841e01a0431SStephan Aßmus status_t 842e01a0431SStephan Aßmus MouseInputDevice::_RemoveDevice(const char* path) 843e01a0431SStephan Aßmus { 844e01a0431SStephan Aßmus MID_CALLED(); 845e01a0431SStephan Aßmus 8465125eae2SStephan Aßmus BAutolock _(fDeviceListLock); 8475125eae2SStephan Aßmus 848e01a0431SStephan Aßmus MouseDevice* device = _FindDevice(path); 849e01a0431SStephan Aßmus if (device == NULL) { 850e01a0431SStephan Aßmus TRACE("%s not found\n", path); 851e01a0431SStephan Aßmus return B_ENTRY_NOT_FOUND; 852e01a0431SStephan Aßmus } 853e01a0431SStephan Aßmus 854e01a0431SStephan Aßmus input_device_ref* devices[2]; 855e01a0431SStephan Aßmus devices[0] = device->DeviceRef(); 856e01a0431SStephan Aßmus devices[1] = NULL; 857e01a0431SStephan Aßmus 858e01a0431SStephan Aßmus TRACE("removing path: %s, name: %s\n", path, devices[0]->name); 859e01a0431SStephan Aßmus 860e01a0431SStephan Aßmus UnregisterDevices(devices); 861e01a0431SStephan Aßmus 862e01a0431SStephan Aßmus fDevices.RemoveItem(device); 863e01a0431SStephan Aßmus 864e01a0431SStephan Aßmus return B_OK; 865e01a0431SStephan Aßmus } 866