123b47e0bSJérôme Duval /* 223b47e0bSJérôme Duval * Copyright 2004-2006, Haiku. 323b47e0bSJérôme Duval * Distributed under the terms of the MIT License. 423b47e0bSJérôme Duval * 523b47e0bSJérôme Duval * Authors: 623b47e0bSJérôme Duval * Stefano Ceccherini 723b47e0bSJérôme Duval */ 833efb919SStefano Ceccherini 933efb919SStefano Ceccherini 1061d7deeeSJérôme Duval #include "MouseInputDevice.h" 11fc2045eeSJérôme Duval #include "kb_mouse_settings.h" 12fc2045eeSJérôme Duval #include "kb_mouse_driver.h" 1361d7deeeSJérôme Duval 14c2fbfb71SJérôme Duval #include <Debug.h> 1533efb919SStefano Ceccherini #include <Directory.h> 1633efb919SStefano Ceccherini #include <Entry.h> 1733efb919SStefano Ceccherini #include <NodeMonitor.h> 1833efb919SStefano Ceccherini #include <Path.h> 1933efb919SStefano Ceccherini #include <String.h> 2061604e48SAxel Dörfler #include <View.h> 2161604e48SAxel Dörfler 2261604e48SAxel Dörfler #include <errno.h> 2361604e48SAxel Dörfler #include <new> 2461604e48SAxel Dörfler #include <stdio.h> 2561604e48SAxel Dörfler #include <stdlib.h> 2661604e48SAxel Dörfler #include <unistd.h> 2733efb919SStefano Ceccherini 283aa69c78SStefano Ceccherini #if DEBUG 29c2fbfb71SJérôme Duval FILE *MouseInputDevice::sLogFile = NULL; 3061604e48SAxel Dörfler # define LOG_ERR(text...) LOG(text) 313aa69c78SStefano Ceccherini #else 32c2fbfb71SJérôme Duval # define LOG(text...) 33c2fbfb71SJérôme Duval # define LOG_ERR(text...) fprintf(stderr, text) 343aa69c78SStefano Ceccherini #endif 353aa69c78SStefano Ceccherini 36c2fbfb71SJérôme Duval #define CALLED() LOG("%s\n", __PRETTY_FUNCTION__) 3733efb919SStefano Ceccherini 3833efb919SStefano Ceccherini const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4; 3933efb919SStefano Ceccherini const static char *kMouseDevicesDirectory = "/dev/input/mouse"; 4033efb919SStefano Ceccherini 4133efb919SStefano Ceccherini // "/dev/" is automatically prepended by StartMonitoringDevice() 42f0bac935SJérôme Duval const static char *kMouseDevicesDirectoryPS2 = "input/mouse/ps2"; 4333efb919SStefano Ceccherini const static char *kMouseDevicesDirectoryUSB = "input/mouse/usb"; 4433efb919SStefano Ceccherini 4561604e48SAxel Dörfler class MouseDevice { 4661604e48SAxel Dörfler public: 4761604e48SAxel Dörfler MouseDevice(BInputServerDevice& target, const char* path); 4861604e48SAxel Dörfler ~MouseDevice(); 4933efb919SStefano Ceccherini 5061604e48SAxel Dörfler status_t Start(); 5161604e48SAxel Dörfler void Stop(); 5261604e48SAxel Dörfler 5361604e48SAxel Dörfler status_t UpdateSettings(); 5461604e48SAxel Dörfler 5561604e48SAxel Dörfler const char* Path() const { return fPath.String(); } 5661604e48SAxel Dörfler input_device_ref* DeviceRef() { return &fDeviceRef; } 5761604e48SAxel Dörfler 5861604e48SAxel Dörfler private: 5961604e48SAxel Dörfler void _Run(); 6061604e48SAxel Dörfler static status_t _ThreadFunction(void *arg); 6161604e48SAxel Dörfler 6261604e48SAxel Dörfler BMessage* _BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, 6361604e48SAxel Dörfler int32 deltaX, int32 deltaY) const; 6461604e48SAxel Dörfler void _ComputeAcceleration(const mouse_movement& movements, 6561604e48SAxel Dörfler int32& deltaX, int32& deltaY) const; 6661604e48SAxel Dörfler uint32 _RemapButtons(uint32 buttons) const; 6761604e48SAxel Dörfler 6861604e48SAxel Dörfler char* _BuildShortName() const; 6961604e48SAxel Dörfler 7061604e48SAxel Dörfler private: 7161604e48SAxel Dörfler BInputServerDevice& fTarget; 7261604e48SAxel Dörfler BString fPath; 7361604e48SAxel Dörfler int fDevice; 7461604e48SAxel Dörfler 7561604e48SAxel Dörfler input_device_ref fDeviceRef; 7661604e48SAxel Dörfler mouse_settings fSettings; 7761604e48SAxel Dörfler bool fDeviceRemapsButtons; 7861604e48SAxel Dörfler 7961604e48SAxel Dörfler thread_id fThread; 8061604e48SAxel Dörfler volatile bool fActive; 810dbc4befSStefano Ceccherini }; 820dbc4befSStefano Ceccherini 830dbc4befSStefano Ceccherini 8461604e48SAxel Dörfler #if DEBUG 8561604e48SAxel Dörfler inline void 8661604e48SAxel Dörfler LOG(const char *fmt, ...) 8761604e48SAxel Dörfler { 8861604e48SAxel Dörfler char buf[1024]; 8961604e48SAxel Dörfler va_list ap; 9061604e48SAxel Dörfler va_start(ap, fmt); 9161604e48SAxel Dörfler vsprintf(buf, fmt, ap); va_end(ap); 9261604e48SAxel Dörfler fputs(buf, MouseInputDevice::sLogFile); fflush(MouseInputDevice::sLogFile); 9361604e48SAxel Dörfler } 9461604e48SAxel Dörfler #endif 954c0af4a8SStefano Ceccherini 964c0af4a8SStefano Ceccherini 9761604e48SAxel Dörfler extern "C" BInputServerDevice * 9861d7deeeSJérôme Duval instantiate_input_device() 9961d7deeeSJérôme Duval { 10061d7deeeSJérôme Duval return new MouseInputDevice(); 10161d7deeeSJérôme Duval } 10261d7deeeSJérôme Duval 10361d7deeeSJérôme Duval 10461604e48SAxel Dörfler // #pragma mark - 10561604e48SAxel Dörfler 10661604e48SAxel Dörfler 10761604e48SAxel Dörfler MouseDevice::MouseDevice(BInputServerDevice& target, const char *driverPath) 10861604e48SAxel Dörfler : 10961604e48SAxel Dörfler fTarget(target), 11061604e48SAxel Dörfler fDevice(-1), 11161604e48SAxel Dörfler fThread(-1), 11261604e48SAxel Dörfler fActive(false) 11361d7deeeSJérôme Duval { 11461604e48SAxel Dörfler fPath = driverPath; 11561604e48SAxel Dörfler 11661604e48SAxel Dörfler fDeviceRef.name = _BuildShortName(); 11761604e48SAxel Dörfler fDeviceRef.type = B_POINTING_DEVICE; 11861604e48SAxel Dörfler fDeviceRef.cookie = this; 11961604e48SAxel Dörfler 12061604e48SAxel Dörfler #ifdef HAIKU_TARGET_PLATFORM_HAIKU 12161604e48SAxel Dörfler fSettings.map.button[0] = B_PRIMARY_MOUSE_BUTTON; 12261604e48SAxel Dörfler fSettings.map.button[1] = B_SECONDARY_MOUSE_BUTTON; 12361604e48SAxel Dörfler fSettings.map.button[2] = B_TERTIARY_MOUSE_BUTTON; 1243aa69c78SStefano Ceccherini #endif 12533efb919SStefano Ceccherini 12661604e48SAxel Dörfler fDeviceRemapsButtons = false; 12761604e48SAxel Dörfler }; 12861d7deeeSJérôme Duval 12961d7deeeSJérôme Duval 13061604e48SAxel Dörfler MouseDevice::~MouseDevice() 13161d7deeeSJérôme Duval { 13261604e48SAxel Dörfler if (fActive) 13361604e48SAxel Dörfler Stop(); 13461d7deeeSJérôme Duval 13561604e48SAxel Dörfler free(fDeviceRef.name); 13661d7deeeSJérôme Duval } 13761d7deeeSJérôme Duval 13861d7deeeSJérôme Duval 13961d7deeeSJérôme Duval status_t 14061604e48SAxel Dörfler MouseDevice::Start() 14153d77642SJérôme Duval { 14261604e48SAxel Dörfler fDevice = open(fPath.String(), O_RDWR); 14361604e48SAxel Dörfler if (fDevice < 0) 14461604e48SAxel Dörfler return errno; 14533efb919SStefano Ceccherini 14661604e48SAxel Dörfler UpdateSettings(); 14733efb919SStefano Ceccherini 14833efb919SStefano Ceccherini char threadName[B_OS_NAME_LENGTH]; 14961604e48SAxel Dörfler snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", fDeviceRef.name); 15033efb919SStefano Ceccherini 15161604e48SAxel Dörfler fThread = spawn_thread(_ThreadFunction, threadName, 15261604e48SAxel Dörfler kMouseThreadPriority, (void *)this); 1534c0af4a8SStefano Ceccherini 15433efb919SStefano Ceccherini status_t status; 15561604e48SAxel Dörfler if (fThread < B_OK) 15661604e48SAxel Dörfler status = fThread; 15761604e48SAxel Dörfler else { 15861604e48SAxel Dörfler fActive = true; 15961604e48SAxel Dörfler status = resume_thread(fThread); 16061604e48SAxel Dörfler } 16133efb919SStefano Ceccherini 16261604e48SAxel Dörfler if (status < B_OK) { 16361604e48SAxel Dörfler LOG_ERR("%s: can't spawn/resume watching thread: %s\n", 16461604e48SAxel Dörfler fDeviceRef.name, strerror(status)); 16561604e48SAxel Dörfler close(fDevice); 16661604e48SAxel Dörfler return status; 16761604e48SAxel Dörfler } 16861604e48SAxel Dörfler 169c2fbfb71SJérôme Duval return B_OK; 17061d7deeeSJérôme Duval } 17161d7deeeSJérôme Duval 17261d7deeeSJérôme Duval 173c2fbfb71SJérôme Duval void 17461604e48SAxel Dörfler MouseDevice::Stop() 17561604e48SAxel Dörfler { 17661604e48SAxel Dörfler fActive = false; 17761604e48SAxel Dörfler // this will stop the thread as soon as it reads the next packet 17861604e48SAxel Dörfler 17961604e48SAxel Dörfler if (fThread >= B_OK) { 18061604e48SAxel Dörfler // unblock the thread, which might wait on a semaphore. 18161604e48SAxel Dörfler suspend_thread(fThread); 18261604e48SAxel Dörfler resume_thread(fThread); 18361604e48SAxel Dörfler 18461604e48SAxel Dörfler status_t dummy; 18561604e48SAxel Dörfler wait_for_thread(fThread, &dummy); 18661604e48SAxel Dörfler } 18761604e48SAxel Dörfler 18861604e48SAxel Dörfler close(fDevice); 18961604e48SAxel Dörfler } 19061604e48SAxel Dörfler 19161604e48SAxel Dörfler 19242b505fbSAxel Dörfler status_t 19342b505fbSAxel Dörfler MouseDevice::UpdateSettings() 19442b505fbSAxel Dörfler { 19542b505fbSAxel Dörfler CALLED(); 19642b505fbSAxel Dörfler 19742b505fbSAxel Dörfler // retrieve current values 19842b505fbSAxel Dörfler 19942b505fbSAxel Dörfler if (get_mouse_map(&fSettings.map) != B_OK) 20042b505fbSAxel Dörfler LOG_ERR("error when get_mouse_map\n"); 20142b505fbSAxel Dörfler else 20242b505fbSAxel Dörfler fDeviceRemapsButtons = ioctl(fDevice, MS_SET_MAP, &fSettings.map) == B_OK; 20342b505fbSAxel Dörfler 20442b505fbSAxel Dörfler if (get_click_speed(&fSettings.click_speed) != B_OK) 20542b505fbSAxel Dörfler LOG_ERR("error when get_click_speed\n"); 20642b505fbSAxel Dörfler else 20742b505fbSAxel Dörfler ioctl(fDevice, MS_SET_CLICKSPEED, &fSettings.click_speed); 20842b505fbSAxel Dörfler 20942b505fbSAxel Dörfler if (get_mouse_speed(&fSettings.accel.speed) != B_OK) 21042b505fbSAxel Dörfler LOG_ERR("error when get_mouse_speed\n"); 21142b505fbSAxel Dörfler else { 21242b505fbSAxel Dörfler if (get_mouse_acceleration(&fSettings.accel.accel_factor) != B_OK) 21342b505fbSAxel Dörfler LOG_ERR("error when get_mouse_acceleration\n"); 21442b505fbSAxel Dörfler else { 21542b505fbSAxel Dörfler mouse_accel accel; 21642b505fbSAxel Dörfler ioctl(fDevice, MS_GET_ACCEL, &accel); 21742b505fbSAxel Dörfler accel.speed = fSettings.accel.speed; 21842b505fbSAxel Dörfler accel.accel_factor = fSettings.accel.accel_factor; 21942b505fbSAxel Dörfler ioctl(fDevice, MS_SET_ACCEL, &fSettings.accel); 22042b505fbSAxel Dörfler } 22142b505fbSAxel Dörfler } 22242b505fbSAxel Dörfler 22342b505fbSAxel Dörfler if (get_mouse_type(&fSettings.type) != B_OK) 22442b505fbSAxel Dörfler LOG_ERR("error when get_mouse_type\n"); 22542b505fbSAxel Dörfler else 22642b505fbSAxel Dörfler ioctl(fDevice, MS_SET_TYPE, &fSettings.type); 22742b505fbSAxel Dörfler 22842b505fbSAxel Dörfler return B_OK; 22942b505fbSAxel Dörfler 23042b505fbSAxel Dörfler } 23142b505fbSAxel Dörfler 23242b505fbSAxel Dörfler 23361604e48SAxel Dörfler void 23461604e48SAxel Dörfler MouseDevice::_Run() 23561604e48SAxel Dörfler { 23661604e48SAxel Dörfler uint32 lastButtons = 0; 23761604e48SAxel Dörfler 23861604e48SAxel Dörfler while (fActive) { 23961604e48SAxel Dörfler mouse_movement movements; 24061604e48SAxel Dörfler memset(&movements, 0, sizeof(movements)); 24161604e48SAxel Dörfler 24261604e48SAxel Dörfler if (ioctl(fDevice, MS_READ, &movements) != B_OK) 24361604e48SAxel Dörfler return; 24461604e48SAxel Dörfler 24561604e48SAxel Dörfler uint32 buttons = lastButtons ^ movements.buttons; 24661604e48SAxel Dörfler 24761604e48SAxel Dörfler uint32 remappedButtons = _RemapButtons(movements.buttons); 24861604e48SAxel Dörfler int32 deltaX, deltaY; 24961604e48SAxel Dörfler _ComputeAcceleration(movements, deltaX, deltaY); 25061604e48SAxel Dörfler 25161604e48SAxel Dörfler LOG("%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld, wheel_x:%ld, wheel_y:%ld\n", 25261604e48SAxel Dörfler device->device_ref.name, movements.buttons, movements.xdelta, movements.ydelta, 25361604e48SAxel Dörfler movements.clicks, movements.wheel_xdelta, movements.wheel_ydelta); 25461604e48SAxel Dörfler LOG("%s: x: %ld, y: %ld\n", device->device_ref.name, deltaX, deltaY); 25561604e48SAxel Dörfler 25661604e48SAxel Dörfler BMessage *message = NULL; 25761604e48SAxel Dörfler 25861604e48SAxel Dörfler // Send single messages for each event 25961604e48SAxel Dörfler 26061604e48SAxel Dörfler if (movements.xdelta != 0 || movements.ydelta != 0) { 26161604e48SAxel Dörfler BMessage* message = _BuildMouseMessage(B_MOUSE_MOVED, movements.timestamp, 26261604e48SAxel Dörfler remappedButtons, deltaX, deltaY); 26361604e48SAxel Dörfler if (message != NULL) 26461604e48SAxel Dörfler fTarget.EnqueueMessage(message); 26561604e48SAxel Dörfler } 26661604e48SAxel Dörfler 26761604e48SAxel Dörfler if (buttons != 0) { 26861604e48SAxel Dörfler bool pressedButton = (buttons & movements.buttons) > 0; 26961604e48SAxel Dörfler BMessage* message = _BuildMouseMessage( 27061604e48SAxel Dörfler pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP, 27161604e48SAxel Dörfler movements.timestamp, remappedButtons, deltaX, deltaY); 27261604e48SAxel Dörfler if (message != NULL) { 27361604e48SAxel Dörfler if (pressedButton) { 27461604e48SAxel Dörfler message->AddInt32("clicks", movements.clicks); 27561604e48SAxel Dörfler LOG("B_MOUSE_DOWN\n"); 27661604e48SAxel Dörfler } else 27761604e48SAxel Dörfler LOG("B_MOUSE_UP\n"); 27861604e48SAxel Dörfler 27961604e48SAxel Dörfler fTarget.EnqueueMessage(message); 28061604e48SAxel Dörfler lastButtons = movements.buttons; 28161604e48SAxel Dörfler } 28261604e48SAxel Dörfler } 28361604e48SAxel Dörfler 28461604e48SAxel Dörfler if ((movements.wheel_ydelta != 0) || (movements.wheel_xdelta != 0)) { 28561604e48SAxel Dörfler message = new BMessage(B_MOUSE_WHEEL_CHANGED); 28661604e48SAxel Dörfler if (message == NULL) 28761604e48SAxel Dörfler continue; 28861604e48SAxel Dörfler 28961604e48SAxel Dörfler if (message->AddInt64("when", movements.timestamp) == B_OK 29061604e48SAxel Dörfler && message->AddFloat("be:wheel_delta_x", movements.wheel_xdelta) == B_OK 29161604e48SAxel Dörfler && message->AddFloat("be:wheel_delta_y", movements.wheel_ydelta) == B_OK) 29261604e48SAxel Dörfler fTarget.EnqueueMessage(message); 29361604e48SAxel Dörfler else 29461604e48SAxel Dörfler delete message; 29561604e48SAxel Dörfler } 29661604e48SAxel Dörfler } 29761604e48SAxel Dörfler } 29861604e48SAxel Dörfler 29961604e48SAxel Dörfler 30061604e48SAxel Dörfler status_t 30161604e48SAxel Dörfler MouseDevice::_ThreadFunction(void* arg) 30261604e48SAxel Dörfler { 30361604e48SAxel Dörfler MouseDevice* device = (MouseDevice *)arg; 30461604e48SAxel Dörfler device->_Run(); 30561604e48SAxel Dörfler return B_OK; 30661604e48SAxel Dörfler } 30761604e48SAxel Dörfler 30861604e48SAxel Dörfler 30961604e48SAxel Dörfler BMessage* 31061604e48SAxel Dörfler MouseDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, 31161604e48SAxel Dörfler int32 deltaX, int32 deltaY) const 31261604e48SAxel Dörfler { 31361604e48SAxel Dörfler BMessage* message = new BMessage(what); 31461604e48SAxel Dörfler if (message == NULL) 31561604e48SAxel Dörfler return NULL; 31661604e48SAxel Dörfler 31761604e48SAxel Dörfler if (message->AddInt64("when", when) < B_OK 31861604e48SAxel Dörfler || message->AddInt32("buttons", buttons) < B_OK 31961604e48SAxel Dörfler || message->AddInt32("x", deltaX) < B_OK 32061604e48SAxel Dörfler || message->AddInt32("y", deltaY) < B_OK) { 32161604e48SAxel Dörfler delete message; 32261604e48SAxel Dörfler return NULL; 32361604e48SAxel Dörfler } 32461604e48SAxel Dörfler 32561604e48SAxel Dörfler return message; 32661604e48SAxel Dörfler } 32761604e48SAxel Dörfler 32861604e48SAxel Dörfler 32961604e48SAxel Dörfler void 33061604e48SAxel Dörfler MouseDevice::_ComputeAcceleration(const mouse_movement& movements, 33161604e48SAxel Dörfler int32& deltaX, int32& deltaY) const 33261604e48SAxel Dörfler { 33342b505fbSAxel Dörfler // basic mouse speed 33442b505fbSAxel Dörfler deltaX = movements.xdelta * fSettings.accel.speed >> 16; 33542b505fbSAxel Dörfler deltaY = movements.ydelta * fSettings.accel.speed >> 16; 33642b505fbSAxel Dörfler 33742b505fbSAxel Dörfler // acceleration 33842b505fbSAxel Dörfler double acceleration = 1; 33942b505fbSAxel Dörfler if (fSettings.accel.accel_factor) { 340*fafab827SAxel Dörfler acceleration = 1 + sqrt(deltaX * deltaX + deltaY * deltaY) 34174ef1621SAxel Dörfler * fSettings.accel.accel_factor / 524288.0; 34242b505fbSAxel Dörfler } 34342b505fbSAxel Dörfler 34442b505fbSAxel Dörfler // make sure that we move at least one pixel (if there was a movement) 34542b505fbSAxel Dörfler if (deltaX > 0) 34642b505fbSAxel Dörfler deltaX = (int32)floor(deltaX * acceleration); 347*fafab827SAxel Dörfler else 348*fafab827SAxel Dörfler deltaX = (int32)ceil(deltaX * acceleration); 34942b505fbSAxel Dörfler 35042b505fbSAxel Dörfler if (deltaY > 0) 35142b505fbSAxel Dörfler deltaY = (int32)floor(deltaY * acceleration); 352*fafab827SAxel Dörfler else 353*fafab827SAxel Dörfler deltaY = (int32)ceil(deltaY * acceleration); 35461604e48SAxel Dörfler } 35561604e48SAxel Dörfler 35633efb919SStefano Ceccherini 35723b47e0bSJérôme Duval uint32 35861604e48SAxel Dörfler MouseDevice::_RemapButtons(uint32 buttons) const 35923b47e0bSJérôme Duval { 36061604e48SAxel Dörfler if (fDeviceRemapsButtons) 36123b47e0bSJérôme Duval return buttons; 36223b47e0bSJérôme Duval 36361604e48SAxel Dörfler uint32 newButtons = 0; 36423b47e0bSJérôme Duval for (int32 i = 0; buttons; i++) { 36523b47e0bSJérôme Duval if (buttons & 0x1) { 36623b47e0bSJérôme Duval #ifdef HAIKU_TARGET_PLATFORM_HAIKU 36761604e48SAxel Dörfler newButtons |= fSettings.map.button[i]; 36823b47e0bSJérôme Duval #else 36923b47e0bSJérôme Duval if (i == 0) 37061604e48SAxel Dörfler newButtons |= fSettings.map.left; 37123b47e0bSJérôme Duval if (i == 1) 37261604e48SAxel Dörfler newButtons |= fSettings.map.right; 37323b47e0bSJérôme Duval if (i == 2) 37461604e48SAxel Dörfler newButtons |= fSettings.map.middle; 37523b47e0bSJérôme Duval #endif 37623b47e0bSJérôme Duval } 37723b47e0bSJérôme Duval buttons >>= 1; 37823b47e0bSJérôme Duval } 37923b47e0bSJérôme Duval 38061604e48SAxel Dörfler return newButtons; 38123b47e0bSJérôme Duval } 38223b47e0bSJérôme Duval 38323b47e0bSJérôme Duval 38461604e48SAxel Dörfler char * 38561604e48SAxel Dörfler MouseDevice::_BuildShortName() const 3864c0af4a8SStefano Ceccherini { 38761604e48SAxel Dörfler BString string(fPath); 38833efb919SStefano Ceccherini BString name; 38933efb919SStefano Ceccherini 39033efb919SStefano Ceccherini int32 slash = string.FindLast("/"); 3917dcdcad2SJérôme Duval string.CopyInto(name, slash + 1, string.Length() - slash); 3927dcdcad2SJérôme Duval int32 index = atoi(name.String()) + 1; 39333efb919SStefano Ceccherini 3947dcdcad2SJérôme Duval int32 previousSlash = string.FindLast("/", slash); 3957dcdcad2SJérôme Duval string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1); 396497d01f0SAxel Dörfler 397497d01f0SAxel Dörfler if (name == "ps2") 398497d01f0SAxel Dörfler name = "PS/2"; 399497d01f0SAxel Dörfler else 400497d01f0SAxel Dörfler name.Capitalize(); 401497d01f0SAxel Dörfler 4027dcdcad2SJérôme Duval name << " Mouse " << index; 40333efb919SStefano Ceccherini 40433efb919SStefano Ceccherini return strdup(name.String()); 40533efb919SStefano Ceccherini } 40661604e48SAxel Dörfler 40761604e48SAxel Dörfler 40861604e48SAxel Dörfler // #pragma mark - 40961604e48SAxel Dörfler 41061604e48SAxel Dörfler 41161604e48SAxel Dörfler MouseInputDevice::MouseInputDevice() 41261604e48SAxel Dörfler { 41361604e48SAxel Dörfler #if DEBUG 41461604e48SAxel Dörfler sLogFile = fopen("/var/log/mouse_device_log.log", "a"); 41561604e48SAxel Dörfler #endif 41661604e48SAxel Dörfler CALLED(); 41761604e48SAxel Dörfler 41861604e48SAxel Dörfler StartMonitoringDevice(kMouseDevicesDirectoryPS2); 41961604e48SAxel Dörfler StartMonitoringDevice(kMouseDevicesDirectoryUSB); 42061604e48SAxel Dörfler 42161604e48SAxel Dörfler _RecursiveScan(kMouseDevicesDirectory); 42261604e48SAxel Dörfler } 42361604e48SAxel Dörfler 42461604e48SAxel Dörfler 42561604e48SAxel Dörfler MouseInputDevice::~MouseInputDevice() 42661604e48SAxel Dörfler { 42761604e48SAxel Dörfler CALLED(); 42861604e48SAxel Dörfler StopMonitoringDevice(kMouseDevicesDirectoryUSB); 42961604e48SAxel Dörfler StopMonitoringDevice(kMouseDevicesDirectoryPS2); 43061604e48SAxel Dörfler 43161604e48SAxel Dörfler int32 count = fDevices.CountItems(); 43261604e48SAxel Dörfler while (count-- > 0) { 43361604e48SAxel Dörfler delete (MouseDevice *)fDevices.RemoveItem(count); 43461604e48SAxel Dörfler } 43561604e48SAxel Dörfler 43661604e48SAxel Dörfler #if DEBUG 43761604e48SAxel Dörfler fclose(sLogFile); 43861604e48SAxel Dörfler #endif 43961604e48SAxel Dörfler } 44061604e48SAxel Dörfler 44161604e48SAxel Dörfler 44261604e48SAxel Dörfler status_t 44361604e48SAxel Dörfler MouseInputDevice::InitCheck() 44461604e48SAxel Dörfler { 44561604e48SAxel Dörfler CALLED(); 44661604e48SAxel Dörfler return B_OK; 44761604e48SAxel Dörfler } 44861604e48SAxel Dörfler 44961604e48SAxel Dörfler 45061604e48SAxel Dörfler status_t 45161604e48SAxel Dörfler MouseInputDevice::Start(const char *name, void *cookie) 45261604e48SAxel Dörfler { 45361604e48SAxel Dörfler LOG("%s(%s)\n", __PRETTY_FUNCTION__, name); 45461604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 45561604e48SAxel Dörfler 45661604e48SAxel Dörfler return device->Start(); 45761604e48SAxel Dörfler } 45861604e48SAxel Dörfler 45961604e48SAxel Dörfler 46061604e48SAxel Dörfler status_t 46161604e48SAxel Dörfler MouseInputDevice::Stop(const char *name, void *cookie) 46261604e48SAxel Dörfler { 46361604e48SAxel Dörfler LOG("%s(%s)\n", __PRETTY_FUNCTION__, name); 46461604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 46561604e48SAxel Dörfler 46661604e48SAxel Dörfler device->Stop(); 46761604e48SAxel Dörfler return B_OK; 46861604e48SAxel Dörfler } 46961604e48SAxel Dörfler 47061604e48SAxel Dörfler 47161604e48SAxel Dörfler status_t 47261604e48SAxel Dörfler MouseInputDevice::Control(const char* name, void* cookie, 47361604e48SAxel Dörfler uint32 command, BMessage* message) 47461604e48SAxel Dörfler { 47561604e48SAxel Dörfler LOG("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command); 47661604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 47761604e48SAxel Dörfler 47861604e48SAxel Dörfler if (command == B_NODE_MONITOR) 47961604e48SAxel Dörfler return _HandleMonitor(message); 48061604e48SAxel Dörfler 48161604e48SAxel Dörfler if (command >= B_MOUSE_TYPE_CHANGED 48261604e48SAxel Dörfler && command <= B_MOUSE_ACCELERATION_CHANGED) 48361604e48SAxel Dörfler return device->UpdateSettings(); 48461604e48SAxel Dörfler 48561604e48SAxel Dörfler return B_BAD_VALUE; 48661604e48SAxel Dörfler } 48761604e48SAxel Dörfler 48861604e48SAxel Dörfler 48961604e48SAxel Dörfler // TODO: Test this. USB doesn't work on my machine 49061604e48SAxel Dörfler status_t 49161604e48SAxel Dörfler MouseInputDevice::_HandleMonitor(BMessage* message) 49261604e48SAxel Dörfler { 49361604e48SAxel Dörfler CALLED(); 49461604e48SAxel Dörfler 49561604e48SAxel Dörfler int32 opcode; 49661604e48SAxel Dörfler if (message->FindInt32("opcode", &opcode) < B_OK) 49761604e48SAxel Dörfler return B_BAD_VALUE; 49861604e48SAxel Dörfler 49961604e48SAxel Dörfler if (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED) 50061604e48SAxel Dörfler return B_OK; 50161604e48SAxel Dörfler 50261604e48SAxel Dörfler BEntry entry; 50361604e48SAxel Dörfler BPath path; 50461604e48SAxel Dörfler dev_t device; 50561604e48SAxel Dörfler ino_t directory; 50661604e48SAxel Dörfler const char *name; 50761604e48SAxel Dörfler 50861604e48SAxel Dörfler if (message->FindInt32("device", &device) < B_OK 50961604e48SAxel Dörfler || message->FindInt64("directory", &directory) < B_OK 51061604e48SAxel Dörfler || message->FindString("name", &name) < B_OK) 51161604e48SAxel Dörfler return B_BAD_VALUE; 51261604e48SAxel Dörfler 51361604e48SAxel Dörfler entry_ref ref(device, directory, name); 51461604e48SAxel Dörfler status_t status; 51561604e48SAxel Dörfler 51661604e48SAxel Dörfler if ((status = entry.SetTo(&ref)) != B_OK) 51761604e48SAxel Dörfler return status; 51861604e48SAxel Dörfler if ((status = entry.GetPath(&path)) != B_OK) 51961604e48SAxel Dörfler return status; 52061604e48SAxel Dörfler if ((status = path.InitCheck()) != B_OK) 52161604e48SAxel Dörfler return status; 52261604e48SAxel Dörfler 52361604e48SAxel Dörfler if (opcode == B_ENTRY_CREATED) 52461604e48SAxel Dörfler status = _AddDevice(path.Path()); 52561604e48SAxel Dörfler else 52661604e48SAxel Dörfler status = _RemoveDevice(path.Path()); 52761604e48SAxel Dörfler 52861604e48SAxel Dörfler return status; 52961604e48SAxel Dörfler } 53061604e48SAxel Dörfler 53161604e48SAxel Dörfler 53261604e48SAxel Dörfler MouseDevice* 53361604e48SAxel Dörfler MouseInputDevice::_FindDevice(const char *path) 53461604e48SAxel Dörfler { 53561604e48SAxel Dörfler CALLED(); 53661604e48SAxel Dörfler 53761604e48SAxel Dörfler for (int32 i = fDevices.CountItems(); i-- > 0;) { 53861604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)fDevices.ItemAt(i); 53961604e48SAxel Dörfler if (!strcmp(device->Path(), path)) 54061604e48SAxel Dörfler return device; 54161604e48SAxel Dörfler } 54261604e48SAxel Dörfler 54361604e48SAxel Dörfler return NULL; 54461604e48SAxel Dörfler } 54561604e48SAxel Dörfler 54661604e48SAxel Dörfler 54761604e48SAxel Dörfler status_t 54861604e48SAxel Dörfler MouseInputDevice::_AddDevice(const char *path) 54961604e48SAxel Dörfler { 55061604e48SAxel Dörfler CALLED(); 55161604e48SAxel Dörfler 55261604e48SAxel Dörfler MouseDevice* device = new (std::nothrow) MouseDevice(*this, path); 55361604e48SAxel Dörfler if (!device) { 55461604e48SAxel Dörfler LOG("No memory\n"); 55561604e48SAxel Dörfler return B_NO_MEMORY; 55661604e48SAxel Dörfler } 55761604e48SAxel Dörfler 55861604e48SAxel Dörfler if (!fDevices.AddItem(device)) { 55961604e48SAxel Dörfler delete device; 56061604e48SAxel Dörfler return B_NO_MEMORY; 56161604e48SAxel Dörfler } 56261604e48SAxel Dörfler 56361604e48SAxel Dörfler input_device_ref *devices[2]; 56461604e48SAxel Dörfler devices[0] = device->DeviceRef(); 56561604e48SAxel Dörfler devices[1] = NULL; 56661604e48SAxel Dörfler 56761604e48SAxel Dörfler return RegisterDevices(devices); 56861604e48SAxel Dörfler } 56961604e48SAxel Dörfler 57061604e48SAxel Dörfler 57161604e48SAxel Dörfler status_t 57261604e48SAxel Dörfler MouseInputDevice::_RemoveDevice(const char *path) 57361604e48SAxel Dörfler { 57461604e48SAxel Dörfler CALLED(); 57561604e48SAxel Dörfler 57661604e48SAxel Dörfler MouseDevice* device = _FindDevice(path); 57761604e48SAxel Dörfler if (device == NULL) 57861604e48SAxel Dörfler return B_ENTRY_NOT_FOUND; 57961604e48SAxel Dörfler 58061604e48SAxel Dörfler fDevices.RemoveItem(device); 58161604e48SAxel Dörfler 58261604e48SAxel Dörfler input_device_ref *devices[2]; 58361604e48SAxel Dörfler devices[0] = device->DeviceRef(); 58461604e48SAxel Dörfler devices[1] = NULL; 58561604e48SAxel Dörfler 58661604e48SAxel Dörfler UnregisterDevices(devices); 58761604e48SAxel Dörfler 58861604e48SAxel Dörfler delete device; 58961604e48SAxel Dörfler return B_OK; 59061604e48SAxel Dörfler } 59161604e48SAxel Dörfler 59261604e48SAxel Dörfler 59361604e48SAxel Dörfler void 59461604e48SAxel Dörfler MouseInputDevice::_RecursiveScan(const char* directory) 59561604e48SAxel Dörfler { 59661604e48SAxel Dörfler CALLED(); 59761604e48SAxel Dörfler 59861604e48SAxel Dörfler BEntry entry; 59961604e48SAxel Dörfler BDirectory dir(directory); 60061604e48SAxel Dörfler while (dir.GetNextEntry(&entry) == B_OK) { 60161604e48SAxel Dörfler BPath path; 60261604e48SAxel Dörfler entry.GetPath(&path); 60361604e48SAxel Dörfler 60461604e48SAxel Dörfler if (!strcmp(path.Leaf(), "serial")) { 60561604e48SAxel Dörfler // skip serial 60661604e48SAxel Dörfler continue; 60761604e48SAxel Dörfler } 60861604e48SAxel Dörfler 60961604e48SAxel Dörfler if (entry.IsDirectory()) 61061604e48SAxel Dörfler _RecursiveScan(path.Path()); 61161604e48SAxel Dörfler else 61261604e48SAxel Dörfler _AddDevice(path.Path()); 61361604e48SAxel Dörfler } 61461604e48SAxel Dörfler } 61561604e48SAxel Dörfler 616