123b47e0bSJérôme Duval /* 2*7d1d7033SStephan 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"; 3115125eae2SStephan Aßmus else 3125125eae2SStephan Aßmus name.Capitalize(); 3135125eae2SStephan Aßmus 314167f43a2SStephan Aßmus if (string.FindFirst("touchpad") >= 0) { 315167f43a2SStephan Aßmus name << " Touchpad "; 316167f43a2SStephan Aßmus } else { 317cc442411SStephan Aßmus if (string.FindFirst("intelli") >= 0) 318cc442411SStephan Aßmus name.Prepend("Extended "); 319cc442411SStephan Aßmus 320167f43a2SStephan Aßmus name << " Mouse "; 321167f43a2SStephan Aßmus } 322167f43a2SStephan Aßmus name << index; 3235125eae2SStephan Aßmus 3245125eae2SStephan Aßmus return strdup(name.String()); 3255125eae2SStephan Aßmus } 3265125eae2SStephan Aßmus 3275125eae2SStephan Aßmus 3285125eae2SStephan Aßmus // #pragma mark - control thread 3295125eae2SStephan Aßmus 3305125eae2SStephan Aßmus 3315125eae2SStephan Aßmus status_t 3325125eae2SStephan Aßmus MouseDevice::_ControlThreadEntry(void* arg) 3335125eae2SStephan Aßmus { 3345125eae2SStephan Aßmus MouseDevice* device = (MouseDevice*)arg; 3355125eae2SStephan Aßmus device->_ControlThread(); 3365125eae2SStephan Aßmus return B_OK; 33742b505fbSAxel Dörfler } 33842b505fbSAxel Dörfler 33942b505fbSAxel Dörfler 34061604e48SAxel Dörfler void 3415125eae2SStephan Aßmus MouseDevice::_ControlThread() 34261604e48SAxel Dörfler { 343167f43a2SStephan Aßmus MD_CALLED(); 344167f43a2SStephan Aßmus 3455125eae2SStephan Aßmus if (fDevice < 0) { 3465125eae2SStephan Aßmus _ControlThreadCleanup(); 3475125eae2SStephan Aßmus // TOAST! 3485125eae2SStephan Aßmus return; 3495125eae2SStephan Aßmus } 3505125eae2SStephan Aßmus 351167f43a2SStephan Aßmus // touchpad settings 352167f43a2SStephan Aßmus if (ioctl(fDevice, MS_IS_TOUCHPAD, NULL) == B_OK) { 353167f43a2SStephan Aßmus TRACE("is touchpad %s\n", fPath.String()); 354167f43a2SStephan Aßmus fIsTouchpad = true; 355167f43a2SStephan Aßmus 356167f43a2SStephan Aßmus fTouchpadSettings = kDefaultTouchpadSettings; 357167f43a2SStephan Aßmus 358167f43a2SStephan Aßmus BPath path; 359167f43a2SStephan Aßmus status_t status = _GetTouchpadSettingsPath(path); 360167f43a2SStephan Aßmus BFile settingsFile(path.Path(), B_READ_ONLY); 361167f43a2SStephan Aßmus if (status == B_OK && settingsFile.InitCheck() == B_OK) { 362167f43a2SStephan Aßmus if (settingsFile.Read(&fTouchpadSettings, sizeof(touchpad_settings)) 363167f43a2SStephan Aßmus != sizeof(touchpad_settings)) { 364167f43a2SStephan Aßmus TRACE("failed to load settings\n"); 365167f43a2SStephan Aßmus } 366167f43a2SStephan Aßmus } 367167f43a2SStephan Aßmus _UpdateTouchpadSettings(); 368167f43a2SStephan Aßmus } 369167f43a2SStephan Aßmus 3705125eae2SStephan Aßmus _UpdateSettings(); 3715125eae2SStephan Aßmus 37261604e48SAxel Dörfler uint32 lastButtons = 0; 3736e094221SStephan Aßmus float historyDeltaX = 0.0; 3746e094221SStephan Aßmus float historyDeltaY = 0.0; 37561604e48SAxel Dörfler 376*7d1d7033SStephan Aßmus static const bigtime_t kTransferDelay = 1000000 / 125; 377*7d1d7033SStephan Aßmus // 125 transfers per second should be more than enough 378*7d1d7033SStephan Aßmus #define USE_REGULAR_INTERVAL 0 379*7d1d7033SStephan Aßmus #if USE_REGULAR_INTERVAL 380*7d1d7033SStephan Aßmus bigtime_t nextTransferTime = system_time() + kTransferDelay; 381*7d1d7033SStephan Aßmus #endif 382*7d1d7033SStephan Aßmus 38361604e48SAxel Dörfler while (fActive) { 38461604e48SAxel Dörfler mouse_movement movements; 385*7d1d7033SStephan Aßmus 386*7d1d7033SStephan Aßmus #if USE_REGULAR_INTERVAL 387*7d1d7033SStephan Aßmus snooze_until(nextTransferTime, B_SYSTEM_TIMEBASE); 388*7d1d7033SStephan Aßmus nextTransferTime += kTransferDelay; 389*7d1d7033SStephan Aßmus #endif 390*7d1d7033SStephan Aßmus 391c5555ad3SStephan Aßmus if (ioctl(fDevice, MS_READ, &movements) != B_OK) { 3925125eae2SStephan Aßmus _ControlThreadCleanup(); 393c5555ad3SStephan Aßmus // TOAST! 39461604e48SAxel Dörfler return; 395c5555ad3SStephan Aßmus } 39661604e48SAxel Dörfler 3975125eae2SStephan Aßmus // take care of updating the settings first, if necessary 3985125eae2SStephan Aßmus if (fUpdateSettings) { 3995125eae2SStephan Aßmus fUpdateSettings = false; 400167f43a2SStephan Aßmus if (fIsTouchpad) { 401167f43a2SStephan Aßmus BAutolock _(fTouchpadSettingsLock); 402167f43a2SStephan Aßmus if (fTouchpadSettingsMessage) { 403167f43a2SStephan Aßmus _ReadTouchpadSettingsMsg(fTouchpadSettingsMessage); 404167f43a2SStephan Aßmus _UpdateTouchpadSettings(); 405167f43a2SStephan Aßmus delete fTouchpadSettingsMessage; 406167f43a2SStephan Aßmus fTouchpadSettingsMessage = NULL; 407167f43a2SStephan Aßmus } else 408167f43a2SStephan Aßmus _UpdateSettings(); 409167f43a2SStephan Aßmus } else 410167f43a2SStephan Aßmus _UpdateSettings(); 4115125eae2SStephan Aßmus } 4125125eae2SStephan Aßmus 41361604e48SAxel Dörfler uint32 buttons = lastButtons ^ movements.buttons; 41461604e48SAxel Dörfler 41561604e48SAxel Dörfler uint32 remappedButtons = _RemapButtons(movements.buttons); 41661604e48SAxel Dörfler int32 deltaX, deltaY; 4176e094221SStephan Aßmus _ComputeAcceleration(movements, deltaX, deltaY, historyDeltaX, 4186e094221SStephan Aßmus historyDeltaY); 41961604e48SAxel Dörfler 4206e094221SStephan Aßmus LOG_EVENT("%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld, " 4216e094221SStephan Aßmus "wheel_x:%ld, wheel_y:%ld\n", 4226e094221SStephan Aßmus fDeviceRef.name, movements.buttons, 4236e094221SStephan Aßmus movements.xdelta, movements.ydelta, movements.clicks, 4246e094221SStephan Aßmus movements.wheel_xdelta, movements.wheel_ydelta); 4256e094221SStephan Aßmus LOG_EVENT("%s: x: %ld, y: %ld (%.4f, %.4f)\n", fDeviceRef.name, 4266e094221SStephan Aßmus deltaX, deltaY, historyDeltaX, historyDeltaY); 42761604e48SAxel Dörfler 42861604e48SAxel Dörfler // Send single messages for each event 42961604e48SAxel Dörfler 43061604e48SAxel Dörfler if (buttons != 0) { 43161604e48SAxel Dörfler bool pressedButton = (buttons & movements.buttons) > 0; 43261604e48SAxel Dörfler BMessage* message = _BuildMouseMessage( 43361604e48SAxel Dörfler pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP, 43461604e48SAxel Dörfler movements.timestamp, remappedButtons, deltaX, deltaY); 43561604e48SAxel Dörfler if (message != NULL) { 43661604e48SAxel Dörfler if (pressedButton) { 43761604e48SAxel Dörfler message->AddInt32("clicks", movements.clicks); 438e01a0431SStephan Aßmus LOG_EVENT("B_MOUSE_DOWN\n"); 43961604e48SAxel Dörfler } else 440e01a0431SStephan Aßmus LOG_EVENT("B_MOUSE_UP\n"); 44161604e48SAxel Dörfler 44261604e48SAxel Dörfler fTarget.EnqueueMessage(message); 44361604e48SAxel Dörfler lastButtons = movements.buttons; 44461604e48SAxel Dörfler } 44561604e48SAxel Dörfler } 44661604e48SAxel Dörfler 44745f11ce8SStephan Aßmus if (movements.xdelta != 0 || movements.ydelta != 0) { 44845f11ce8SStephan Aßmus BMessage* message = _BuildMouseMessage(B_MOUSE_MOVED, 44945f11ce8SStephan Aßmus movements.timestamp, remappedButtons, deltaX, deltaY); 45045f11ce8SStephan Aßmus if (message != NULL) 45145f11ce8SStephan Aßmus fTarget.EnqueueMessage(message); 45245f11ce8SStephan Aßmus } 45345f11ce8SStephan Aßmus 45461604e48SAxel Dörfler if ((movements.wheel_ydelta != 0) || (movements.wheel_xdelta != 0)) { 455c5555ad3SStephan Aßmus BMessage* message = new BMessage(B_MOUSE_WHEEL_CHANGED); 45661604e48SAxel Dörfler if (message == NULL) 45761604e48SAxel Dörfler continue; 45861604e48SAxel Dörfler 45961604e48SAxel Dörfler if (message->AddInt64("when", movements.timestamp) == B_OK 46061604e48SAxel Dörfler && message->AddFloat("be:wheel_delta_x", movements.wheel_xdelta) == B_OK 46161604e48SAxel Dörfler && message->AddFloat("be:wheel_delta_y", movements.wheel_ydelta) == B_OK) 46261604e48SAxel Dörfler fTarget.EnqueueMessage(message); 46361604e48SAxel Dörfler else 46461604e48SAxel Dörfler delete message; 46561604e48SAxel Dörfler } 466*7d1d7033SStephan Aßmus 467*7d1d7033SStephan Aßmus #if !USE_REGULAR_INTERVAL 468*7d1d7033SStephan Aßmus snooze(kTransferDelay); 469*7d1d7033SStephan Aßmus #endif 47061604e48SAxel Dörfler } 47161604e48SAxel Dörfler } 47261604e48SAxel Dörfler 47361604e48SAxel Dörfler 4745125eae2SStephan Aßmus void 4755125eae2SStephan Aßmus MouseDevice::_ControlThreadCleanup() 47661604e48SAxel Dörfler { 4775125eae2SStephan Aßmus // NOTE: Only executed when the control thread detected an error 4785125eae2SStephan Aßmus // and from within the control thread! 4795125eae2SStephan Aßmus 4805125eae2SStephan Aßmus if (fActive) { 4815125eae2SStephan Aßmus fThread = -1; 4825125eae2SStephan Aßmus fTarget._RemoveDevice(fPath.String()); 4835125eae2SStephan Aßmus } else { 4845125eae2SStephan Aßmus // In case active is already false, another thread 4855125eae2SStephan Aßmus // waits for this thread to quit, and may already hold 4865125eae2SStephan Aßmus // locks that _RemoveDevice() wants to acquire. In another 4875125eae2SStephan Aßmus // words, the device is already being removed, so we simply 4885125eae2SStephan Aßmus // quit here. 4895125eae2SStephan Aßmus } 4905125eae2SStephan Aßmus } 4915125eae2SStephan Aßmus 4925125eae2SStephan Aßmus 4935125eae2SStephan Aßmus void 4945125eae2SStephan Aßmus MouseDevice::_UpdateSettings() 4955125eae2SStephan Aßmus { 4965125eae2SStephan Aßmus MD_CALLED(); 4975125eae2SStephan Aßmus 4985125eae2SStephan Aßmus // retrieve current values 4995125eae2SStephan Aßmus 5005125eae2SStephan Aßmus if (get_mouse_map(&fSettings.map) != B_OK) 5015125eae2SStephan Aßmus LOG_ERR("error when get_mouse_map\n"); 5025125eae2SStephan Aßmus else { 5035125eae2SStephan Aßmus fDeviceRemapsButtons 5045125eae2SStephan Aßmus = ioctl(fDevice, MS_SET_MAP, &fSettings.map) == B_OK; 5055125eae2SStephan Aßmus } 5065125eae2SStephan Aßmus 5075125eae2SStephan Aßmus if (get_click_speed(&fSettings.click_speed) != B_OK) 5085125eae2SStephan Aßmus LOG_ERR("error when get_click_speed\n"); 5095125eae2SStephan Aßmus else 5105125eae2SStephan Aßmus ioctl(fDevice, MS_SET_CLICKSPEED, &fSettings.click_speed); 5115125eae2SStephan Aßmus 5125125eae2SStephan Aßmus if (get_mouse_speed(&fSettings.accel.speed) != B_OK) 5135125eae2SStephan Aßmus LOG_ERR("error when get_mouse_speed\n"); 5145125eae2SStephan Aßmus else { 5155125eae2SStephan Aßmus if (get_mouse_acceleration(&fSettings.accel.accel_factor) != B_OK) 5165125eae2SStephan Aßmus LOG_ERR("error when get_mouse_acceleration\n"); 5175125eae2SStephan Aßmus else { 5185125eae2SStephan Aßmus mouse_accel accel; 5195125eae2SStephan Aßmus ioctl(fDevice, MS_GET_ACCEL, &accel); 5205125eae2SStephan Aßmus accel.speed = fSettings.accel.speed; 5215125eae2SStephan Aßmus accel.accel_factor = fSettings.accel.accel_factor; 5225125eae2SStephan Aßmus ioctl(fDevice, MS_SET_ACCEL, &fSettings.accel); 5235125eae2SStephan Aßmus } 5245125eae2SStephan Aßmus } 5255125eae2SStephan Aßmus 5265125eae2SStephan Aßmus if (get_mouse_type(&fSettings.type) != B_OK) 5275125eae2SStephan Aßmus LOG_ERR("error when get_mouse_type\n"); 5285125eae2SStephan Aßmus else 5295125eae2SStephan Aßmus ioctl(fDevice, MS_SET_TYPE, &fSettings.type); 53061604e48SAxel Dörfler } 53161604e48SAxel Dörfler 53261604e48SAxel Dörfler 533167f43a2SStephan Aßmus status_t 534167f43a2SStephan Aßmus MouseDevice::_GetTouchpadSettingsPath(BPath& path) 535167f43a2SStephan Aßmus { 536167f43a2SStephan Aßmus status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); 537167f43a2SStephan Aßmus if (status < B_OK) 538167f43a2SStephan Aßmus return status; 539167f43a2SStephan Aßmus return path.Append(TOUCHPAD_SETTINGS_FILE); 540167f43a2SStephan Aßmus } 541167f43a2SStephan Aßmus 542167f43a2SStephan Aßmus 543167f43a2SStephan Aßmus status_t 544167f43a2SStephan Aßmus MouseDevice::_ReadTouchpadSettingsMsg(BMessage* message) 545167f43a2SStephan Aßmus { 546167f43a2SStephan Aßmus message->FindBool("scroll_twofinger", 547167f43a2SStephan Aßmus &(fTouchpadSettings.scroll_twofinger)); 548167f43a2SStephan Aßmus message->FindBool("scroll_multifinger", 549167f43a2SStephan Aßmus &(fTouchpadSettings.scroll_multifinger)); 550167f43a2SStephan Aßmus message->FindFloat("scroll_rightrange", 551167f43a2SStephan Aßmus &(fTouchpadSettings.scroll_rightrange)); 552167f43a2SStephan Aßmus message->FindFloat("scroll_bottomrange", 553167f43a2SStephan Aßmus &(fTouchpadSettings.scroll_bottomrange)); 554167f43a2SStephan Aßmus message->FindInt16("scroll_xstepsize", 555167f43a2SStephan Aßmus (int16*)&(fTouchpadSettings.scroll_xstepsize)); 556167f43a2SStephan Aßmus message->FindInt16("scroll_ystepsize", 557167f43a2SStephan Aßmus (int16*)&(fTouchpadSettings.scroll_ystepsize)); 558167f43a2SStephan Aßmus message->FindInt8("scroll_acceleration", 559167f43a2SStephan Aßmus (int8*)&(fTouchpadSettings.scroll_acceleration)); 560167f43a2SStephan Aßmus message->FindInt8("tapgesture_sensibility", 561167f43a2SStephan Aßmus (int8*)&(fTouchpadSettings.tapgesture_sensibility)); 562167f43a2SStephan Aßmus 563167f43a2SStephan Aßmus return B_OK; 564167f43a2SStephan Aßmus } 565167f43a2SStephan Aßmus 566167f43a2SStephan Aßmus 567167f43a2SStephan Aßmus status_t 568167f43a2SStephan Aßmus MouseDevice::_UpdateTouchpadSettings() 569167f43a2SStephan Aßmus { 570167f43a2SStephan Aßmus if (fIsTouchpad) { 571167f43a2SStephan Aßmus ioctl(fDevice, MS_SET_TOUCHPAD_SETTINGS, &fTouchpadSettings); 572167f43a2SStephan Aßmus return B_OK; 573167f43a2SStephan Aßmus } 574167f43a2SStephan Aßmus return B_ERROR; 575167f43a2SStephan Aßmus } 576167f43a2SStephan Aßmus 577167f43a2SStephan Aßmus 57861604e48SAxel Dörfler BMessage* 57961604e48SAxel Dörfler MouseDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, 58061604e48SAxel Dörfler int32 deltaX, int32 deltaY) const 58161604e48SAxel Dörfler { 58261604e48SAxel Dörfler BMessage* message = new BMessage(what); 58361604e48SAxel Dörfler if (message == NULL) 58461604e48SAxel Dörfler return NULL; 58561604e48SAxel Dörfler 58661604e48SAxel Dörfler if (message->AddInt64("when", when) < B_OK 58761604e48SAxel Dörfler || message->AddInt32("buttons", buttons) < B_OK 58861604e48SAxel Dörfler || message->AddInt32("x", deltaX) < B_OK 58961604e48SAxel Dörfler || message->AddInt32("y", deltaY) < B_OK) { 59061604e48SAxel Dörfler delete message; 59161604e48SAxel Dörfler return NULL; 59261604e48SAxel Dörfler } 59361604e48SAxel Dörfler 59461604e48SAxel Dörfler return message; 59561604e48SAxel Dörfler } 59661604e48SAxel Dörfler 59761604e48SAxel Dörfler 59861604e48SAxel Dörfler void 59961604e48SAxel Dörfler MouseDevice::_ComputeAcceleration(const mouse_movement& movements, 6006e094221SStephan Aßmus int32& _deltaX, int32& _deltaY, float& historyDeltaX, 6016e094221SStephan Aßmus float& historyDeltaY) const 60261604e48SAxel Dörfler { 60342b505fbSAxel Dörfler // basic mouse speed 6046e094221SStephan Aßmus float deltaX = (float)movements.xdelta * fSettings.accel.speed / 65536.0 6056e094221SStephan Aßmus + historyDeltaX; 6066e094221SStephan Aßmus float deltaY = (float)movements.ydelta * fSettings.accel.speed / 65536.0 6076e094221SStephan Aßmus + historyDeltaY; 60842b505fbSAxel Dörfler 60942b505fbSAxel Dörfler // acceleration 61042b505fbSAxel Dörfler double acceleration = 1; 61142b505fbSAxel Dörfler if (fSettings.accel.accel_factor) { 612fafab827SAxel Dörfler acceleration = 1 + sqrt(deltaX * deltaX + deltaY * deltaY) 61374ef1621SAxel Dörfler * fSettings.accel.accel_factor / 524288.0; 61442b505fbSAxel Dörfler } 61542b505fbSAxel Dörfler 6166e094221SStephan Aßmus deltaX *= acceleration; 6176e094221SStephan Aßmus deltaY *= acceleration; 61842b505fbSAxel Dörfler 6196e094221SStephan Aßmus if (deltaX >= 0) 6206e094221SStephan Aßmus _deltaX = (int32)floorf(deltaX); 621fafab827SAxel Dörfler else 6226e094221SStephan Aßmus _deltaX = (int32)ceilf(deltaX); 6236e094221SStephan Aßmus 6246e094221SStephan Aßmus if (deltaY >= 0) 6256e094221SStephan Aßmus _deltaY = (int32)floorf(deltaY); 6266e094221SStephan Aßmus else 6276e094221SStephan Aßmus _deltaY = (int32)ceilf(deltaY); 6286e094221SStephan Aßmus 6296e094221SStephan Aßmus historyDeltaX = deltaX - _deltaX; 6306e094221SStephan Aßmus historyDeltaY = deltaY - _deltaY; 63161604e48SAxel Dörfler } 63261604e48SAxel Dörfler 63333efb919SStefano Ceccherini 63423b47e0bSJérôme Duval uint32 63561604e48SAxel Dörfler MouseDevice::_RemapButtons(uint32 buttons) const 63623b47e0bSJérôme Duval { 63761604e48SAxel Dörfler if (fDeviceRemapsButtons) 63823b47e0bSJérôme Duval return buttons; 63923b47e0bSJérôme Duval 64061604e48SAxel Dörfler uint32 newButtons = 0; 64123b47e0bSJérôme Duval for (int32 i = 0; buttons; i++) { 64223b47e0bSJérôme Duval if (buttons & 0x1) { 64321631085SStephan Aßmus #if defined(HAIKU_TARGET_PLATFORM_HAIKU) || defined(HAIKU_TARGET_PLATFORM_DANO) 64461604e48SAxel Dörfler newButtons |= fSettings.map.button[i]; 64523b47e0bSJérôme Duval #else 64623b47e0bSJérôme Duval if (i == 0) 64761604e48SAxel Dörfler newButtons |= fSettings.map.left; 64823b47e0bSJérôme Duval if (i == 1) 64961604e48SAxel Dörfler newButtons |= fSettings.map.right; 65023b47e0bSJérôme Duval if (i == 2) 65161604e48SAxel Dörfler newButtons |= fSettings.map.middle; 65223b47e0bSJérôme Duval #endif 65323b47e0bSJérôme Duval } 65423b47e0bSJérôme Duval buttons >>= 1; 65523b47e0bSJérôme Duval } 65623b47e0bSJérôme Duval 65761604e48SAxel Dörfler return newButtons; 65823b47e0bSJérôme Duval } 65923b47e0bSJérôme Duval 66023b47e0bSJérôme Duval 66161604e48SAxel Dörfler // #pragma mark - 66261604e48SAxel Dörfler 66361604e48SAxel Dörfler 66461604e48SAxel Dörfler MouseInputDevice::MouseInputDevice() 665b6a7b204SAxel Dörfler : 6665125eae2SStephan Aßmus fDevices(2, true), 6675125eae2SStephan Aßmus fDeviceListLock("MouseInputDevice list") 66861604e48SAxel Dörfler { 669e01a0431SStephan Aßmus MID_CALLED(); 67061604e48SAxel Dörfler 671c5555ad3SStephan Aßmus StartMonitoringDevice(kMouseDevicesDirectory); 672167f43a2SStephan Aßmus StartMonitoringDevice(kTouchpadDevicesDirectory); 6739dd2d40eSStephan Aßmus _RecursiveScan(kMouseDevicesDirectory); 674167f43a2SStephan Aßmus _RecursiveScan(kTouchpadDevicesDirectory); 67561604e48SAxel Dörfler } 67661604e48SAxel Dörfler 67761604e48SAxel Dörfler 67861604e48SAxel Dörfler MouseInputDevice::~MouseInputDevice() 67961604e48SAxel Dörfler { 680e01a0431SStephan Aßmus MID_CALLED(); 681e01a0431SStephan Aßmus 682167f43a2SStephan Aßmus StopMonitoringDevice(kTouchpadDevicesDirectory); 683b6a7b204SAxel Dörfler StopMonitoringDevice(kMouseDevicesDirectory); 684e01a0431SStephan Aßmus fDevices.MakeEmpty(); 68561604e48SAxel Dörfler } 68661604e48SAxel Dörfler 68761604e48SAxel Dörfler 68861604e48SAxel Dörfler status_t 68961604e48SAxel Dörfler MouseInputDevice::InitCheck() 69061604e48SAxel Dörfler { 691e01a0431SStephan Aßmus MID_CALLED(); 692e01a0431SStephan Aßmus 693d246d9beSStefano Ceccherini return BInputServerDevice::InitCheck(); 69461604e48SAxel Dörfler } 69561604e48SAxel Dörfler 69661604e48SAxel Dörfler 69761604e48SAxel Dörfler status_t 69861604e48SAxel Dörfler MouseInputDevice::Start(const char* name, void* cookie) 69961604e48SAxel Dörfler { 700e01a0431SStephan Aßmus MID_CALLED(); 701e01a0431SStephan Aßmus 70261604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 70361604e48SAxel Dörfler 70461604e48SAxel Dörfler return device->Start(); 70561604e48SAxel Dörfler } 70661604e48SAxel Dörfler 70761604e48SAxel Dörfler 70861604e48SAxel Dörfler status_t 70961604e48SAxel Dörfler MouseInputDevice::Stop(const char* name, void* cookie) 71061604e48SAxel Dörfler { 711e01a0431SStephan Aßmus TRACE("%s(%s)\n", __PRETTY_FUNCTION__, name); 71261604e48SAxel Dörfler 713e01a0431SStephan Aßmus MouseDevice* device = (MouseDevice*)cookie; 71461604e48SAxel Dörfler device->Stop(); 715e01a0431SStephan Aßmus 71661604e48SAxel Dörfler return B_OK; 71761604e48SAxel Dörfler } 71861604e48SAxel Dörfler 71961604e48SAxel Dörfler 72061604e48SAxel Dörfler status_t 72161604e48SAxel Dörfler MouseInputDevice::Control(const char* name, void* cookie, 72261604e48SAxel Dörfler uint32 command, BMessage* message) 72361604e48SAxel Dörfler { 724e01a0431SStephan Aßmus TRACE("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command); 725e01a0431SStephan Aßmus 72661604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 72761604e48SAxel Dörfler 72861604e48SAxel Dörfler if (command == B_NODE_MONITOR) 72961604e48SAxel Dörfler return _HandleMonitor(message); 73061604e48SAxel Dörfler 731167f43a2SStephan Aßmus if (command == MS_SET_TOUCHPAD_SETTINGS) 732167f43a2SStephan Aßmus return device->UpdateTouchpadSettings(message); 733167f43a2SStephan Aßmus 73461604e48SAxel Dörfler if (command >= B_MOUSE_TYPE_CHANGED 73561604e48SAxel Dörfler && command <= B_MOUSE_ACCELERATION_CHANGED) 73661604e48SAxel Dörfler return device->UpdateSettings(); 73761604e48SAxel Dörfler 73861604e48SAxel Dörfler return B_BAD_VALUE; 73961604e48SAxel Dörfler } 74061604e48SAxel Dörfler 74161604e48SAxel Dörfler 74261604e48SAxel Dörfler status_t 74361604e48SAxel Dörfler MouseInputDevice::_HandleMonitor(BMessage* message) 74461604e48SAxel Dörfler { 745e01a0431SStephan Aßmus MID_CALLED(); 74661604e48SAxel Dörfler 747b6a7b204SAxel Dörfler const char* path; 74861604e48SAxel Dörfler int32 opcode; 749b6a7b204SAxel Dörfler if (message->FindInt32("opcode", &opcode) != B_OK 750c5555ad3SStephan Aßmus || (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED) 751b6a7b204SAxel Dörfler || message->FindString("path", &path) != B_OK) 75261604e48SAxel Dörfler return B_BAD_VALUE; 75361604e48SAxel Dörfler 75461604e48SAxel Dörfler if (opcode == B_ENTRY_CREATED) 755b6a7b204SAxel Dörfler return _AddDevice(path); 75661604e48SAxel Dörfler 757c5555ad3SStephan Aßmus #if 0 758b6a7b204SAxel Dörfler return _RemoveDevice(path); 759c5555ad3SStephan Aßmus #else 760c5555ad3SStephan Aßmus // Don't handle B_ENTRY_REMOVED, let the control thread take care of it. 761c5555ad3SStephan Aßmus return B_OK; 762c5555ad3SStephan Aßmus #endif 76361604e48SAxel Dörfler } 76461604e48SAxel Dörfler 76561604e48SAxel Dörfler 76661604e48SAxel Dörfler void 76761604e48SAxel Dörfler MouseInputDevice::_RecursiveScan(const char* directory) 76861604e48SAxel Dörfler { 769e01a0431SStephan Aßmus MID_CALLED(); 77061604e48SAxel Dörfler 77161604e48SAxel Dörfler BEntry entry; 77261604e48SAxel Dörfler BDirectory dir(directory); 77361604e48SAxel Dörfler while (dir.GetNextEntry(&entry) == B_OK) { 77461604e48SAxel Dörfler BPath path; 77561604e48SAxel Dörfler entry.GetPath(&path); 77661604e48SAxel Dörfler 77761604e48SAxel Dörfler if (!strcmp(path.Leaf(), "serial")) { 77861604e48SAxel Dörfler // skip serial 77961604e48SAxel Dörfler continue; 78061604e48SAxel Dörfler } 78161604e48SAxel Dörfler 78261604e48SAxel Dörfler if (entry.IsDirectory()) 78361604e48SAxel Dörfler _RecursiveScan(path.Path()); 78461604e48SAxel Dörfler else 78561604e48SAxel Dörfler _AddDevice(path.Path()); 78661604e48SAxel Dörfler } 78761604e48SAxel Dörfler } 78861604e48SAxel Dörfler 789e01a0431SStephan Aßmus 790e01a0431SStephan Aßmus MouseDevice* 7915125eae2SStephan Aßmus MouseInputDevice::_FindDevice(const char* path) const 792e01a0431SStephan Aßmus { 793e01a0431SStephan Aßmus MID_CALLED(); 794e01a0431SStephan Aßmus 795e01a0431SStephan Aßmus for (int32 i = fDevices.CountItems() - 1; i >= 0; i--) { 796e01a0431SStephan Aßmus MouseDevice* device = fDevices.ItemAt(i); 797e01a0431SStephan Aßmus if (strcmp(device->Path(), path) == 0) 798e01a0431SStephan Aßmus return device; 799e01a0431SStephan Aßmus } 800e01a0431SStephan Aßmus 801e01a0431SStephan Aßmus return NULL; 802e01a0431SStephan Aßmus } 803e01a0431SStephan Aßmus 804e01a0431SStephan Aßmus 805e01a0431SStephan Aßmus status_t 806e01a0431SStephan Aßmus MouseInputDevice::_AddDevice(const char* path) 807e01a0431SStephan Aßmus { 808e01a0431SStephan Aßmus MID_CALLED(); 809e01a0431SStephan Aßmus 8105125eae2SStephan Aßmus BAutolock _(fDeviceListLock); 8115125eae2SStephan Aßmus 812e01a0431SStephan Aßmus _RemoveDevice(path); 813e01a0431SStephan Aßmus 814e01a0431SStephan Aßmus MouseDevice* device = new(std::nothrow) MouseDevice(*this, path); 815e01a0431SStephan Aßmus if (!device) { 816e01a0431SStephan Aßmus TRACE("No memory\n"); 817e01a0431SStephan Aßmus return B_NO_MEMORY; 818e01a0431SStephan Aßmus } 819e01a0431SStephan Aßmus 820e01a0431SStephan Aßmus if (!fDevices.AddItem(device)) { 821e01a0431SStephan Aßmus TRACE("No memory in list\n"); 822e01a0431SStephan Aßmus delete device; 823e01a0431SStephan Aßmus return B_NO_MEMORY; 824e01a0431SStephan Aßmus } 825e01a0431SStephan Aßmus 826e01a0431SStephan Aßmus input_device_ref* devices[2]; 827e01a0431SStephan Aßmus devices[0] = device->DeviceRef(); 828e01a0431SStephan Aßmus devices[1] = NULL; 829e01a0431SStephan Aßmus 830e01a0431SStephan Aßmus TRACE("adding path: %s, name: %s\n", path, devices[0]->name); 831e01a0431SStephan Aßmus 832e01a0431SStephan Aßmus return RegisterDevices(devices); 833e01a0431SStephan Aßmus } 834e01a0431SStephan Aßmus 835e01a0431SStephan Aßmus 836e01a0431SStephan Aßmus status_t 837e01a0431SStephan Aßmus MouseInputDevice::_RemoveDevice(const char* path) 838e01a0431SStephan Aßmus { 839e01a0431SStephan Aßmus MID_CALLED(); 840e01a0431SStephan Aßmus 8415125eae2SStephan Aßmus BAutolock _(fDeviceListLock); 8425125eae2SStephan Aßmus 843e01a0431SStephan Aßmus MouseDevice* device = _FindDevice(path); 844e01a0431SStephan Aßmus if (device == NULL) { 845e01a0431SStephan Aßmus TRACE("%s not found\n", path); 846e01a0431SStephan Aßmus return B_ENTRY_NOT_FOUND; 847e01a0431SStephan Aßmus } 848e01a0431SStephan Aßmus 849e01a0431SStephan Aßmus input_device_ref* devices[2]; 850e01a0431SStephan Aßmus devices[0] = device->DeviceRef(); 851e01a0431SStephan Aßmus devices[1] = NULL; 852e01a0431SStephan Aßmus 853e01a0431SStephan Aßmus TRACE("removing path: %s, name: %s\n", path, devices[0]->name); 854e01a0431SStephan Aßmus 855e01a0431SStephan Aßmus UnregisterDevices(devices); 856e01a0431SStephan Aßmus 857e01a0431SStephan Aßmus fDevices.RemoveItem(device); 858e01a0431SStephan Aßmus 859e01a0431SStephan Aßmus return B_OK; 860e01a0431SStephan Aßmus } 861e01a0431SStephan Aßmus 862e01a0431SStephan Aßmus 863e01a0431SStephan Aßmus 864