123b47e0bSJérôme Duval /* 2d246d9beSStefano Ceccherini * Copyright 2004-2007, 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 923b47e0bSJérôme Duval */ 1033efb919SStefano Ceccherini 1133efb919SStefano Ceccherini 1261d7deeeSJérôme Duval #include "MouseInputDevice.h" 13b6a7b204SAxel Dörfler 14b6a7b204SAxel Dörfler #include <errno.h> 15b6a7b204SAxel Dörfler #include <new> 16b6a7b204SAxel Dörfler #include <stdio.h> 17b6a7b204SAxel Dörfler #include <stdlib.h> 18b6a7b204SAxel Dörfler #include <unistd.h> 1961d7deeeSJérôme Duval 20c2fbfb71SJérôme Duval #include <Debug.h> 2133efb919SStefano Ceccherini #include <Directory.h> 2233efb919SStefano Ceccherini #include <Entry.h> 2333efb919SStefano Ceccherini #include <NodeMonitor.h> 2433efb919SStefano Ceccherini #include <Path.h> 2533efb919SStefano Ceccherini #include <String.h> 2661604e48SAxel Dörfler #include <View.h> 2761604e48SAxel Dörfler 28b6a7b204SAxel Dörfler #include "kb_mouse_settings.h" 29b6a7b204SAxel Dörfler #include "kb_mouse_driver.h" 3033efb919SStefano Ceccherini 31b6a7b204SAxel Dörfler 32b6a7b204SAxel Dörfler //#define TRACE_MOUSE_DEVICE 33b6a7b204SAxel Dörfler #ifdef TRACE_MOUSE_DEVICE 34b6a7b204SAxel Dörfler # define LOG(text...) debug_printf(text) 3561604e48SAxel Dörfler # define LOG_ERR(text...) LOG(text) 363aa69c78SStefano Ceccherini #else 37b6a7b204SAxel Dörfler # define LOG(text...) do {} while (0) 38b6a7b204SAxel Dörfler # define LOG_ERR(text...) debug_printf(text) 393aa69c78SStefano Ceccherini #endif 403aa69c78SStefano Ceccherini 41*c5555ad3SStephan Aßmus //#define LOG_DEVICES(text...) debug_printf(text) 42*c5555ad3SStephan Aßmus #define LOG_DEVICES(text...) LOG(text) 43*c5555ad3SStephan Aßmus 44c2fbfb71SJérôme Duval #define CALLED() LOG("%s\n", __PRETTY_FUNCTION__) 4533efb919SStefano Ceccherini 46b6a7b204SAxel Dörfler 47*c5555ad3SStephan Aßmus 4833efb919SStefano Ceccherini const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4; 4933efb919SStefano Ceccherini const static char* kMouseDevicesDirectory = "/dev/input/mouse"; 5033efb919SStefano Ceccherini 5133efb919SStefano Ceccherini 5261604e48SAxel Dörfler class MouseDevice { 5361604e48SAxel Dörfler public: 54*c5555ad3SStephan Aßmus MouseDevice(MouseInputDevice& target, const char* path); 5561604e48SAxel Dörfler ~MouseDevice(); 5633efb919SStefano Ceccherini 5761604e48SAxel Dörfler status_t Start(); 5861604e48SAxel Dörfler void Stop(); 5961604e48SAxel Dörfler 6061604e48SAxel Dörfler status_t UpdateSettings(); 6161604e48SAxel Dörfler 6261604e48SAxel Dörfler const char* Path() const { return fPath.String(); } 6361604e48SAxel Dörfler input_device_ref* DeviceRef() { return &fDeviceRef; } 6461604e48SAxel Dörfler 6561604e48SAxel Dörfler private: 6661604e48SAxel Dörfler void _Run(); 6761604e48SAxel Dörfler static status_t _ThreadFunction(void* arg); 6861604e48SAxel Dörfler 6961604e48SAxel Dörfler BMessage* _BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, 7061604e48SAxel Dörfler int32 deltaX, int32 deltaY) const; 7161604e48SAxel Dörfler void _ComputeAcceleration(const mouse_movement& movements, 7261604e48SAxel Dörfler int32& deltaX, int32& deltaY) const; 7361604e48SAxel Dörfler uint32 _RemapButtons(uint32 buttons) const; 7461604e48SAxel Dörfler 7561604e48SAxel Dörfler char* _BuildShortName() const; 7661604e48SAxel Dörfler 7761604e48SAxel Dörfler private: 78*c5555ad3SStephan Aßmus MouseInputDevice& fTarget; 7961604e48SAxel Dörfler BString fPath; 8061604e48SAxel Dörfler int fDevice; 8161604e48SAxel Dörfler 8261604e48SAxel Dörfler input_device_ref fDeviceRef; 8361604e48SAxel Dörfler mouse_settings fSettings; 8461604e48SAxel Dörfler bool fDeviceRemapsButtons; 8561604e48SAxel Dörfler 8661604e48SAxel Dörfler thread_id fThread; 8761604e48SAxel Dörfler volatile bool fActive; 880dbc4befSStefano Ceccherini }; 890dbc4befSStefano Ceccherini 900dbc4befSStefano Ceccherini 9161604e48SAxel Dörfler extern "C" BInputServerDevice* 9261d7deeeSJérôme Duval instantiate_input_device() 9361d7deeeSJérôme Duval { 94d246d9beSStefano Ceccherini return new(std::nothrow) MouseInputDevice(); 9561d7deeeSJérôme Duval } 9661d7deeeSJérôme Duval 9761d7deeeSJérôme Duval 9861604e48SAxel Dörfler // #pragma mark - 9961604e48SAxel Dörfler 10061604e48SAxel Dörfler 101*c5555ad3SStephan Aßmus MouseDevice::MouseDevice(MouseInputDevice& target, const char* driverPath) 10261604e48SAxel Dörfler : 10361604e48SAxel Dörfler fTarget(target), 104*c5555ad3SStephan Aßmus fPath(driverPath), 10561604e48SAxel Dörfler fDevice(-1), 10661604e48SAxel Dörfler fThread(-1), 10761604e48SAxel Dörfler fActive(false) 10861d7deeeSJérôme Duval { 10961604e48SAxel Dörfler fDeviceRef.name = _BuildShortName(); 11061604e48SAxel Dörfler fDeviceRef.type = B_POINTING_DEVICE; 11161604e48SAxel Dörfler fDeviceRef.cookie = this; 11261604e48SAxel Dörfler 11361604e48SAxel Dörfler #ifdef HAIKU_TARGET_PLATFORM_HAIKU 11461604e48SAxel Dörfler fSettings.map.button[0] = B_PRIMARY_MOUSE_BUTTON; 11561604e48SAxel Dörfler fSettings.map.button[1] = B_SECONDARY_MOUSE_BUTTON; 11661604e48SAxel Dörfler fSettings.map.button[2] = B_TERTIARY_MOUSE_BUTTON; 1173aa69c78SStefano Ceccherini #endif 11833efb919SStefano Ceccherini 11961604e48SAxel Dörfler fDeviceRemapsButtons = false; 12061604e48SAxel Dörfler }; 12161d7deeeSJérôme Duval 12261d7deeeSJérôme Duval 12361604e48SAxel Dörfler MouseDevice::~MouseDevice() 12461d7deeeSJérôme Duval { 12561604e48SAxel Dörfler if (fActive) 12661604e48SAxel Dörfler Stop(); 12761d7deeeSJérôme Duval 12861604e48SAxel Dörfler free(fDeviceRef.name); 12961d7deeeSJérôme Duval } 13061d7deeeSJérôme Duval 13161d7deeeSJérôme Duval 13261d7deeeSJérôme Duval status_t 13361604e48SAxel Dörfler MouseDevice::Start() 13453d77642SJérôme Duval { 13561604e48SAxel Dörfler fDevice = open(fPath.String(), O_RDWR); 13661604e48SAxel Dörfler if (fDevice < 0) 13761604e48SAxel Dörfler return errno; 13833efb919SStefano Ceccherini 13961604e48SAxel Dörfler UpdateSettings(); 14033efb919SStefano Ceccherini 14133efb919SStefano Ceccherini char threadName[B_OS_NAME_LENGTH]; 14261604e48SAxel Dörfler snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", fDeviceRef.name); 14333efb919SStefano Ceccherini 14461604e48SAxel Dörfler fThread = spawn_thread(_ThreadFunction, threadName, 14561604e48SAxel Dörfler kMouseThreadPriority, (void*)this); 1464c0af4a8SStefano Ceccherini 14733efb919SStefano Ceccherini status_t status; 14861604e48SAxel Dörfler if (fThread < B_OK) 14961604e48SAxel Dörfler status = fThread; 15061604e48SAxel Dörfler else { 15161604e48SAxel Dörfler fActive = true; 15261604e48SAxel Dörfler status = resume_thread(fThread); 15361604e48SAxel Dörfler } 15433efb919SStefano Ceccherini 15561604e48SAxel Dörfler if (status < B_OK) { 15661604e48SAxel Dörfler LOG_ERR("%s: can't spawn/resume watching thread: %s\n", 15761604e48SAxel Dörfler fDeviceRef.name, strerror(status)); 15861604e48SAxel Dörfler close(fDevice); 15961604e48SAxel Dörfler return status; 16061604e48SAxel Dörfler } 16161604e48SAxel Dörfler 162c2fbfb71SJérôme Duval return B_OK; 16361d7deeeSJérôme Duval } 16461d7deeeSJérôme Duval 16561d7deeeSJérôme Duval 166c2fbfb71SJérôme Duval void 16761604e48SAxel Dörfler MouseDevice::Stop() 16861604e48SAxel Dörfler { 1691ccc2f2dSJérôme Duval close(fDevice); 1701ccc2f2dSJérôme Duval fDevice = -1; 1711ccc2f2dSJérôme Duval 17261604e48SAxel Dörfler fActive = false; 17361604e48SAxel Dörfler // this will stop the thread as soon as it reads the next packet 17461604e48SAxel Dörfler 17561604e48SAxel Dörfler if (fThread >= B_OK) { 17661604e48SAxel Dörfler // unblock the thread, which might wait on a semaphore. 17761604e48SAxel Dörfler suspend_thread(fThread); 17861604e48SAxel Dörfler resume_thread(fThread); 17961604e48SAxel Dörfler 18061604e48SAxel Dörfler status_t dummy; 18161604e48SAxel Dörfler wait_for_thread(fThread, &dummy); 18261604e48SAxel Dörfler } 18361604e48SAxel Dörfler } 18461604e48SAxel Dörfler 18561604e48SAxel Dörfler 18642b505fbSAxel Dörfler status_t 18742b505fbSAxel Dörfler MouseDevice::UpdateSettings() 18842b505fbSAxel Dörfler { 18942b505fbSAxel Dörfler CALLED(); 19042b505fbSAxel Dörfler 19142b505fbSAxel Dörfler // retrieve current values 19242b505fbSAxel Dörfler 19342b505fbSAxel Dörfler if (get_mouse_map(&fSettings.map) != B_OK) 19442b505fbSAxel Dörfler LOG_ERR("error when get_mouse_map\n"); 19542b505fbSAxel Dörfler else 19642b505fbSAxel Dörfler fDeviceRemapsButtons = ioctl(fDevice, MS_SET_MAP, &fSettings.map) == B_OK; 19742b505fbSAxel Dörfler 19842b505fbSAxel Dörfler if (get_click_speed(&fSettings.click_speed) != B_OK) 19942b505fbSAxel Dörfler LOG_ERR("error when get_click_speed\n"); 20042b505fbSAxel Dörfler else 20142b505fbSAxel Dörfler ioctl(fDevice, MS_SET_CLICKSPEED, &fSettings.click_speed); 20242b505fbSAxel Dörfler 20342b505fbSAxel Dörfler if (get_mouse_speed(&fSettings.accel.speed) != B_OK) 20442b505fbSAxel Dörfler LOG_ERR("error when get_mouse_speed\n"); 20542b505fbSAxel Dörfler else { 20642b505fbSAxel Dörfler if (get_mouse_acceleration(&fSettings.accel.accel_factor) != B_OK) 20742b505fbSAxel Dörfler LOG_ERR("error when get_mouse_acceleration\n"); 20842b505fbSAxel Dörfler else { 20942b505fbSAxel Dörfler mouse_accel accel; 21042b505fbSAxel Dörfler ioctl(fDevice, MS_GET_ACCEL, &accel); 21142b505fbSAxel Dörfler accel.speed = fSettings.accel.speed; 21242b505fbSAxel Dörfler accel.accel_factor = fSettings.accel.accel_factor; 21342b505fbSAxel Dörfler ioctl(fDevice, MS_SET_ACCEL, &fSettings.accel); 21442b505fbSAxel Dörfler } 21542b505fbSAxel Dörfler } 21642b505fbSAxel Dörfler 21742b505fbSAxel Dörfler if (get_mouse_type(&fSettings.type) != B_OK) 21842b505fbSAxel Dörfler LOG_ERR("error when get_mouse_type\n"); 21942b505fbSAxel Dörfler else 22042b505fbSAxel Dörfler ioctl(fDevice, MS_SET_TYPE, &fSettings.type); 22142b505fbSAxel Dörfler 22242b505fbSAxel Dörfler return B_OK; 22342b505fbSAxel Dörfler 22442b505fbSAxel Dörfler } 22542b505fbSAxel Dörfler 22642b505fbSAxel Dörfler 22761604e48SAxel Dörfler void 22861604e48SAxel Dörfler MouseDevice::_Run() 22961604e48SAxel Dörfler { 23061604e48SAxel Dörfler uint32 lastButtons = 0; 23161604e48SAxel Dörfler 23261604e48SAxel Dörfler while (fActive) { 23361604e48SAxel Dörfler mouse_movement movements; 23461604e48SAxel Dörfler memset(&movements, 0, sizeof(movements)); 23561604e48SAxel Dörfler 236*c5555ad3SStephan Aßmus if (ioctl(fDevice, MS_READ, &movements) != B_OK) { 237*c5555ad3SStephan Aßmus fThread = -1; 238*c5555ad3SStephan Aßmus fTarget._RemoveDevice(fPath.String()); 239*c5555ad3SStephan Aßmus // TOAST! 24061604e48SAxel Dörfler return; 241*c5555ad3SStephan Aßmus } 24261604e48SAxel Dörfler 24361604e48SAxel Dörfler uint32 buttons = lastButtons ^ movements.buttons; 24461604e48SAxel Dörfler 24561604e48SAxel Dörfler uint32 remappedButtons = _RemapButtons(movements.buttons); 24661604e48SAxel Dörfler int32 deltaX, deltaY; 24761604e48SAxel Dörfler _ComputeAcceleration(movements, deltaX, deltaY); 24861604e48SAxel Dörfler 24961604e48SAxel Dörfler LOG("%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld, wheel_x:%ld, wheel_y:%ld\n", 2501ccc2f2dSJérôme Duval fDeviceRef.name, movements.buttons, movements.xdelta, movements.ydelta, 25161604e48SAxel Dörfler movements.clicks, movements.wheel_xdelta, movements.wheel_ydelta); 2521ccc2f2dSJérôme Duval LOG("%s: x: %ld, y: %ld\n", fDeviceRef.name, deltaX, deltaY); 25361604e48SAxel Dörfler 25461604e48SAxel Dörfler // Send single messages for each event 25561604e48SAxel Dörfler 25661604e48SAxel Dörfler if (buttons != 0) { 25761604e48SAxel Dörfler bool pressedButton = (buttons & movements.buttons) > 0; 25861604e48SAxel Dörfler BMessage* message = _BuildMouseMessage( 25961604e48SAxel Dörfler pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP, 26061604e48SAxel Dörfler movements.timestamp, remappedButtons, deltaX, deltaY); 26161604e48SAxel Dörfler if (message != NULL) { 26261604e48SAxel Dörfler if (pressedButton) { 26361604e48SAxel Dörfler message->AddInt32("clicks", movements.clicks); 26461604e48SAxel Dörfler LOG("B_MOUSE_DOWN\n"); 26561604e48SAxel Dörfler } else 26661604e48SAxel Dörfler LOG("B_MOUSE_UP\n"); 26761604e48SAxel Dörfler 26861604e48SAxel Dörfler fTarget.EnqueueMessage(message); 26961604e48SAxel Dörfler lastButtons = movements.buttons; 27061604e48SAxel Dörfler } 27161604e48SAxel Dörfler } 27261604e48SAxel Dörfler 27345f11ce8SStephan Aßmus if (movements.xdelta != 0 || movements.ydelta != 0) { 27445f11ce8SStephan Aßmus BMessage* message = _BuildMouseMessage(B_MOUSE_MOVED, 27545f11ce8SStephan Aßmus movements.timestamp, remappedButtons, deltaX, deltaY); 27645f11ce8SStephan Aßmus if (message != NULL) 27745f11ce8SStephan Aßmus fTarget.EnqueueMessage(message); 27845f11ce8SStephan Aßmus } 27945f11ce8SStephan Aßmus 28061604e48SAxel Dörfler if ((movements.wheel_ydelta != 0) || (movements.wheel_xdelta != 0)) { 281*c5555ad3SStephan Aßmus BMessage* message = new BMessage(B_MOUSE_WHEEL_CHANGED); 28261604e48SAxel Dörfler if (message == NULL) 28361604e48SAxel Dörfler continue; 28461604e48SAxel Dörfler 28561604e48SAxel Dörfler if (message->AddInt64("when", movements.timestamp) == B_OK 28661604e48SAxel Dörfler && message->AddFloat("be:wheel_delta_x", movements.wheel_xdelta) == B_OK 28761604e48SAxel Dörfler && message->AddFloat("be:wheel_delta_y", movements.wheel_ydelta) == B_OK) 28861604e48SAxel Dörfler fTarget.EnqueueMessage(message); 28961604e48SAxel Dörfler else 29061604e48SAxel Dörfler delete message; 29161604e48SAxel Dörfler } 29261604e48SAxel Dörfler } 29361604e48SAxel Dörfler } 29461604e48SAxel Dörfler 29561604e48SAxel Dörfler 29661604e48SAxel Dörfler status_t 29761604e48SAxel Dörfler MouseDevice::_ThreadFunction(void* arg) 29861604e48SAxel Dörfler { 29961604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)arg; 30061604e48SAxel Dörfler device->_Run(); 30161604e48SAxel Dörfler return B_OK; 30261604e48SAxel Dörfler } 30361604e48SAxel Dörfler 30461604e48SAxel Dörfler 30561604e48SAxel Dörfler BMessage* 30661604e48SAxel Dörfler MouseDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, 30761604e48SAxel Dörfler int32 deltaX, int32 deltaY) const 30861604e48SAxel Dörfler { 30961604e48SAxel Dörfler BMessage* message = new BMessage(what); 31061604e48SAxel Dörfler if (message == NULL) 31161604e48SAxel Dörfler return NULL; 31261604e48SAxel Dörfler 31361604e48SAxel Dörfler if (message->AddInt64("when", when) < B_OK 31461604e48SAxel Dörfler || message->AddInt32("buttons", buttons) < B_OK 31561604e48SAxel Dörfler || message->AddInt32("x", deltaX) < B_OK 31661604e48SAxel Dörfler || message->AddInt32("y", deltaY) < B_OK) { 31761604e48SAxel Dörfler delete message; 31861604e48SAxel Dörfler return NULL; 31961604e48SAxel Dörfler } 32061604e48SAxel Dörfler 32161604e48SAxel Dörfler return message; 32261604e48SAxel Dörfler } 32361604e48SAxel Dörfler 32461604e48SAxel Dörfler 32561604e48SAxel Dörfler void 32661604e48SAxel Dörfler MouseDevice::_ComputeAcceleration(const mouse_movement& movements, 32761604e48SAxel Dörfler int32& deltaX, int32& deltaY) const 32861604e48SAxel Dörfler { 32942b505fbSAxel Dörfler // basic mouse speed 33042b505fbSAxel Dörfler deltaX = movements.xdelta * fSettings.accel.speed >> 16; 33142b505fbSAxel Dörfler deltaY = movements.ydelta * fSettings.accel.speed >> 16; 33242b505fbSAxel Dörfler 33342b505fbSAxel Dörfler // acceleration 33442b505fbSAxel Dörfler double acceleration = 1; 33542b505fbSAxel Dörfler if (fSettings.accel.accel_factor) { 336fafab827SAxel Dörfler acceleration = 1 + sqrt(deltaX * deltaX + deltaY * deltaY) 33774ef1621SAxel Dörfler * fSettings.accel.accel_factor / 524288.0; 33842b505fbSAxel Dörfler } 33942b505fbSAxel Dörfler 34042b505fbSAxel Dörfler // make sure that we move at least one pixel (if there was a movement) 34142b505fbSAxel Dörfler if (deltaX > 0) 34242b505fbSAxel Dörfler deltaX = (int32)floor(deltaX * acceleration); 343fafab827SAxel Dörfler else 344fafab827SAxel Dörfler deltaX = (int32)ceil(deltaX * acceleration); 34542b505fbSAxel Dörfler 34642b505fbSAxel Dörfler if (deltaY > 0) 34742b505fbSAxel Dörfler deltaY = (int32)floor(deltaY * acceleration); 348fafab827SAxel Dörfler else 349fafab827SAxel Dörfler deltaY = (int32)ceil(deltaY * acceleration); 35061604e48SAxel Dörfler } 35161604e48SAxel Dörfler 35233efb919SStefano Ceccherini 35323b47e0bSJérôme Duval uint32 35461604e48SAxel Dörfler MouseDevice::_RemapButtons(uint32 buttons) const 35523b47e0bSJérôme Duval { 35661604e48SAxel Dörfler if (fDeviceRemapsButtons) 35723b47e0bSJérôme Duval return buttons; 35823b47e0bSJérôme Duval 35961604e48SAxel Dörfler uint32 newButtons = 0; 36023b47e0bSJérôme Duval for (int32 i = 0; buttons; i++) { 36123b47e0bSJérôme Duval if (buttons & 0x1) { 36221631085SStephan Aßmus #if defined(HAIKU_TARGET_PLATFORM_HAIKU) || defined(HAIKU_TARGET_PLATFORM_DANO) 36361604e48SAxel Dörfler newButtons |= fSettings.map.button[i]; 36423b47e0bSJérôme Duval #else 36523b47e0bSJérôme Duval if (i == 0) 36661604e48SAxel Dörfler newButtons |= fSettings.map.left; 36723b47e0bSJérôme Duval if (i == 1) 36861604e48SAxel Dörfler newButtons |= fSettings.map.right; 36923b47e0bSJérôme Duval if (i == 2) 37061604e48SAxel Dörfler newButtons |= fSettings.map.middle; 37123b47e0bSJérôme Duval #endif 37223b47e0bSJérôme Duval } 37323b47e0bSJérôme Duval buttons >>= 1; 37423b47e0bSJérôme Duval } 37523b47e0bSJérôme Duval 37661604e48SAxel Dörfler return newButtons; 37723b47e0bSJérôme Duval } 37823b47e0bSJérôme Duval 37923b47e0bSJérôme Duval 38061604e48SAxel Dörfler char* 38161604e48SAxel Dörfler MouseDevice::_BuildShortName() const 3824c0af4a8SStefano Ceccherini { 38361604e48SAxel Dörfler BString string(fPath); 38433efb919SStefano Ceccherini BString name; 38533efb919SStefano Ceccherini 38633efb919SStefano Ceccherini int32 slash = string.FindLast("/"); 3877dcdcad2SJérôme Duval string.CopyInto(name, slash + 1, string.Length() - slash); 3887dcdcad2SJérôme Duval int32 index = atoi(name.String()) + 1; 38933efb919SStefano Ceccherini 3907dcdcad2SJérôme Duval int32 previousSlash = string.FindLast("/", slash); 3917dcdcad2SJérôme Duval string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1); 392497d01f0SAxel Dörfler 393497d01f0SAxel Dörfler if (name == "ps2") 394497d01f0SAxel Dörfler name = "PS/2"; 395497d01f0SAxel Dörfler else 396497d01f0SAxel Dörfler name.Capitalize(); 397497d01f0SAxel Dörfler 3987dcdcad2SJérôme Duval name << " Mouse " << index; 39933efb919SStefano Ceccherini 40033efb919SStefano Ceccherini return strdup(name.String()); 40133efb919SStefano Ceccherini } 40261604e48SAxel Dörfler 40361604e48SAxel Dörfler 40461604e48SAxel Dörfler // #pragma mark - 40561604e48SAxel Dörfler 40661604e48SAxel Dörfler 40761604e48SAxel Dörfler MouseInputDevice::MouseInputDevice() 408b6a7b204SAxel Dörfler : 409b6a7b204SAxel Dörfler fDevices(2, true) 41061604e48SAxel Dörfler { 41161604e48SAxel Dörfler CALLED(); 41261604e48SAxel Dörfler 41361604e48SAxel Dörfler _RecursiveScan(kMouseDevicesDirectory); 414*c5555ad3SStephan Aßmus StartMonitoringDevice(kMouseDevicesDirectory); 41561604e48SAxel Dörfler } 41661604e48SAxel Dörfler 41761604e48SAxel Dörfler 41861604e48SAxel Dörfler MouseInputDevice::~MouseInputDevice() 41961604e48SAxel Dörfler { 42061604e48SAxel Dörfler CALLED(); 421b6a7b204SAxel Dörfler StopMonitoringDevice(kMouseDevicesDirectory); 42261604e48SAxel Dörfler } 42361604e48SAxel Dörfler 42461604e48SAxel Dörfler 42561604e48SAxel Dörfler status_t 42661604e48SAxel Dörfler MouseInputDevice::InitCheck() 42761604e48SAxel Dörfler { 42861604e48SAxel Dörfler CALLED(); 429d246d9beSStefano Ceccherini return BInputServerDevice::InitCheck(); 43061604e48SAxel Dörfler } 43161604e48SAxel Dörfler 43261604e48SAxel Dörfler 43361604e48SAxel Dörfler status_t 43461604e48SAxel Dörfler MouseInputDevice::Start(const char* name, void* cookie) 43561604e48SAxel Dörfler { 43661604e48SAxel Dörfler LOG("%s(%s)\n", __PRETTY_FUNCTION__, name); 43761604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 43861604e48SAxel Dörfler 43961604e48SAxel Dörfler return device->Start(); 44061604e48SAxel Dörfler } 44161604e48SAxel Dörfler 44261604e48SAxel Dörfler 44361604e48SAxel Dörfler status_t 44461604e48SAxel Dörfler MouseInputDevice::Stop(const char* name, void* cookie) 44561604e48SAxel Dörfler { 44661604e48SAxel Dörfler LOG("%s(%s)\n", __PRETTY_FUNCTION__, name); 44761604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 44861604e48SAxel Dörfler 44961604e48SAxel Dörfler device->Stop(); 45061604e48SAxel Dörfler return B_OK; 45161604e48SAxel Dörfler } 45261604e48SAxel Dörfler 45361604e48SAxel Dörfler 45461604e48SAxel Dörfler status_t 45561604e48SAxel Dörfler MouseInputDevice::Control(const char* name, void* cookie, 45661604e48SAxel Dörfler uint32 command, BMessage* message) 45761604e48SAxel Dörfler { 45861604e48SAxel Dörfler LOG("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command); 45961604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 46061604e48SAxel Dörfler 46161604e48SAxel Dörfler if (command == B_NODE_MONITOR) 46261604e48SAxel Dörfler return _HandleMonitor(message); 46361604e48SAxel Dörfler 46461604e48SAxel Dörfler if (command >= B_MOUSE_TYPE_CHANGED 46561604e48SAxel Dörfler && command <= B_MOUSE_ACCELERATION_CHANGED) 46661604e48SAxel Dörfler return device->UpdateSettings(); 46761604e48SAxel Dörfler 46861604e48SAxel Dörfler return B_BAD_VALUE; 46961604e48SAxel Dörfler } 47061604e48SAxel Dörfler 47161604e48SAxel Dörfler 47261604e48SAxel Dörfler status_t 47361604e48SAxel Dörfler MouseInputDevice::_HandleMonitor(BMessage* message) 47461604e48SAxel Dörfler { 47561604e48SAxel Dörfler CALLED(); 47661604e48SAxel Dörfler 477b6a7b204SAxel Dörfler const char* path; 47861604e48SAxel Dörfler int32 opcode; 479b6a7b204SAxel Dörfler if (message->FindInt32("opcode", &opcode) != B_OK 480*c5555ad3SStephan Aßmus || (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED) 481b6a7b204SAxel Dörfler || message->FindString("path", &path) != B_OK) 48261604e48SAxel Dörfler return B_BAD_VALUE; 48361604e48SAxel Dörfler 48461604e48SAxel Dörfler if (opcode == B_ENTRY_CREATED) 485b6a7b204SAxel Dörfler return _AddDevice(path); 48661604e48SAxel Dörfler 487*c5555ad3SStephan Aßmus #if 0 488b6a7b204SAxel Dörfler return _RemoveDevice(path); 489*c5555ad3SStephan Aßmus #else 490*c5555ad3SStephan Aßmus // Don't handle B_ENTRY_REMOVED, let the control thread take care of it. 491*c5555ad3SStephan Aßmus return B_OK; 492*c5555ad3SStephan Aßmus #endif 49361604e48SAxel Dörfler } 49461604e48SAxel Dörfler 49561604e48SAxel Dörfler 49661604e48SAxel Dörfler MouseDevice* 49761604e48SAxel Dörfler MouseInputDevice::_FindDevice(const char* path) 49861604e48SAxel Dörfler { 49961604e48SAxel Dörfler CALLED(); 50061604e48SAxel Dörfler 501*c5555ad3SStephan Aßmus for (int32 i = fDevices.CountItems() - 1; i >= 0; i--) { 502b6a7b204SAxel Dörfler MouseDevice* device = fDevices.ItemAt(i); 503*c5555ad3SStephan Aßmus if (strcmp(device->Path(), path) == 0) 50461604e48SAxel Dörfler return device; 50561604e48SAxel Dörfler } 50661604e48SAxel Dörfler 50761604e48SAxel Dörfler return NULL; 50861604e48SAxel Dörfler } 50961604e48SAxel Dörfler 51061604e48SAxel Dörfler 51161604e48SAxel Dörfler status_t 51261604e48SAxel Dörfler MouseInputDevice::_AddDevice(const char* path) 51361604e48SAxel Dörfler { 51461604e48SAxel Dörfler CALLED(); 51561604e48SAxel Dörfler 516*c5555ad3SStephan Aßmus _RemoveDevice(path); 517*c5555ad3SStephan Aßmus 51861604e48SAxel Dörfler MouseDevice* device = new(std::nothrow) MouseDevice(*this, path); 51961604e48SAxel Dörfler if (!device) { 520*c5555ad3SStephan Aßmus LOG("MouseInputDevice::_AddDevice() - No memory\n"); 52161604e48SAxel Dörfler return B_NO_MEMORY; 52261604e48SAxel Dörfler } 52361604e48SAxel Dörfler 52461604e48SAxel Dörfler if (!fDevices.AddItem(device)) { 52561604e48SAxel Dörfler delete device; 52661604e48SAxel Dörfler return B_NO_MEMORY; 52761604e48SAxel Dörfler } 52861604e48SAxel Dörfler 52961604e48SAxel Dörfler input_device_ref* devices[2]; 53061604e48SAxel Dörfler devices[0] = device->DeviceRef(); 53161604e48SAxel Dörfler devices[1] = NULL; 53261604e48SAxel Dörfler 533*c5555ad3SStephan Aßmus LOG_DEVICES("MouseInputDevice::_AddDevice(%s), name: %s\n", path, 534*c5555ad3SStephan Aßmus devices[0]->name); 535*c5555ad3SStephan Aßmus 53661604e48SAxel Dörfler return RegisterDevices(devices); 53761604e48SAxel Dörfler } 53861604e48SAxel Dörfler 53961604e48SAxel Dörfler 54061604e48SAxel Dörfler status_t 54161604e48SAxel Dörfler MouseInputDevice::_RemoveDevice(const char* path) 54261604e48SAxel Dörfler { 54361604e48SAxel Dörfler CALLED(); 54461604e48SAxel Dörfler 54561604e48SAxel Dörfler MouseDevice* device = _FindDevice(path); 54661604e48SAxel Dörfler if (device == NULL) 54761604e48SAxel Dörfler return B_ENTRY_NOT_FOUND; 54861604e48SAxel Dörfler 54961604e48SAxel Dörfler input_device_ref* devices[2]; 55061604e48SAxel Dörfler devices[0] = device->DeviceRef(); 55161604e48SAxel Dörfler devices[1] = NULL; 55261604e48SAxel Dörfler 553*c5555ad3SStephan Aßmus LOG_DEVICES("MouseInputDevice::_RemoveDevice(%s), name: %s\n", path, 554*c5555ad3SStephan Aßmus devices[0]->name); 555*c5555ad3SStephan Aßmus 55661604e48SAxel Dörfler UnregisterDevices(devices); 55761604e48SAxel Dörfler 558*c5555ad3SStephan Aßmus fDevices.RemoveItem(device); 559*c5555ad3SStephan Aßmus 56061604e48SAxel Dörfler return B_OK; 56161604e48SAxel Dörfler } 56261604e48SAxel Dörfler 56361604e48SAxel Dörfler 56461604e48SAxel Dörfler void 56561604e48SAxel Dörfler MouseInputDevice::_RecursiveScan(const char* directory) 56661604e48SAxel Dörfler { 56761604e48SAxel Dörfler CALLED(); 56861604e48SAxel Dörfler 56961604e48SAxel Dörfler BEntry entry; 57061604e48SAxel Dörfler BDirectory dir(directory); 57161604e48SAxel Dörfler while (dir.GetNextEntry(&entry) == B_OK) { 57261604e48SAxel Dörfler BPath path; 57361604e48SAxel Dörfler entry.GetPath(&path); 57461604e48SAxel Dörfler 57561604e48SAxel Dörfler if (!strcmp(path.Leaf(), "serial")) { 57661604e48SAxel Dörfler // skip serial 57761604e48SAxel Dörfler continue; 57861604e48SAxel Dörfler } 57961604e48SAxel Dörfler 58061604e48SAxel Dörfler if (entry.IsDirectory()) 58161604e48SAxel Dörfler _RecursiveScan(path.Path()); 58261604e48SAxel Dörfler else 58361604e48SAxel Dörfler _AddDevice(path.Path()); 58461604e48SAxel Dörfler } 58561604e48SAxel Dörfler } 58661604e48SAxel Dörfler 587