123b47e0bSJérôme Duval /* 2fdad31e6SMichael Lotz * Copyright 2004-2011, Haiku. 323b47e0bSJérôme Duval * Distributed under the terms of the MIT License. 423b47e0bSJérôme Duval * 523b47e0bSJérôme Duval * Authors: 6d246d9beSStefano Ceccherini * Stefano Ceccherini (stefano.ceccherini@gmail.com) 7d246d9beSStefano Ceccherini * Jérôme Duval 8d246d9beSStefano Ceccherini * Axel Dörfler, axeld@pinc-software.de 9167f43a2SStephan Aßmus * Clemens Zeidler, haiku@clemens-zeidler.de 10239fd643SStephan Aßmus * Stephan Aßmus, superstippi@gmx.de 1123b47e0bSJérôme Duval */ 1233efb919SStefano Ceccherini 1333efb919SStefano Ceccherini 1461d7deeeSJérôme Duval #include "MouseInputDevice.h" 15b6a7b204SAxel Dörfler 16b6a7b204SAxel Dörfler #include <errno.h> 17b6a7b204SAxel Dörfler #include <new> 18b6a7b204SAxel Dörfler #include <stdio.h> 19b6a7b204SAxel Dörfler #include <stdlib.h> 20b6a7b204SAxel Dörfler #include <unistd.h> 2161d7deeeSJérôme Duval 225125eae2SStephan Aßmus #include <Autolock.h> 23c2fbfb71SJérôme Duval #include <Debug.h> 2433efb919SStefano Ceccherini #include <Directory.h> 2533efb919SStefano Ceccherini #include <Entry.h> 26167f43a2SStephan Aßmus #include <File.h> 27167f43a2SStephan Aßmus #include <FindDirectory.h> 2833efb919SStefano Ceccherini #include <NodeMonitor.h> 2933efb919SStefano Ceccherini #include <Path.h> 3033efb919SStefano Ceccherini #include <String.h> 3161604e48SAxel Dörfler #include <View.h> 3261604e48SAxel Dörfler 332c494653SAxel Dörfler #include <kb_mouse_settings.h> 342c494653SAxel Dörfler #include <keyboard_mouse_driver.h> 352c494653SAxel Dörfler #include <touchpad_settings.h> 3633efb919SStefano Ceccherini 375e596efeSAugustin Cavalier #include "movement_maker.h" 385e596efeSAugustin Cavalier 39b6a7b204SAxel Dörfler 40e01a0431SStephan Aßmus #undef TRACE 41b6a7b204SAxel Dörfler //#define TRACE_MOUSE_DEVICE 42b6a7b204SAxel Dörfler #ifdef TRACE_MOUSE_DEVICE 43e01a0431SStephan Aßmus 44e01a0431SStephan Aßmus class FunctionTracer { 45e01a0431SStephan Aßmus public: 46e01a0431SStephan Aßmus FunctionTracer(const void* pointer, const char* className, 47e01a0431SStephan Aßmus const char* functionName, 48e01a0431SStephan Aßmus int32& depth) 49e01a0431SStephan Aßmus : fFunctionName(), 50e01a0431SStephan Aßmus fPrepend(), 51e01a0431SStephan Aßmus fFunctionDepth(depth), 52e01a0431SStephan Aßmus fPointer(pointer) 53e01a0431SStephan Aßmus { 54e01a0431SStephan Aßmus fFunctionDepth++; 55e01a0431SStephan Aßmus fPrepend.Append(' ', fFunctionDepth * 2); 56e01a0431SStephan Aßmus fFunctionName << className << "::" << functionName << "()"; 57e01a0431SStephan Aßmus 58e01a0431SStephan Aßmus debug_printf("%p -> %s%s {\n", fPointer, fPrepend.String(), 59e01a0431SStephan Aßmus fFunctionName.String()); 60e01a0431SStephan Aßmus } 61e01a0431SStephan Aßmus 62e01a0431SStephan Aßmus ~FunctionTracer() 63e01a0431SStephan Aßmus { 64e01a0431SStephan Aßmus debug_printf("%p -> %s}\n", fPointer, fPrepend.String()); 65e01a0431SStephan Aßmus fFunctionDepth--; 66e01a0431SStephan Aßmus } 67e01a0431SStephan Aßmus 68e01a0431SStephan Aßmus private: 69e01a0431SStephan Aßmus BString fFunctionName; 70e01a0431SStephan Aßmus BString fPrepend; 71e01a0431SStephan Aßmus int32& fFunctionDepth; 72e01a0431SStephan Aßmus const void* fPointer; 73e01a0431SStephan Aßmus }; 74e01a0431SStephan Aßmus 75e01a0431SStephan Aßmus 76e01a0431SStephan Aßmus static int32 sFunctionDepth = -1; 77e01a0431SStephan Aßmus # define MD_CALLED(x...) FunctionTracer _ft(this, "MouseDevice", \ 78e01a0431SStephan Aßmus __FUNCTION__, sFunctionDepth) 79e01a0431SStephan Aßmus # define MID_CALLED(x...) FunctionTracer _ft(this, "MouseInputDevice", \ 80e01a0431SStephan Aßmus __FUNCTION__, sFunctionDepth) 81e02ed691SRene Gollent # define TRACE(x...) do { BString _to; \ 82e01a0431SStephan Aßmus _to.Append(' ', (sFunctionDepth + 1) * 2); \ 83e01a0431SStephan Aßmus debug_printf("%p -> %s", this, _to.String()); \ 84e02ed691SRene Gollent debug_printf(x); } while (0) 85e01a0431SStephan Aßmus # define LOG_EVENT(text...) do {} while (0) 865125eae2SStephan Aßmus # define LOG_ERR(text...) TRACE(text) 873aa69c78SStefano Ceccherini #else 88e01a0431SStephan Aßmus # define TRACE(x...) do {} while (0) 89e01a0431SStephan Aßmus # define MD_CALLED(x...) TRACE(x) 90e01a0431SStephan Aßmus # define MID_CALLED(x...) TRACE(x) 916e094221SStephan Aßmus # define LOG_ERR(x...) debug_printf(x) 926e094221SStephan Aßmus # define LOG_EVENT(x...) TRACE(x) 933aa69c78SStefano Ceccherini #endif 943aa69c78SStefano Ceccherini 95e01a0431SStephan Aßmus 9633efb919SStefano Ceccherini const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4; 9733efb919SStefano Ceccherini const static char* kMouseDevicesDirectory = "/dev/input/mouse"; 98167f43a2SStephan Aßmus const static char* kTouchpadDevicesDirectory = "/dev/input/touchpad"; 9933efb919SStefano Ceccherini 10033efb919SStefano Ceccherini 10161604e48SAxel Dörfler class MouseDevice { 10261604e48SAxel Dörfler public: 1035125eae2SStephan Aßmus MouseDevice(MouseInputDevice& target, 1045125eae2SStephan Aßmus const char* path); 10561604e48SAxel Dörfler ~MouseDevice(); 10633efb919SStefano Ceccherini 10761604e48SAxel Dörfler status_t Start(); 10861604e48SAxel Dörfler void Stop(); 10961604e48SAxel Dörfler 11061604e48SAxel Dörfler status_t UpdateSettings(); 111167f43a2SStephan Aßmus status_t UpdateTouchpadSettings(const BMessage* message); 11261604e48SAxel Dörfler 11361604e48SAxel Dörfler const char* Path() const { return fPath.String(); } 11461604e48SAxel Dörfler input_device_ref* DeviceRef() { return &fDeviceRef; } 11561604e48SAxel Dörfler 11661604e48SAxel Dörfler private: 1175125eae2SStephan Aßmus char* _BuildShortName() const; 11861604e48SAxel Dörfler 1195125eae2SStephan Aßmus static status_t _ControlThreadEntry(void* arg); 1205125eae2SStephan Aßmus void _ControlThread(); 1215125eae2SStephan Aßmus void _ControlThreadCleanup(); 1225125eae2SStephan Aßmus void _UpdateSettings(); 1235125eae2SStephan Aßmus 124167f43a2SStephan Aßmus status_t _GetTouchpadSettingsPath(BPath& path); 1255e596efeSAugustin Cavalier status_t _UpdateTouchpadSettings(BMessage* message); 126167f43a2SStephan Aßmus 1275125eae2SStephan Aßmus BMessage* _BuildMouseMessage(uint32 what, 1285125eae2SStephan Aßmus uint64 when, uint32 buttons, 12961604e48SAxel Dörfler int32 deltaX, int32 deltaY) const; 1305125eae2SStephan Aßmus void _ComputeAcceleration( 1315125eae2SStephan Aßmus const mouse_movement& movements, 1326e094221SStephan Aßmus int32& deltaX, int32& deltaY, 1336e094221SStephan Aßmus float& historyDeltaX, 1346e094221SStephan Aßmus float& historyDeltaY) const; 13561604e48SAxel Dörfler uint32 _RemapButtons(uint32 buttons) const; 13661604e48SAxel Dörfler 13761604e48SAxel Dörfler private: 138c5555ad3SStephan Aßmus MouseInputDevice& fTarget; 13961604e48SAxel Dörfler BString fPath; 14061604e48SAxel Dörfler int fDevice; 14161604e48SAxel Dörfler 14261604e48SAxel Dörfler input_device_ref fDeviceRef; 14361604e48SAxel Dörfler mouse_settings fSettings; 14461604e48SAxel Dörfler bool fDeviceRemapsButtons; 14561604e48SAxel Dörfler 14661604e48SAxel Dörfler thread_id fThread; 14761604e48SAxel Dörfler volatile bool fActive; 1485125eae2SStephan Aßmus volatile bool fUpdateSettings; 149167f43a2SStephan Aßmus 150167f43a2SStephan Aßmus bool fIsTouchpad; 1515e596efeSAugustin Cavalier TouchpadMovement fTouchpadMovementMaker; 152167f43a2SStephan Aßmus BMessage* fTouchpadSettingsMessage; 153167f43a2SStephan Aßmus BLocker fTouchpadSettingsLock; 1540dbc4befSStefano Ceccherini }; 1550dbc4befSStefano Ceccherini 1560dbc4befSStefano Ceccherini 15761604e48SAxel Dörfler extern "C" BInputServerDevice* 15861d7deeeSJérôme Duval instantiate_input_device() 15961d7deeeSJérôme Duval { 160d246d9beSStefano Ceccherini return new(std::nothrow) MouseInputDevice(); 16161d7deeeSJérôme Duval } 16261d7deeeSJérôme Duval 16361d7deeeSJérôme Duval 16461604e48SAxel Dörfler // #pragma mark - 16561604e48SAxel Dörfler 16661604e48SAxel Dörfler 167c5555ad3SStephan Aßmus MouseDevice::MouseDevice(MouseInputDevice& target, const char* driverPath) 16861604e48SAxel Dörfler : 16961604e48SAxel Dörfler fTarget(target), 170c5555ad3SStephan Aßmus fPath(driverPath), 17161604e48SAxel Dörfler fDevice(-1), 172e01a0431SStephan Aßmus fDeviceRemapsButtons(false), 17361604e48SAxel Dörfler fThread(-1), 1745125eae2SStephan Aßmus fActive(false), 175167f43a2SStephan Aßmus fUpdateSettings(false), 176167f43a2SStephan Aßmus fIsTouchpad(false), 177167f43a2SStephan Aßmus fTouchpadSettingsMessage(NULL), 178167f43a2SStephan Aßmus fTouchpadSettingsLock("Touchpad settings lock") 17961d7deeeSJérôme Duval { 180e01a0431SStephan Aßmus MD_CALLED(); 181e01a0431SStephan Aßmus 18261604e48SAxel Dörfler fDeviceRef.name = _BuildShortName(); 18361604e48SAxel Dörfler fDeviceRef.type = B_POINTING_DEVICE; 18461604e48SAxel Dörfler fDeviceRef.cookie = this; 18561604e48SAxel Dörfler 18661604e48SAxel Dörfler #ifdef HAIKU_TARGET_PLATFORM_HAIKU 1875bbf7f1bSAdrien Destugues for (int i = 0; i < B_MAX_MOUSE_BUTTONS; i++) 1885bbf7f1bSAdrien Destugues fSettings.map.button[i] = B_MOUSE_BUTTON(i + 1); 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; 221fdad31e6SMichael 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)); 231fdad31e6SMichael 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 252fdad31e6SMichael 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); 293fdad31e6SMichael Lotz if (fTouchpadSettingsMessage == NULL) 294fdad31e6SMichael 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 { 303ffd6c2f4SAdrien Destugues // TODO It would be simpler and better to use B_GET_DEVICE_NAME, but... 304ffd6c2f4SAdrien Destugues // - This is currently called before the device is open 305ffd6c2f4SAdrien Destugues // - We need to implement that in our input drivers first 3065125eae2SStephan Aßmus BString string(fPath); 307ffd6c2f4SAdrien Destugues BString deviceName; 3085125eae2SStephan Aßmus BString name; 3095125eae2SStephan Aßmus 3105125eae2SStephan Aßmus int32 slash = string.FindLast("/"); 311ffd6c2f4SAdrien Destugues string.CopyInto(deviceName, slash + 1, string.Length() - slash); 312ffd6c2f4SAdrien Destugues // FIXME the device name may be more than just a number (for example 313ffd6c2f4SAdrien Destugues // ibm_trackpoint_0) 314ffd6c2f4SAdrien Destugues int32 index = atoi(deviceName.String()) + 1; 3155125eae2SStephan Aßmus 3165125eae2SStephan Aßmus int32 previousSlash = string.FindLast("/", slash); 3175125eae2SStephan Aßmus string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1); 3185125eae2SStephan Aßmus 3195125eae2SStephan Aßmus if (name == "ps2") 3205125eae2SStephan Aßmus name = "PS/2"; 321155b8260SPhilippe Houdoin 322ffd6c2f4SAdrien Destugues if (name.Length() <= 4) 323155b8260SPhilippe Houdoin name.ToUpper(); 3245125eae2SStephan Aßmus else 3255125eae2SStephan Aßmus name.Capitalize(); 3265125eae2SStephan Aßmus 327f32bcfd5SAdrien Destugues // Check the whole string for "touchpad" because it's a different directory 328f32bcfd5SAdrien Destugues // FIXME use MS_IS_TOUCHPAD ioctl instead (or fIsTouchpad which caches its 329f32bcfd5SAdrien Destugues // result) but this can only be done after the control thread is running 330f32bcfd5SAdrien Destugues if (string.FindFirst("touchpad") >= 0) { 331167f43a2SStephan Aßmus name << " Touchpad "; 332ffd6c2f4SAdrien Destugues } else if (deviceName.FindFirst("trackpoint") >= 0) { 333ffd6c2f4SAdrien Destugues // That's always PS/2, so don't keep the bus name 334ffd6c2f4SAdrien Destugues name = "Trackpoint "; 335167f43a2SStephan Aßmus } else { 336ffd6c2f4SAdrien Destugues if (deviceName.FindFirst("intelli") >= 0) 337cc442411SStephan Aßmus name.Prepend("Extended "); 338cc442411SStephan Aßmus 339167f43a2SStephan Aßmus name << " Mouse "; 340167f43a2SStephan Aßmus } 341167f43a2SStephan Aßmus name << index; 3425125eae2SStephan Aßmus 3435125eae2SStephan Aßmus return strdup(name.String()); 3445125eae2SStephan Aßmus } 3455125eae2SStephan Aßmus 3465125eae2SStephan Aßmus 3475125eae2SStephan Aßmus // #pragma mark - control thread 3485125eae2SStephan Aßmus 3495125eae2SStephan Aßmus 3505125eae2SStephan Aßmus status_t 3515125eae2SStephan Aßmus MouseDevice::_ControlThreadEntry(void* arg) 3525125eae2SStephan Aßmus { 3535125eae2SStephan Aßmus MouseDevice* device = (MouseDevice*)arg; 3545125eae2SStephan Aßmus device->_ControlThread(); 3555125eae2SStephan Aßmus return B_OK; 35642b505fbSAxel Dörfler } 35742b505fbSAxel Dörfler 35842b505fbSAxel Dörfler 35961604e48SAxel Dörfler void 3605125eae2SStephan Aßmus MouseDevice::_ControlThread() 36161604e48SAxel Dörfler { 362167f43a2SStephan Aßmus MD_CALLED(); 363167f43a2SStephan Aßmus 3645125eae2SStephan Aßmus if (fDevice < 0) { 3655125eae2SStephan Aßmus _ControlThreadCleanup(); 3665125eae2SStephan Aßmus // TOAST! 3675125eae2SStephan Aßmus return; 3685125eae2SStephan Aßmus } 3695125eae2SStephan Aßmus 370167f43a2SStephan Aßmus // touchpad settings 3715e596efeSAugustin Cavalier touchpad_specs touchpadSpecs; 3725e596efeSAugustin Cavalier if (ioctl(fDevice, MS_IS_TOUCHPAD, &touchpadSpecs, sizeof(touchpadSpecs)) == B_OK) { 373167f43a2SStephan Aßmus TRACE("is touchpad %s\n", fPath.String()); 374167f43a2SStephan Aßmus fIsTouchpad = true; 375167f43a2SStephan Aßmus 3765e596efeSAugustin Cavalier touchpad_settings settings; 3775e596efeSAugustin Cavalier settings = kDefaultTouchpadSettings; 378167f43a2SStephan Aßmus 379167f43a2SStephan Aßmus BPath path; 380167f43a2SStephan Aßmus status_t status = _GetTouchpadSettingsPath(path); 381167f43a2SStephan Aßmus BFile settingsFile(path.Path(), B_READ_ONLY); 382167f43a2SStephan Aßmus if (status == B_OK && settingsFile.InitCheck() == B_OK) { 3835e596efeSAugustin Cavalier if (settingsFile.Read(&settings, sizeof(touchpad_settings)) 384167f43a2SStephan Aßmus != sizeof(touchpad_settings)) { 385167f43a2SStephan Aßmus TRACE("failed to load settings\n"); 386167f43a2SStephan Aßmus } 387167f43a2SStephan Aßmus } 3885e596efeSAugustin Cavalier 3895e596efeSAugustin Cavalier fTouchpadMovementMaker.SetSpecs(touchpadSpecs); 3905e596efeSAugustin Cavalier fTouchpadMovementMaker.SetSettings(settings); 391167f43a2SStephan Aßmus } 392167f43a2SStephan Aßmus 3935125eae2SStephan Aßmus _UpdateSettings(); 3945125eae2SStephan Aßmus 39561604e48SAxel Dörfler uint32 lastButtons = 0; 3966e094221SStephan Aßmus float historyDeltaX = 0.0; 3976e094221SStephan Aßmus float historyDeltaY = 0.0; 39861604e48SAxel Dörfler 3997d1d7033SStephan Aßmus static const bigtime_t kTransferDelay = 1000000 / 125; 4007d1d7033SStephan Aßmus // 125 transfers per second should be more than enough 4015994d47aSStephan Aßmus #define USE_REGULAR_INTERVAL 1 4027d1d7033SStephan Aßmus #if USE_REGULAR_INTERVAL 4037d1d7033SStephan Aßmus bigtime_t nextTransferTime = system_time() + kTransferDelay; 4047d1d7033SStephan Aßmus #endif 4057d1d7033SStephan Aßmus 4065e596efeSAugustin Cavalier // touchpads only 4075e596efeSAugustin Cavalier touchpad_movement lastTouchpadMovement; 4085e596efeSAugustin Cavalier bigtime_t touchpadEventTimeout = B_INFINITE_TIMEOUT; 4095e596efeSAugustin Cavalier 41061604e48SAxel Dörfler while (fActive) { 41161604e48SAxel Dörfler mouse_movement movements; 4127d1d7033SStephan Aßmus 4137d1d7033SStephan Aßmus #if USE_REGULAR_INTERVAL 4147d1d7033SStephan Aßmus snooze_until(nextTransferTime, B_SYSTEM_TIMEBASE); 4157d1d7033SStephan Aßmus nextTransferTime += kTransferDelay; 4167d1d7033SStephan Aßmus #endif 4177d1d7033SStephan Aßmus 4185e596efeSAugustin Cavalier if (!fIsTouchpad) { 419308e87fcSRene Gollent if (ioctl(fDevice, MS_READ, &movements, sizeof(movements)) != B_OK) { 420308e87fcSRene Gollent LOG_ERR("Mouse device exiting, %s\n", strerror(errno)); 4215125eae2SStephan Aßmus _ControlThreadCleanup(); 422c5555ad3SStephan Aßmus // TOAST! 42361604e48SAxel Dörfler return; 424c5555ad3SStephan Aßmus } 4255e596efeSAugustin Cavalier } else { 4265e596efeSAugustin Cavalier touchpad_read read; 4275e596efeSAugustin Cavalier read.timeout = touchpadEventTimeout; 4285e596efeSAugustin Cavalier 4295e596efeSAugustin Cavalier status_t status = ioctl(fDevice, MS_READ_TOUCHPAD, &read, sizeof(read)); 430ba0a86caSAugustin Cavalier if (status < 0) 431ba0a86caSAugustin Cavalier status = errno; 4325e596efeSAugustin Cavalier if (status != B_OK && status != B_TIMED_OUT) { 433ba0a86caSAugustin Cavalier LOG_ERR("Mouse (touchpad) device exiting, %s\n", strerror(errno)); 4345e596efeSAugustin Cavalier _ControlThreadCleanup(); 4355e596efeSAugustin Cavalier // TOAST! 4365e596efeSAugustin Cavalier return; 437ba0a86caSAugustin Cavalier } else if (status == B_TIMED_OUT) { 4385e596efeSAugustin Cavalier read.event = MS_READ_TOUCHPAD; 4395e596efeSAugustin Cavalier read.u.touchpad = lastTouchpadMovement; 4405e596efeSAugustin Cavalier } 4415e596efeSAugustin Cavalier 4425e596efeSAugustin Cavalier if (read.event == MS_READ_TOUCHPAD) { 4435e596efeSAugustin Cavalier lastTouchpadMovement = read.u.touchpad; 4445e596efeSAugustin Cavalier status = fTouchpadMovementMaker.EventToMovement(&read.u.touchpad, 4455e596efeSAugustin Cavalier &movements, touchpadEventTimeout); 4465e596efeSAugustin Cavalier } else if (read.event == MS_READ) { 4475e596efeSAugustin Cavalier movements = read.u.mouse; 4485e596efeSAugustin Cavalier touchpadEventTimeout = -1; 4495e596efeSAugustin Cavalier } 4505e596efeSAugustin Cavalier 4515e596efeSAugustin Cavalier if (status != B_OK) 4525e596efeSAugustin Cavalier continue; 4535e596efeSAugustin Cavalier } 45461604e48SAxel Dörfler 4555125eae2SStephan Aßmus // take care of updating the settings first, if necessary 4565125eae2SStephan Aßmus if (fUpdateSettings) { 4575125eae2SStephan Aßmus fUpdateSettings = false; 458167f43a2SStephan Aßmus if (fIsTouchpad) { 459167f43a2SStephan Aßmus BAutolock _(fTouchpadSettingsLock); 4603bf47305SAxel Dörfler if (fTouchpadSettingsMessage != NULL) { 4615e596efeSAugustin Cavalier _UpdateTouchpadSettings(fTouchpadSettingsMessage); 462167f43a2SStephan Aßmus delete fTouchpadSettingsMessage; 463167f43a2SStephan Aßmus fTouchpadSettingsMessage = NULL; 464167f43a2SStephan Aßmus } else 465167f43a2SStephan Aßmus _UpdateSettings(); 466167f43a2SStephan Aßmus } else 467167f43a2SStephan Aßmus _UpdateSettings(); 4685125eae2SStephan Aßmus } 4695125eae2SStephan Aßmus 47061604e48SAxel Dörfler uint32 buttons = lastButtons ^ movements.buttons; 47161604e48SAxel Dörfler 47261604e48SAxel Dörfler uint32 remappedButtons = _RemapButtons(movements.buttons); 47361604e48SAxel Dörfler int32 deltaX, deltaY; 4746e094221SStephan Aßmus _ComputeAcceleration(movements, deltaX, deltaY, historyDeltaX, 4756e094221SStephan Aßmus historyDeltaY); 47661604e48SAxel Dörfler 4776e094221SStephan Aßmus LOG_EVENT("%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld, " 4786e094221SStephan Aßmus "wheel_x:%ld, wheel_y:%ld\n", 4796e094221SStephan Aßmus fDeviceRef.name, movements.buttons, 4806e094221SStephan Aßmus movements.xdelta, movements.ydelta, movements.clicks, 4816e094221SStephan Aßmus movements.wheel_xdelta, movements.wheel_ydelta); 4826e094221SStephan Aßmus LOG_EVENT("%s: x: %ld, y: %ld (%.4f, %.4f)\n", fDeviceRef.name, 4836e094221SStephan Aßmus deltaX, deltaY, historyDeltaX, historyDeltaY); 48461604e48SAxel Dörfler 48561604e48SAxel Dörfler // Send single messages for each event 48661604e48SAxel Dörfler 48761604e48SAxel Dörfler if (buttons != 0) { 48861604e48SAxel Dörfler bool pressedButton = (buttons & movements.buttons) > 0; 48961604e48SAxel Dörfler BMessage* message = _BuildMouseMessage( 49061604e48SAxel Dörfler pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP, 49161604e48SAxel Dörfler movements.timestamp, remappedButtons, deltaX, deltaY); 49261604e48SAxel Dörfler if (message != NULL) { 49361604e48SAxel Dörfler if (pressedButton) { 49461604e48SAxel Dörfler message->AddInt32("clicks", movements.clicks); 495e01a0431SStephan Aßmus LOG_EVENT("B_MOUSE_DOWN\n"); 49661604e48SAxel Dörfler } else 497e01a0431SStephan Aßmus LOG_EVENT("B_MOUSE_UP\n"); 49861604e48SAxel Dörfler 49961604e48SAxel Dörfler fTarget.EnqueueMessage(message); 50061604e48SAxel Dörfler lastButtons = movements.buttons; 50161604e48SAxel Dörfler } 50261604e48SAxel Dörfler } 50361604e48SAxel Dörfler 50445f11ce8SStephan Aßmus if (movements.xdelta != 0 || movements.ydelta != 0) { 50545f11ce8SStephan Aßmus BMessage* message = _BuildMouseMessage(B_MOUSE_MOVED, 50645f11ce8SStephan Aßmus movements.timestamp, remappedButtons, deltaX, deltaY); 50745f11ce8SStephan Aßmus if (message != NULL) 50845f11ce8SStephan Aßmus fTarget.EnqueueMessage(message); 50945f11ce8SStephan Aßmus } 51045f11ce8SStephan Aßmus 511fdad31e6SMichael Lotz if (movements.wheel_ydelta != 0 || movements.wheel_xdelta != 0) { 512c5555ad3SStephan Aßmus BMessage* message = new BMessage(B_MOUSE_WHEEL_CHANGED); 51361604e48SAxel Dörfler if (message == NULL) 51461604e48SAxel Dörfler continue; 51561604e48SAxel Dörfler 51661604e48SAxel Dörfler if (message->AddInt64("when", movements.timestamp) == B_OK 5173bf47305SAxel Dörfler && message->AddFloat("be:wheel_delta_x", 5183bf47305SAxel Dörfler movements.wheel_xdelta) == B_OK 5193bf47305SAxel Dörfler && message->AddFloat("be:wheel_delta_y", 5203bf47305SAxel Dörfler movements.wheel_ydelta) == B_OK) 52161604e48SAxel Dörfler fTarget.EnqueueMessage(message); 52261604e48SAxel Dörfler else 52361604e48SAxel Dörfler delete message; 52461604e48SAxel Dörfler } 5257d1d7033SStephan Aßmus 5267d1d7033SStephan Aßmus #if !USE_REGULAR_INTERVAL 5277d1d7033SStephan Aßmus snooze(kTransferDelay); 5287d1d7033SStephan Aßmus #endif 52961604e48SAxel Dörfler } 53061604e48SAxel Dörfler } 53161604e48SAxel Dörfler 53261604e48SAxel Dörfler 5335125eae2SStephan Aßmus void 5345125eae2SStephan Aßmus MouseDevice::_ControlThreadCleanup() 53561604e48SAxel Dörfler { 5365125eae2SStephan Aßmus // NOTE: Only executed when the control thread detected an error 5375125eae2SStephan Aßmus // and from within the control thread! 5385125eae2SStephan Aßmus 5395125eae2SStephan Aßmus if (fActive) { 5405125eae2SStephan Aßmus fThread = -1; 5415125eae2SStephan Aßmus fTarget._RemoveDevice(fPath.String()); 5425125eae2SStephan Aßmus } else { 5435125eae2SStephan Aßmus // In case active is already false, another thread 5445125eae2SStephan Aßmus // waits for this thread to quit, and may already hold 545fdad31e6SMichael Lotz // locks that _RemoveDevice() wants to acquire. In other 5465125eae2SStephan Aßmus // words, the device is already being removed, so we simply 5475125eae2SStephan Aßmus // quit here. 5485125eae2SStephan Aßmus } 5495125eae2SStephan Aßmus } 5505125eae2SStephan Aßmus 5515125eae2SStephan Aßmus 5525125eae2SStephan Aßmus void 5535125eae2SStephan Aßmus MouseDevice::_UpdateSettings() 5545125eae2SStephan Aßmus { 5555125eae2SStephan Aßmus MD_CALLED(); 5565125eae2SStephan Aßmus // retrieve current values 5575125eae2SStephan Aßmus 558*caed67a8SMáximo Castañeda if (get_mouse_map(fDeviceRef.name, &fSettings.map) != B_OK) 5595125eae2SStephan Aßmus LOG_ERR("error when get_mouse_map\n"); 560*caed67a8SMáximo Castañeda else 561*caed67a8SMáximo Castañeda fDeviceRemapsButtons = ioctl(fDevice, MS_SET_MAP, &fSettings.map) == B_OK; 5625125eae2SStephan Aßmus 563*caed67a8SMáximo Castañeda if (get_click_speed(fDeviceRef.name, &fSettings.click_speed) == B_OK) { 5645e596efeSAugustin Cavalier if (fIsTouchpad) 5655e596efeSAugustin Cavalier fTouchpadMovementMaker.click_speed = fSettings.click_speed; 5665125eae2SStephan Aßmus ioctl(fDevice, MS_SET_CLICKSPEED, &fSettings.click_speed); 5675e596efeSAugustin Cavalier } else 5685e596efeSAugustin Cavalier LOG_ERR("error when get_click_speed\n"); 5695125eae2SStephan Aßmus 57068d1b97eSAugustin Cavalier if (get_mouse_speed(fDeviceRef.name, &fSettings.accel.speed) != B_OK) 5715125eae2SStephan Aßmus LOG_ERR("error when get_mouse_speed\n"); 5725125eae2SStephan Aßmus else { 57368d1b97eSAugustin Cavalier if (get_mouse_acceleration(fDeviceRef.name, &fSettings.accel.accel_factor) != B_OK) 5745125eae2SStephan Aßmus LOG_ERR("error when get_mouse_acceleration\n"); 5755125eae2SStephan Aßmus else { 5765125eae2SStephan Aßmus mouse_accel accel; 5775125eae2SStephan Aßmus ioctl(fDevice, MS_GET_ACCEL, &accel); 5785125eae2SStephan Aßmus accel.speed = fSettings.accel.speed; 5795125eae2SStephan Aßmus accel.accel_factor = fSettings.accel.accel_factor; 5805125eae2SStephan Aßmus ioctl(fDevice, MS_SET_ACCEL, &fSettings.accel); 5815125eae2SStephan Aßmus } 5825125eae2SStephan Aßmus } 5835125eae2SStephan Aßmus 58468d1b97eSAugustin Cavalier if (get_mouse_type(fDeviceRef.name, &fSettings.type) != B_OK) 5855125eae2SStephan Aßmus LOG_ERR("error when get_mouse_type\n"); 5865125eae2SStephan Aßmus else 5875125eae2SStephan Aßmus ioctl(fDevice, MS_SET_TYPE, &fSettings.type); 58861604e48SAxel Dörfler } 58961604e48SAxel Dörfler 59061604e48SAxel Dörfler 591167f43a2SStephan Aßmus status_t 592167f43a2SStephan Aßmus MouseDevice::_GetTouchpadSettingsPath(BPath& path) 593167f43a2SStephan Aßmus { 594167f43a2SStephan Aßmus status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); 595167f43a2SStephan Aßmus if (status < B_OK) 596167f43a2SStephan Aßmus return status; 597167f43a2SStephan Aßmus return path.Append(TOUCHPAD_SETTINGS_FILE); 598167f43a2SStephan Aßmus } 599167f43a2SStephan Aßmus 600167f43a2SStephan Aßmus 601167f43a2SStephan Aßmus status_t 6025e596efeSAugustin Cavalier MouseDevice::_UpdateTouchpadSettings(BMessage* message) 603167f43a2SStephan Aßmus { 6045e596efeSAugustin Cavalier touchpad_settings settings; 6055e596efeSAugustin Cavalier message->FindBool("scroll_twofinger", &settings.scroll_twofinger); 606fc548b41SAxel Dörfler message->FindBool("scroll_twofinger_horizontal", 6075e596efeSAugustin Cavalier &settings.scroll_twofinger_horizontal); 608167f43a2SStephan Aßmus message->FindFloat("scroll_rightrange", 6095e596efeSAugustin Cavalier &settings.scroll_rightrange); 610167f43a2SStephan Aßmus message->FindFloat("scroll_bottomrange", 6115e596efeSAugustin Cavalier &settings.scroll_bottomrange); 6123bf47305SAxel Dörfler 613167f43a2SStephan Aßmus message->FindInt16("scroll_xstepsize", 6145e596efeSAugustin Cavalier (int16*)&settings.scroll_xstepsize); 615167f43a2SStephan Aßmus message->FindInt16("scroll_ystepsize", 6165e596efeSAugustin Cavalier (int16*)&settings.scroll_ystepsize); 617167f43a2SStephan Aßmus message->FindInt8("scroll_acceleration", 6185e596efeSAugustin Cavalier (int8*)&settings.scroll_acceleration); 619167f43a2SStephan Aßmus message->FindInt8("tapgesture_sensibility", 6205e596efeSAugustin Cavalier (int8*)&settings.tapgesture_sensibility); 6215e596efeSAugustin Cavalier 6225e596efeSAugustin Cavalier if (fIsTouchpad) 6235e596efeSAugustin Cavalier fTouchpadMovementMaker.SetSettings(settings); 624167f43a2SStephan Aßmus 625167f43a2SStephan Aßmus return B_OK; 626167f43a2SStephan Aßmus } 627167f43a2SStephan Aßmus 628167f43a2SStephan Aßmus 62961604e48SAxel Dörfler BMessage* 63061604e48SAxel Dörfler MouseDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, 63161604e48SAxel Dörfler int32 deltaX, int32 deltaY) const 63261604e48SAxel Dörfler { 63361604e48SAxel Dörfler BMessage* message = new BMessage(what); 63461604e48SAxel Dörfler if (message == NULL) 63561604e48SAxel Dörfler return NULL; 63661604e48SAxel Dörfler 63761604e48SAxel Dörfler if (message->AddInt64("when", when) < B_OK 63861604e48SAxel Dörfler || message->AddInt32("buttons", buttons) < B_OK 63961604e48SAxel Dörfler || message->AddInt32("x", deltaX) < B_OK 64061604e48SAxel Dörfler || message->AddInt32("y", deltaY) < B_OK) { 64161604e48SAxel Dörfler delete message; 64261604e48SAxel Dörfler return NULL; 64361604e48SAxel Dörfler } 64461604e48SAxel Dörfler 64561604e48SAxel Dörfler return message; 64661604e48SAxel Dörfler } 64761604e48SAxel Dörfler 64861604e48SAxel Dörfler 64961604e48SAxel Dörfler void 65061604e48SAxel Dörfler MouseDevice::_ComputeAcceleration(const mouse_movement& movements, 6516e094221SStephan Aßmus int32& _deltaX, int32& _deltaY, float& historyDeltaX, 6526e094221SStephan Aßmus float& historyDeltaY) const 65361604e48SAxel Dörfler { 65442b505fbSAxel Dörfler // basic mouse speed 6556e094221SStephan Aßmus float deltaX = (float)movements.xdelta * fSettings.accel.speed / 65536.0 6566e094221SStephan Aßmus + historyDeltaX; 6576e094221SStephan Aßmus float deltaY = (float)movements.ydelta * fSettings.accel.speed / 65536.0 6586e094221SStephan Aßmus + historyDeltaY; 65942b505fbSAxel Dörfler 66042b505fbSAxel Dörfler // acceleration 66142b505fbSAxel Dörfler double acceleration = 1; 66242b505fbSAxel Dörfler if (fSettings.accel.accel_factor) { 663fafab827SAxel Dörfler acceleration = 1 + sqrt(deltaX * deltaX + deltaY * deltaY) 66474ef1621SAxel Dörfler * fSettings.accel.accel_factor / 524288.0; 66542b505fbSAxel Dörfler } 66642b505fbSAxel Dörfler 6676e094221SStephan Aßmus deltaX *= acceleration; 6686e094221SStephan Aßmus deltaY *= acceleration; 66942b505fbSAxel Dörfler 6706e094221SStephan Aßmus if (deltaX >= 0) 6716e094221SStephan Aßmus _deltaX = (int32)floorf(deltaX); 672fafab827SAxel Dörfler else 6736e094221SStephan Aßmus _deltaX = (int32)ceilf(deltaX); 6746e094221SStephan Aßmus 6756e094221SStephan Aßmus if (deltaY >= 0) 6766e094221SStephan Aßmus _deltaY = (int32)floorf(deltaY); 6776e094221SStephan Aßmus else 6786e094221SStephan Aßmus _deltaY = (int32)ceilf(deltaY); 6796e094221SStephan Aßmus 6806e094221SStephan Aßmus historyDeltaX = deltaX - _deltaX; 6816e094221SStephan Aßmus historyDeltaY = deltaY - _deltaY; 68261604e48SAxel Dörfler } 68361604e48SAxel Dörfler 68433efb919SStefano Ceccherini 68523b47e0bSJérôme Duval uint32 68661604e48SAxel Dörfler MouseDevice::_RemapButtons(uint32 buttons) const 68723b47e0bSJérôme Duval { 68861604e48SAxel Dörfler if (fDeviceRemapsButtons) 68923b47e0bSJérôme Duval return buttons; 69023b47e0bSJérôme Duval 69161604e48SAxel Dörfler uint32 newButtons = 0; 69223b47e0bSJérôme Duval for (int32 i = 0; buttons; i++) { 69323b47e0bSJérôme Duval if (buttons & 0x1) { 69421631085SStephan Aßmus #if defined(HAIKU_TARGET_PLATFORM_HAIKU) || defined(HAIKU_TARGET_PLATFORM_DANO) 69561604e48SAxel Dörfler newButtons |= fSettings.map.button[i]; 69623b47e0bSJérôme Duval #else 69723b47e0bSJérôme Duval if (i == 0) 69861604e48SAxel Dörfler newButtons |= fSettings.map.left; 69923b47e0bSJérôme Duval if (i == 1) 70061604e48SAxel Dörfler newButtons |= fSettings.map.right; 70123b47e0bSJérôme Duval if (i == 2) 70261604e48SAxel Dörfler newButtons |= fSettings.map.middle; 70323b47e0bSJérôme Duval #endif 70423b47e0bSJérôme Duval } 70523b47e0bSJérôme Duval buttons >>= 1; 70623b47e0bSJérôme Duval } 70723b47e0bSJérôme Duval 70861604e48SAxel Dörfler return newButtons; 70923b47e0bSJérôme Duval } 71023b47e0bSJérôme Duval 71123b47e0bSJérôme Duval 71261604e48SAxel Dörfler // #pragma mark - 71361604e48SAxel Dörfler 71461604e48SAxel Dörfler 71561604e48SAxel Dörfler MouseInputDevice::MouseInputDevice() 716b6a7b204SAxel Dörfler : 7175125eae2SStephan Aßmus fDevices(2, true), 7185125eae2SStephan Aßmus fDeviceListLock("MouseInputDevice list") 71961604e48SAxel Dörfler { 720e01a0431SStephan Aßmus MID_CALLED(); 72161604e48SAxel Dörfler 722c5555ad3SStephan Aßmus StartMonitoringDevice(kMouseDevicesDirectory); 723167f43a2SStephan Aßmus StartMonitoringDevice(kTouchpadDevicesDirectory); 7249dd2d40eSStephan Aßmus _RecursiveScan(kMouseDevicesDirectory); 725167f43a2SStephan Aßmus _RecursiveScan(kTouchpadDevicesDirectory); 72661604e48SAxel Dörfler } 72761604e48SAxel Dörfler 72861604e48SAxel Dörfler 72961604e48SAxel Dörfler MouseInputDevice::~MouseInputDevice() 73061604e48SAxel Dörfler { 731e01a0431SStephan Aßmus MID_CALLED(); 732e01a0431SStephan Aßmus 733167f43a2SStephan Aßmus StopMonitoringDevice(kTouchpadDevicesDirectory); 734b6a7b204SAxel Dörfler StopMonitoringDevice(kMouseDevicesDirectory); 735e01a0431SStephan Aßmus fDevices.MakeEmpty(); 73661604e48SAxel Dörfler } 73761604e48SAxel Dörfler 73861604e48SAxel Dörfler 73961604e48SAxel Dörfler status_t 74061604e48SAxel Dörfler MouseInputDevice::InitCheck() 74161604e48SAxel Dörfler { 742e01a0431SStephan Aßmus MID_CALLED(); 743e01a0431SStephan Aßmus 744d246d9beSStefano Ceccherini return BInputServerDevice::InitCheck(); 74561604e48SAxel Dörfler } 74661604e48SAxel Dörfler 74761604e48SAxel Dörfler 74861604e48SAxel Dörfler status_t 74961604e48SAxel Dörfler MouseInputDevice::Start(const char* name, void* cookie) 75061604e48SAxel Dörfler { 751e01a0431SStephan Aßmus MID_CALLED(); 752e01a0431SStephan Aßmus 75361604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 75461604e48SAxel Dörfler 75561604e48SAxel Dörfler return device->Start(); 75661604e48SAxel Dörfler } 75761604e48SAxel Dörfler 75861604e48SAxel Dörfler 75961604e48SAxel Dörfler status_t 76061604e48SAxel Dörfler MouseInputDevice::Stop(const char* name, void* cookie) 76161604e48SAxel Dörfler { 762e01a0431SStephan Aßmus TRACE("%s(%s)\n", __PRETTY_FUNCTION__, name); 76361604e48SAxel Dörfler 764e01a0431SStephan Aßmus MouseDevice* device = (MouseDevice*)cookie; 76561604e48SAxel Dörfler device->Stop(); 766e01a0431SStephan Aßmus 76761604e48SAxel Dörfler return B_OK; 76861604e48SAxel Dörfler } 76961604e48SAxel Dörfler 77061604e48SAxel Dörfler 77161604e48SAxel Dörfler status_t 77261604e48SAxel Dörfler MouseInputDevice::Control(const char* name, void* cookie, 77361604e48SAxel Dörfler uint32 command, BMessage* message) 77461604e48SAxel Dörfler { 775e01a0431SStephan Aßmus TRACE("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command); 776e01a0431SStephan Aßmus 77761604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 77861604e48SAxel Dörfler 77961604e48SAxel Dörfler if (command == B_NODE_MONITOR) 78061604e48SAxel Dörfler return _HandleMonitor(message); 78161604e48SAxel Dörfler 7825e596efeSAugustin Cavalier if (command == B_SET_TOUCHPAD_SETTINGS) 783167f43a2SStephan Aßmus return device->UpdateTouchpadSettings(message); 784167f43a2SStephan Aßmus 78561604e48SAxel Dörfler if (command >= B_MOUSE_TYPE_CHANGED 78661604e48SAxel Dörfler && command <= B_MOUSE_ACCELERATION_CHANGED) 78761604e48SAxel Dörfler return device->UpdateSettings(); 78861604e48SAxel Dörfler 78961604e48SAxel Dörfler return B_BAD_VALUE; 79061604e48SAxel Dörfler } 79161604e48SAxel Dörfler 79261604e48SAxel Dörfler 79361604e48SAxel Dörfler status_t 79461604e48SAxel Dörfler MouseInputDevice::_HandleMonitor(BMessage* message) 79561604e48SAxel Dörfler { 796e01a0431SStephan Aßmus MID_CALLED(); 79761604e48SAxel Dörfler 798b6a7b204SAxel Dörfler const char* path; 79961604e48SAxel Dörfler int32 opcode; 800b6a7b204SAxel Dörfler if (message->FindInt32("opcode", &opcode) != B_OK 801c5555ad3SStephan Aßmus || (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED) 802b6a7b204SAxel Dörfler || message->FindString("path", &path) != B_OK) 80361604e48SAxel Dörfler return B_BAD_VALUE; 80461604e48SAxel Dörfler 80561604e48SAxel Dörfler if (opcode == B_ENTRY_CREATED) 806b6a7b204SAxel Dörfler return _AddDevice(path); 80761604e48SAxel Dörfler 808c5555ad3SStephan Aßmus #if 0 809b6a7b204SAxel Dörfler return _RemoveDevice(path); 810c5555ad3SStephan Aßmus #else 811c5555ad3SStephan Aßmus // Don't handle B_ENTRY_REMOVED, let the control thread take care of it. 812c5555ad3SStephan Aßmus return B_OK; 813c5555ad3SStephan Aßmus #endif 81461604e48SAxel Dörfler } 81561604e48SAxel Dörfler 81661604e48SAxel Dörfler 81761604e48SAxel Dörfler void 81861604e48SAxel Dörfler MouseInputDevice::_RecursiveScan(const char* directory) 81961604e48SAxel Dörfler { 820e01a0431SStephan Aßmus MID_CALLED(); 82161604e48SAxel Dörfler 82261604e48SAxel Dörfler BEntry entry; 82361604e48SAxel Dörfler BDirectory dir(directory); 82461604e48SAxel Dörfler while (dir.GetNextEntry(&entry) == B_OK) { 82561604e48SAxel Dörfler BPath path; 82661604e48SAxel Dörfler entry.GetPath(&path); 82761604e48SAxel Dörfler 82861604e48SAxel Dörfler if (!strcmp(path.Leaf(), "serial")) { 82961604e48SAxel Dörfler // skip serial 83061604e48SAxel Dörfler continue; 83161604e48SAxel Dörfler } 83261604e48SAxel Dörfler 83361604e48SAxel Dörfler if (entry.IsDirectory()) 83461604e48SAxel Dörfler _RecursiveScan(path.Path()); 83561604e48SAxel Dörfler else 83661604e48SAxel Dörfler _AddDevice(path.Path()); 83761604e48SAxel Dörfler } 83861604e48SAxel Dörfler } 83961604e48SAxel Dörfler 840e01a0431SStephan Aßmus 841e01a0431SStephan Aßmus MouseDevice* 8425125eae2SStephan Aßmus MouseInputDevice::_FindDevice(const char* path) const 843e01a0431SStephan Aßmus { 844e01a0431SStephan Aßmus MID_CALLED(); 845e01a0431SStephan Aßmus 846e01a0431SStephan Aßmus for (int32 i = fDevices.CountItems() - 1; i >= 0; i--) { 847e01a0431SStephan Aßmus MouseDevice* device = fDevices.ItemAt(i); 848e01a0431SStephan Aßmus if (strcmp(device->Path(), path) == 0) 849e01a0431SStephan Aßmus return device; 850e01a0431SStephan Aßmus } 851e01a0431SStephan Aßmus 852e01a0431SStephan Aßmus return NULL; 853e01a0431SStephan Aßmus } 854e01a0431SStephan Aßmus 855e01a0431SStephan Aßmus 856e01a0431SStephan Aßmus status_t 857e01a0431SStephan Aßmus MouseInputDevice::_AddDevice(const char* path) 858e01a0431SStephan Aßmus { 859e01a0431SStephan Aßmus MID_CALLED(); 860e01a0431SStephan Aßmus 8615125eae2SStephan Aßmus BAutolock _(fDeviceListLock); 8625125eae2SStephan Aßmus 863e01a0431SStephan Aßmus _RemoveDevice(path); 864e01a0431SStephan Aßmus 865e01a0431SStephan Aßmus MouseDevice* device = new(std::nothrow) MouseDevice(*this, path); 866fdad31e6SMichael Lotz if (device == NULL) { 867e01a0431SStephan Aßmus TRACE("No memory\n"); 868e01a0431SStephan Aßmus return B_NO_MEMORY; 869e01a0431SStephan Aßmus } 870e01a0431SStephan Aßmus 871e01a0431SStephan Aßmus if (!fDevices.AddItem(device)) { 872e01a0431SStephan Aßmus TRACE("No memory in list\n"); 873e01a0431SStephan Aßmus delete device; 874e01a0431SStephan Aßmus return B_NO_MEMORY; 875e01a0431SStephan Aßmus } 876e01a0431SStephan Aßmus 877e01a0431SStephan Aßmus input_device_ref* devices[2]; 878e01a0431SStephan Aßmus devices[0] = device->DeviceRef(); 879e01a0431SStephan Aßmus devices[1] = NULL; 880e01a0431SStephan Aßmus 881e01a0431SStephan Aßmus TRACE("adding path: %s, name: %s\n", path, devices[0]->name); 882e01a0431SStephan Aßmus 883e01a0431SStephan Aßmus return RegisterDevices(devices); 884e01a0431SStephan Aßmus } 885e01a0431SStephan Aßmus 886e01a0431SStephan Aßmus 887e01a0431SStephan Aßmus status_t 888e01a0431SStephan Aßmus MouseInputDevice::_RemoveDevice(const char* path) 889e01a0431SStephan Aßmus { 890e01a0431SStephan Aßmus MID_CALLED(); 891e01a0431SStephan Aßmus 8925125eae2SStephan Aßmus BAutolock _(fDeviceListLock); 8935125eae2SStephan Aßmus 894e01a0431SStephan Aßmus MouseDevice* device = _FindDevice(path); 895e01a0431SStephan Aßmus if (device == NULL) { 896e01a0431SStephan Aßmus TRACE("%s not found\n", path); 897e01a0431SStephan Aßmus return B_ENTRY_NOT_FOUND; 898e01a0431SStephan Aßmus } 899e01a0431SStephan Aßmus 900e01a0431SStephan Aßmus input_device_ref* devices[2]; 901e01a0431SStephan Aßmus devices[0] = device->DeviceRef(); 902e01a0431SStephan Aßmus devices[1] = NULL; 903e01a0431SStephan Aßmus 904e01a0431SStephan Aßmus TRACE("removing path: %s, name: %s\n", path, devices[0]->name); 905e01a0431SStephan Aßmus 906e01a0431SStephan Aßmus UnregisterDevices(devices); 907e01a0431SStephan Aßmus 908e01a0431SStephan Aßmus fDevices.RemoveItem(device); 909e01a0431SStephan Aßmus 910e01a0431SStephan Aßmus return B_OK; 911e01a0431SStephan Aßmus } 912