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 3823b47e0bSJérôme Duval #ifndef B_FIRST_REAL_TIME_PRIORITY 3923b47e0bSJérôme Duval # define B_FIRST_REAL_TIME_PRIORITY B_REAL_TIME_DISPLAY_PRIORITY 4023b47e0bSJérôme Duval #endif 4161604e48SAxel Dörfler 4233efb919SStefano Ceccherini const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4; 4333efb919SStefano Ceccherini const static char *kMouseDevicesDirectory = "/dev/input/mouse"; 4433efb919SStefano Ceccherini 4533efb919SStefano Ceccherini // "/dev/" is automatically prepended by StartMonitoringDevice() 46f0bac935SJérôme Duval const static char *kMouseDevicesDirectoryPS2 = "input/mouse/ps2"; 4733efb919SStefano Ceccherini const static char *kMouseDevicesDirectoryUSB = "input/mouse/usb"; 4833efb919SStefano Ceccherini 4961604e48SAxel Dörfler class MouseDevice { 5061604e48SAxel Dörfler public: 5161604e48SAxel Dörfler MouseDevice(BInputServerDevice& target, const char* path); 5261604e48SAxel Dörfler ~MouseDevice(); 5333efb919SStefano Ceccherini 5461604e48SAxel Dörfler status_t Start(); 5561604e48SAxel Dörfler void Stop(); 5661604e48SAxel Dörfler 5761604e48SAxel Dörfler status_t UpdateSettings(); 5861604e48SAxel Dörfler 5961604e48SAxel Dörfler const char* Path() const { return fPath.String(); } 6061604e48SAxel Dörfler input_device_ref* DeviceRef() { return &fDeviceRef; } 6161604e48SAxel Dörfler 6261604e48SAxel Dörfler private: 6361604e48SAxel Dörfler void _Run(); 6461604e48SAxel Dörfler static status_t _ThreadFunction(void *arg); 6561604e48SAxel Dörfler 6661604e48SAxel Dörfler BMessage* _BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, 6761604e48SAxel Dörfler int32 deltaX, int32 deltaY) const; 6861604e48SAxel Dörfler void _ComputeAcceleration(const mouse_movement& movements, 6961604e48SAxel Dörfler int32& deltaX, int32& deltaY) const; 7061604e48SAxel Dörfler uint32 _RemapButtons(uint32 buttons) const; 7161604e48SAxel Dörfler 7261604e48SAxel Dörfler char* _BuildShortName() const; 7361604e48SAxel Dörfler 7461604e48SAxel Dörfler private: 7561604e48SAxel Dörfler BInputServerDevice& fTarget; 7661604e48SAxel Dörfler BString fPath; 7761604e48SAxel Dörfler int fDevice; 7861604e48SAxel Dörfler 7961604e48SAxel Dörfler input_device_ref fDeviceRef; 8061604e48SAxel Dörfler mouse_settings fSettings; 8161604e48SAxel Dörfler bool fDeviceRemapsButtons; 8261604e48SAxel Dörfler 8361604e48SAxel Dörfler thread_id fThread; 8461604e48SAxel Dörfler volatile bool fActive; 850dbc4befSStefano Ceccherini }; 860dbc4befSStefano Ceccherini 870dbc4befSStefano Ceccherini 8861604e48SAxel Dörfler #if DEBUG 8961604e48SAxel Dörfler inline void 9061604e48SAxel Dörfler LOG(const char *fmt, ...) 9161604e48SAxel Dörfler { 9261604e48SAxel Dörfler char buf[1024]; 9361604e48SAxel Dörfler va_list ap; 9461604e48SAxel Dörfler va_start(ap, fmt); 9561604e48SAxel Dörfler vsprintf(buf, fmt, ap); va_end(ap); 9661604e48SAxel Dörfler fputs(buf, MouseInputDevice::sLogFile); fflush(MouseInputDevice::sLogFile); 9761604e48SAxel Dörfler } 9861604e48SAxel Dörfler #endif 994c0af4a8SStefano Ceccherini 1004c0af4a8SStefano Ceccherini 10161604e48SAxel Dörfler extern "C" BInputServerDevice * 10261d7deeeSJérôme Duval instantiate_input_device() 10361d7deeeSJérôme Duval { 10461d7deeeSJérôme Duval return new MouseInputDevice(); 10561d7deeeSJérôme Duval } 10661d7deeeSJérôme Duval 10761d7deeeSJérôme Duval 10861604e48SAxel Dörfler // #pragma mark - 10961604e48SAxel Dörfler 11061604e48SAxel Dörfler 11161604e48SAxel Dörfler MouseDevice::MouseDevice(BInputServerDevice& target, const char *driverPath) 11261604e48SAxel Dörfler : 11361604e48SAxel Dörfler fTarget(target), 11461604e48SAxel Dörfler fDevice(-1), 11561604e48SAxel Dörfler fThread(-1), 11661604e48SAxel Dörfler fActive(false) 11761d7deeeSJérôme Duval { 11861604e48SAxel Dörfler fPath = driverPath; 11961604e48SAxel Dörfler 12061604e48SAxel Dörfler fDeviceRef.name = _BuildShortName(); 12161604e48SAxel Dörfler fDeviceRef.type = B_POINTING_DEVICE; 12261604e48SAxel Dörfler fDeviceRef.cookie = this; 12361604e48SAxel Dörfler 12461604e48SAxel Dörfler #ifdef HAIKU_TARGET_PLATFORM_HAIKU 12561604e48SAxel Dörfler fSettings.map.button[0] = B_PRIMARY_MOUSE_BUTTON; 12661604e48SAxel Dörfler fSettings.map.button[1] = B_SECONDARY_MOUSE_BUTTON; 12761604e48SAxel Dörfler fSettings.map.button[2] = B_TERTIARY_MOUSE_BUTTON; 1283aa69c78SStefano Ceccherini #endif 12933efb919SStefano Ceccherini 13061604e48SAxel Dörfler fDeviceRemapsButtons = false; 13161604e48SAxel Dörfler }; 13261d7deeeSJérôme Duval 13361d7deeeSJérôme Duval 13461604e48SAxel Dörfler MouseDevice::~MouseDevice() 13561d7deeeSJérôme Duval { 13661604e48SAxel Dörfler if (fActive) 13761604e48SAxel Dörfler Stop(); 13861d7deeeSJérôme Duval 13961604e48SAxel Dörfler free(fDeviceRef.name); 14061d7deeeSJérôme Duval } 14161d7deeeSJérôme Duval 14261d7deeeSJérôme Duval 14361d7deeeSJérôme Duval status_t 14461604e48SAxel Dörfler MouseDevice::Start() 14553d77642SJérôme Duval { 14661604e48SAxel Dörfler fDevice = open(fPath.String(), O_RDWR); 14761604e48SAxel Dörfler if (fDevice < 0) 14861604e48SAxel Dörfler return errno; 14933efb919SStefano Ceccherini 15061604e48SAxel Dörfler UpdateSettings(); 15133efb919SStefano Ceccherini 15233efb919SStefano Ceccherini char threadName[B_OS_NAME_LENGTH]; 15361604e48SAxel Dörfler snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", fDeviceRef.name); 15433efb919SStefano Ceccherini 15561604e48SAxel Dörfler fThread = spawn_thread(_ThreadFunction, threadName, 15661604e48SAxel Dörfler kMouseThreadPriority, (void *)this); 1574c0af4a8SStefano Ceccherini 15833efb919SStefano Ceccherini status_t status; 15961604e48SAxel Dörfler if (fThread < B_OK) 16061604e48SAxel Dörfler status = fThread; 16161604e48SAxel Dörfler else { 16261604e48SAxel Dörfler fActive = true; 16361604e48SAxel Dörfler status = resume_thread(fThread); 16461604e48SAxel Dörfler } 16533efb919SStefano Ceccherini 16661604e48SAxel Dörfler if (status < B_OK) { 16761604e48SAxel Dörfler LOG_ERR("%s: can't spawn/resume watching thread: %s\n", 16861604e48SAxel Dörfler fDeviceRef.name, strerror(status)); 16961604e48SAxel Dörfler close(fDevice); 17061604e48SAxel Dörfler return status; 17161604e48SAxel Dörfler } 17261604e48SAxel Dörfler 173c2fbfb71SJérôme Duval return B_OK; 17461d7deeeSJérôme Duval } 17561d7deeeSJérôme Duval 17661d7deeeSJérôme Duval 177c2fbfb71SJérôme Duval void 17861604e48SAxel Dörfler MouseDevice::Stop() 17961604e48SAxel Dörfler { 18061604e48SAxel Dörfler fActive = false; 18161604e48SAxel Dörfler // this will stop the thread as soon as it reads the next packet 18261604e48SAxel Dörfler 18361604e48SAxel Dörfler if (fThread >= B_OK) { 18461604e48SAxel Dörfler // unblock the thread, which might wait on a semaphore. 18561604e48SAxel Dörfler suspend_thread(fThread); 18661604e48SAxel Dörfler resume_thread(fThread); 18761604e48SAxel Dörfler 18861604e48SAxel Dörfler status_t dummy; 18961604e48SAxel Dörfler wait_for_thread(fThread, &dummy); 19061604e48SAxel Dörfler } 19161604e48SAxel Dörfler 19261604e48SAxel Dörfler close(fDevice); 19361604e48SAxel Dörfler } 19461604e48SAxel Dörfler 19561604e48SAxel Dörfler 19642b505fbSAxel Dörfler status_t 19742b505fbSAxel Dörfler MouseDevice::UpdateSettings() 19842b505fbSAxel Dörfler { 19942b505fbSAxel Dörfler CALLED(); 20042b505fbSAxel Dörfler 20142b505fbSAxel Dörfler // retrieve current values 20242b505fbSAxel Dörfler 20342b505fbSAxel Dörfler if (get_mouse_map(&fSettings.map) != B_OK) 20442b505fbSAxel Dörfler LOG_ERR("error when get_mouse_map\n"); 20542b505fbSAxel Dörfler else 20642b505fbSAxel Dörfler fDeviceRemapsButtons = ioctl(fDevice, MS_SET_MAP, &fSettings.map) == B_OK; 20742b505fbSAxel Dörfler 20842b505fbSAxel Dörfler if (get_click_speed(&fSettings.click_speed) != B_OK) 20942b505fbSAxel Dörfler LOG_ERR("error when get_click_speed\n"); 21042b505fbSAxel Dörfler else 21142b505fbSAxel Dörfler ioctl(fDevice, MS_SET_CLICKSPEED, &fSettings.click_speed); 21242b505fbSAxel Dörfler 21342b505fbSAxel Dörfler if (get_mouse_speed(&fSettings.accel.speed) != B_OK) 21442b505fbSAxel Dörfler LOG_ERR("error when get_mouse_speed\n"); 21542b505fbSAxel Dörfler else { 21642b505fbSAxel Dörfler if (get_mouse_acceleration(&fSettings.accel.accel_factor) != B_OK) 21742b505fbSAxel Dörfler LOG_ERR("error when get_mouse_acceleration\n"); 21842b505fbSAxel Dörfler else { 21942b505fbSAxel Dörfler mouse_accel accel; 22042b505fbSAxel Dörfler ioctl(fDevice, MS_GET_ACCEL, &accel); 22142b505fbSAxel Dörfler accel.speed = fSettings.accel.speed; 22242b505fbSAxel Dörfler accel.accel_factor = fSettings.accel.accel_factor; 22342b505fbSAxel Dörfler ioctl(fDevice, MS_SET_ACCEL, &fSettings.accel); 22442b505fbSAxel Dörfler } 22542b505fbSAxel Dörfler } 22642b505fbSAxel Dörfler 22742b505fbSAxel Dörfler if (get_mouse_type(&fSettings.type) != B_OK) 22842b505fbSAxel Dörfler LOG_ERR("error when get_mouse_type\n"); 22942b505fbSAxel Dörfler else 23042b505fbSAxel Dörfler ioctl(fDevice, MS_SET_TYPE, &fSettings.type); 23142b505fbSAxel Dörfler 23242b505fbSAxel Dörfler return B_OK; 23342b505fbSAxel Dörfler 23442b505fbSAxel Dörfler } 23542b505fbSAxel Dörfler 23642b505fbSAxel Dörfler 23761604e48SAxel Dörfler void 23861604e48SAxel Dörfler MouseDevice::_Run() 23961604e48SAxel Dörfler { 24061604e48SAxel Dörfler uint32 lastButtons = 0; 24161604e48SAxel Dörfler 24261604e48SAxel Dörfler while (fActive) { 24361604e48SAxel Dörfler mouse_movement movements; 24461604e48SAxel Dörfler memset(&movements, 0, sizeof(movements)); 24561604e48SAxel Dörfler 24661604e48SAxel Dörfler if (ioctl(fDevice, MS_READ, &movements) != B_OK) 24761604e48SAxel Dörfler return; 24861604e48SAxel Dörfler 24961604e48SAxel Dörfler uint32 buttons = lastButtons ^ movements.buttons; 25061604e48SAxel Dörfler 25161604e48SAxel Dörfler uint32 remappedButtons = _RemapButtons(movements.buttons); 25261604e48SAxel Dörfler int32 deltaX, deltaY; 25361604e48SAxel Dörfler _ComputeAcceleration(movements, deltaX, deltaY); 25461604e48SAxel Dörfler 25561604e48SAxel Dörfler LOG("%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld, wheel_x:%ld, wheel_y:%ld\n", 25661604e48SAxel Dörfler device->device_ref.name, movements.buttons, movements.xdelta, movements.ydelta, 25761604e48SAxel Dörfler movements.clicks, movements.wheel_xdelta, movements.wheel_ydelta); 25861604e48SAxel Dörfler LOG("%s: x: %ld, y: %ld\n", device->device_ref.name, deltaX, deltaY); 25961604e48SAxel Dörfler 26061604e48SAxel Dörfler BMessage *message = NULL; 26161604e48SAxel Dörfler 26261604e48SAxel Dörfler // Send single messages for each event 26361604e48SAxel Dörfler 26461604e48SAxel Dörfler if (movements.xdelta != 0 || movements.ydelta != 0) { 26561604e48SAxel Dörfler BMessage* message = _BuildMouseMessage(B_MOUSE_MOVED, movements.timestamp, 26661604e48SAxel Dörfler remappedButtons, deltaX, deltaY); 26761604e48SAxel Dörfler if (message != NULL) 26861604e48SAxel Dörfler fTarget.EnqueueMessage(message); 26961604e48SAxel Dörfler } 27061604e48SAxel Dörfler 27161604e48SAxel Dörfler if (buttons != 0) { 27261604e48SAxel Dörfler bool pressedButton = (buttons & movements.buttons) > 0; 27361604e48SAxel Dörfler BMessage* message = _BuildMouseMessage( 27461604e48SAxel Dörfler pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP, 27561604e48SAxel Dörfler movements.timestamp, remappedButtons, deltaX, deltaY); 27661604e48SAxel Dörfler if (message != NULL) { 27761604e48SAxel Dörfler if (pressedButton) { 27861604e48SAxel Dörfler message->AddInt32("clicks", movements.clicks); 27961604e48SAxel Dörfler LOG("B_MOUSE_DOWN\n"); 28061604e48SAxel Dörfler } else 28161604e48SAxel Dörfler LOG("B_MOUSE_UP\n"); 28261604e48SAxel Dörfler 28361604e48SAxel Dörfler fTarget.EnqueueMessage(message); 28461604e48SAxel Dörfler lastButtons = movements.buttons; 28561604e48SAxel Dörfler } 28661604e48SAxel Dörfler } 28761604e48SAxel Dörfler 28861604e48SAxel Dörfler if ((movements.wheel_ydelta != 0) || (movements.wheel_xdelta != 0)) { 28961604e48SAxel Dörfler message = new BMessage(B_MOUSE_WHEEL_CHANGED); 29061604e48SAxel Dörfler if (message == NULL) 29161604e48SAxel Dörfler continue; 29261604e48SAxel Dörfler 29361604e48SAxel Dörfler if (message->AddInt64("when", movements.timestamp) == B_OK 29461604e48SAxel Dörfler && message->AddFloat("be:wheel_delta_x", movements.wheel_xdelta) == B_OK 29561604e48SAxel Dörfler && message->AddFloat("be:wheel_delta_y", movements.wheel_ydelta) == B_OK) 29661604e48SAxel Dörfler fTarget.EnqueueMessage(message); 29761604e48SAxel Dörfler else 29861604e48SAxel Dörfler delete message; 29961604e48SAxel Dörfler } 30061604e48SAxel Dörfler } 30161604e48SAxel Dörfler } 30261604e48SAxel Dörfler 30361604e48SAxel Dörfler 30461604e48SAxel Dörfler status_t 30561604e48SAxel Dörfler MouseDevice::_ThreadFunction(void* arg) 30661604e48SAxel Dörfler { 30761604e48SAxel Dörfler MouseDevice* device = (MouseDevice *)arg; 30861604e48SAxel Dörfler device->_Run(); 30961604e48SAxel Dörfler return B_OK; 31061604e48SAxel Dörfler } 31161604e48SAxel Dörfler 31261604e48SAxel Dörfler 31361604e48SAxel Dörfler BMessage* 31461604e48SAxel Dörfler MouseDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, 31561604e48SAxel Dörfler int32 deltaX, int32 deltaY) const 31661604e48SAxel Dörfler { 31761604e48SAxel Dörfler BMessage* message = new BMessage(what); 31861604e48SAxel Dörfler if (message == NULL) 31961604e48SAxel Dörfler return NULL; 32061604e48SAxel Dörfler 32161604e48SAxel Dörfler if (message->AddInt64("when", when) < B_OK 32261604e48SAxel Dörfler || message->AddInt32("buttons", buttons) < B_OK 32361604e48SAxel Dörfler || message->AddInt32("x", deltaX) < B_OK 32461604e48SAxel Dörfler || message->AddInt32("y", deltaY) < B_OK) { 32561604e48SAxel Dörfler delete message; 32661604e48SAxel Dörfler return NULL; 32761604e48SAxel Dörfler } 32861604e48SAxel Dörfler 32961604e48SAxel Dörfler return message; 33061604e48SAxel Dörfler } 33161604e48SAxel Dörfler 33261604e48SAxel Dörfler 33361604e48SAxel Dörfler void 33461604e48SAxel Dörfler MouseDevice::_ComputeAcceleration(const mouse_movement& movements, 33561604e48SAxel Dörfler int32& deltaX, int32& deltaY) const 33661604e48SAxel Dörfler { 33742b505fbSAxel Dörfler // basic mouse speed 33842b505fbSAxel Dörfler deltaX = movements.xdelta * fSettings.accel.speed >> 16; 33942b505fbSAxel Dörfler deltaY = movements.ydelta * fSettings.accel.speed >> 16; 34042b505fbSAxel Dörfler 34142b505fbSAxel Dörfler // acceleration 34242b505fbSAxel Dörfler double acceleration = 1; 34342b505fbSAxel Dörfler if (fSettings.accel.accel_factor) { 344*74ef1621SAxel Dörfler acceleration = 1 + sqrt(deltaX * deltaX + deltaY * deltaY) 345*74ef1621SAxel Dörfler * fSettings.accel.accel_factor / 524288.0; 34642b505fbSAxel Dörfler } 34742b505fbSAxel Dörfler 34842b505fbSAxel Dörfler // make sure that we move at least one pixel (if there was a movement) 34942b505fbSAxel Dörfler if (deltaX > 0) 35042b505fbSAxel Dörfler deltaX = (int32)ceil(deltaX * acceleration); 35142b505fbSAxel Dörfler else 35242b505fbSAxel Dörfler deltaX = (int32)floor(deltaX * acceleration); 35342b505fbSAxel Dörfler 35442b505fbSAxel Dörfler if (deltaY > 0) 35542b505fbSAxel Dörfler deltaY = (int32)ceil(deltaY * acceleration); 35642b505fbSAxel Dörfler else 35742b505fbSAxel Dörfler deltaY = (int32)floor(deltaY * acceleration); 35861604e48SAxel Dörfler } 35961604e48SAxel Dörfler 36033efb919SStefano Ceccherini 36123b47e0bSJérôme Duval uint32 36261604e48SAxel Dörfler MouseDevice::_RemapButtons(uint32 buttons) const 36323b47e0bSJérôme Duval { 36461604e48SAxel Dörfler if (fDeviceRemapsButtons) 36523b47e0bSJérôme Duval return buttons; 36623b47e0bSJérôme Duval 36761604e48SAxel Dörfler uint32 newButtons = 0; 36823b47e0bSJérôme Duval for (int32 i = 0; buttons; i++) { 36923b47e0bSJérôme Duval if (buttons & 0x1) { 37023b47e0bSJérôme Duval #ifdef HAIKU_TARGET_PLATFORM_HAIKU 37161604e48SAxel Dörfler newButtons |= fSettings.map.button[i]; 37223b47e0bSJérôme Duval #else 37323b47e0bSJérôme Duval if (i == 0) 37461604e48SAxel Dörfler newButtons |= fSettings.map.left; 37523b47e0bSJérôme Duval if (i == 1) 37661604e48SAxel Dörfler newButtons |= fSettings.map.right; 37723b47e0bSJérôme Duval if (i == 2) 37861604e48SAxel Dörfler newButtons |= fSettings.map.middle; 37923b47e0bSJérôme Duval #endif 38023b47e0bSJérôme Duval } 38123b47e0bSJérôme Duval buttons >>= 1; 38223b47e0bSJérôme Duval } 38323b47e0bSJérôme Duval 38461604e48SAxel Dörfler return newButtons; 38523b47e0bSJérôme Duval } 38623b47e0bSJérôme Duval 38723b47e0bSJérôme Duval 38861604e48SAxel Dörfler char * 38961604e48SAxel Dörfler MouseDevice::_BuildShortName() const 3904c0af4a8SStefano Ceccherini { 39161604e48SAxel Dörfler BString string(fPath); 39233efb919SStefano Ceccherini BString name; 39333efb919SStefano Ceccherini 39433efb919SStefano Ceccherini int32 slash = string.FindLast("/"); 3957dcdcad2SJérôme Duval string.CopyInto(name, slash + 1, string.Length() - slash); 3967dcdcad2SJérôme Duval int32 index = atoi(name.String()) + 1; 39733efb919SStefano Ceccherini 3987dcdcad2SJérôme Duval int32 previousSlash = string.FindLast("/", slash); 3997dcdcad2SJérôme Duval string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1); 400497d01f0SAxel Dörfler 401497d01f0SAxel Dörfler if (name == "ps2") 402497d01f0SAxel Dörfler name = "PS/2"; 403497d01f0SAxel Dörfler else 404497d01f0SAxel Dörfler name.Capitalize(); 405497d01f0SAxel Dörfler 4067dcdcad2SJérôme Duval name << " Mouse " << index; 40733efb919SStefano Ceccherini 40833efb919SStefano Ceccherini return strdup(name.String()); 40933efb919SStefano Ceccherini } 41061604e48SAxel Dörfler 41161604e48SAxel Dörfler 41261604e48SAxel Dörfler // #pragma mark - 41361604e48SAxel Dörfler 41461604e48SAxel Dörfler 41561604e48SAxel Dörfler MouseInputDevice::MouseInputDevice() 41661604e48SAxel Dörfler { 41761604e48SAxel Dörfler #if DEBUG 41861604e48SAxel Dörfler sLogFile = fopen("/var/log/mouse_device_log.log", "a"); 41961604e48SAxel Dörfler #endif 42061604e48SAxel Dörfler CALLED(); 42161604e48SAxel Dörfler 42261604e48SAxel Dörfler StartMonitoringDevice(kMouseDevicesDirectoryPS2); 42361604e48SAxel Dörfler StartMonitoringDevice(kMouseDevicesDirectoryUSB); 42461604e48SAxel Dörfler 42561604e48SAxel Dörfler _RecursiveScan(kMouseDevicesDirectory); 42661604e48SAxel Dörfler } 42761604e48SAxel Dörfler 42861604e48SAxel Dörfler 42961604e48SAxel Dörfler MouseInputDevice::~MouseInputDevice() 43061604e48SAxel Dörfler { 43161604e48SAxel Dörfler CALLED(); 43261604e48SAxel Dörfler StopMonitoringDevice(kMouseDevicesDirectoryUSB); 43361604e48SAxel Dörfler StopMonitoringDevice(kMouseDevicesDirectoryPS2); 43461604e48SAxel Dörfler 43561604e48SAxel Dörfler int32 count = fDevices.CountItems(); 43661604e48SAxel Dörfler while (count-- > 0) { 43761604e48SAxel Dörfler delete (MouseDevice *)fDevices.RemoveItem(count); 43861604e48SAxel Dörfler } 43961604e48SAxel Dörfler 44061604e48SAxel Dörfler #if DEBUG 44161604e48SAxel Dörfler fclose(sLogFile); 44261604e48SAxel Dörfler #endif 44361604e48SAxel Dörfler } 44461604e48SAxel Dörfler 44561604e48SAxel Dörfler 44661604e48SAxel Dörfler status_t 44761604e48SAxel Dörfler MouseInputDevice::InitCheck() 44861604e48SAxel Dörfler { 44961604e48SAxel Dörfler CALLED(); 45061604e48SAxel Dörfler return B_OK; 45161604e48SAxel Dörfler } 45261604e48SAxel Dörfler 45361604e48SAxel Dörfler 45461604e48SAxel Dörfler status_t 45561604e48SAxel Dörfler MouseInputDevice::Start(const char *name, void *cookie) 45661604e48SAxel Dörfler { 45761604e48SAxel Dörfler LOG("%s(%s)\n", __PRETTY_FUNCTION__, name); 45861604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 45961604e48SAxel Dörfler 46061604e48SAxel Dörfler return device->Start(); 46161604e48SAxel Dörfler } 46261604e48SAxel Dörfler 46361604e48SAxel Dörfler 46461604e48SAxel Dörfler status_t 46561604e48SAxel Dörfler MouseInputDevice::Stop(const char *name, void *cookie) 46661604e48SAxel Dörfler { 46761604e48SAxel Dörfler LOG("%s(%s)\n", __PRETTY_FUNCTION__, name); 46861604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 46961604e48SAxel Dörfler 47061604e48SAxel Dörfler device->Stop(); 47161604e48SAxel Dörfler return B_OK; 47261604e48SAxel Dörfler } 47361604e48SAxel Dörfler 47461604e48SAxel Dörfler 47561604e48SAxel Dörfler status_t 47661604e48SAxel Dörfler MouseInputDevice::Control(const char* name, void* cookie, 47761604e48SAxel Dörfler uint32 command, BMessage* message) 47861604e48SAxel Dörfler { 47961604e48SAxel Dörfler LOG("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command); 48061604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 48161604e48SAxel Dörfler 48261604e48SAxel Dörfler if (command == B_NODE_MONITOR) 48361604e48SAxel Dörfler return _HandleMonitor(message); 48461604e48SAxel Dörfler 48561604e48SAxel Dörfler if (command >= B_MOUSE_TYPE_CHANGED 48661604e48SAxel Dörfler && command <= B_MOUSE_ACCELERATION_CHANGED) 48761604e48SAxel Dörfler return device->UpdateSettings(); 48861604e48SAxel Dörfler 48961604e48SAxel Dörfler return B_BAD_VALUE; 49061604e48SAxel Dörfler } 49161604e48SAxel Dörfler 49261604e48SAxel Dörfler 49361604e48SAxel Dörfler // TODO: Test this. USB doesn't work on my machine 49461604e48SAxel Dörfler status_t 49561604e48SAxel Dörfler MouseInputDevice::_HandleMonitor(BMessage* message) 49661604e48SAxel Dörfler { 49761604e48SAxel Dörfler CALLED(); 49861604e48SAxel Dörfler 49961604e48SAxel Dörfler int32 opcode; 50061604e48SAxel Dörfler if (message->FindInt32("opcode", &opcode) < B_OK) 50161604e48SAxel Dörfler return B_BAD_VALUE; 50261604e48SAxel Dörfler 50361604e48SAxel Dörfler if (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED) 50461604e48SAxel Dörfler return B_OK; 50561604e48SAxel Dörfler 50661604e48SAxel Dörfler BEntry entry; 50761604e48SAxel Dörfler BPath path; 50861604e48SAxel Dörfler dev_t device; 50961604e48SAxel Dörfler ino_t directory; 51061604e48SAxel Dörfler const char *name; 51161604e48SAxel Dörfler 51261604e48SAxel Dörfler if (message->FindInt32("device", &device) < B_OK 51361604e48SAxel Dörfler || message->FindInt64("directory", &directory) < B_OK 51461604e48SAxel Dörfler || message->FindString("name", &name) < B_OK) 51561604e48SAxel Dörfler return B_BAD_VALUE; 51661604e48SAxel Dörfler 51761604e48SAxel Dörfler entry_ref ref(device, directory, name); 51861604e48SAxel Dörfler status_t status; 51961604e48SAxel Dörfler 52061604e48SAxel Dörfler if ((status = entry.SetTo(&ref)) != B_OK) 52161604e48SAxel Dörfler return status; 52261604e48SAxel Dörfler if ((status = entry.GetPath(&path)) != B_OK) 52361604e48SAxel Dörfler return status; 52461604e48SAxel Dörfler if ((status = path.InitCheck()) != B_OK) 52561604e48SAxel Dörfler return status; 52661604e48SAxel Dörfler 52761604e48SAxel Dörfler if (opcode == B_ENTRY_CREATED) 52861604e48SAxel Dörfler status = _AddDevice(path.Path()); 52961604e48SAxel Dörfler else 53061604e48SAxel Dörfler status = _RemoveDevice(path.Path()); 53161604e48SAxel Dörfler 53261604e48SAxel Dörfler return status; 53361604e48SAxel Dörfler } 53461604e48SAxel Dörfler 53561604e48SAxel Dörfler 53661604e48SAxel Dörfler MouseDevice* 53761604e48SAxel Dörfler MouseInputDevice::_FindDevice(const char *path) 53861604e48SAxel Dörfler { 53961604e48SAxel Dörfler CALLED(); 54061604e48SAxel Dörfler 54161604e48SAxel Dörfler for (int32 i = fDevices.CountItems(); i-- > 0;) { 54261604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)fDevices.ItemAt(i); 54361604e48SAxel Dörfler if (!strcmp(device->Path(), path)) 54461604e48SAxel Dörfler return device; 54561604e48SAxel Dörfler } 54661604e48SAxel Dörfler 54761604e48SAxel Dörfler return NULL; 54861604e48SAxel Dörfler } 54961604e48SAxel Dörfler 55061604e48SAxel Dörfler 55161604e48SAxel Dörfler status_t 55261604e48SAxel Dörfler MouseInputDevice::_AddDevice(const char *path) 55361604e48SAxel Dörfler { 55461604e48SAxel Dörfler CALLED(); 55561604e48SAxel Dörfler 55661604e48SAxel Dörfler MouseDevice* device = new (std::nothrow) MouseDevice(*this, path); 55761604e48SAxel Dörfler if (!device) { 55861604e48SAxel Dörfler LOG("No memory\n"); 55961604e48SAxel Dörfler return B_NO_MEMORY; 56061604e48SAxel Dörfler } 56161604e48SAxel Dörfler 56261604e48SAxel Dörfler if (!fDevices.AddItem(device)) { 56361604e48SAxel Dörfler delete device; 56461604e48SAxel Dörfler return B_NO_MEMORY; 56561604e48SAxel Dörfler } 56661604e48SAxel Dörfler 56761604e48SAxel Dörfler input_device_ref *devices[2]; 56861604e48SAxel Dörfler devices[0] = device->DeviceRef(); 56961604e48SAxel Dörfler devices[1] = NULL; 57061604e48SAxel Dörfler 57161604e48SAxel Dörfler return RegisterDevices(devices); 57261604e48SAxel Dörfler } 57361604e48SAxel Dörfler 57461604e48SAxel Dörfler 57561604e48SAxel Dörfler status_t 57661604e48SAxel Dörfler MouseInputDevice::_RemoveDevice(const char *path) 57761604e48SAxel Dörfler { 57861604e48SAxel Dörfler CALLED(); 57961604e48SAxel Dörfler 58061604e48SAxel Dörfler MouseDevice* device = _FindDevice(path); 58161604e48SAxel Dörfler if (device == NULL) 58261604e48SAxel Dörfler return B_ENTRY_NOT_FOUND; 58361604e48SAxel Dörfler 58461604e48SAxel Dörfler fDevices.RemoveItem(device); 58561604e48SAxel Dörfler 58661604e48SAxel Dörfler input_device_ref *devices[2]; 58761604e48SAxel Dörfler devices[0] = device->DeviceRef(); 58861604e48SAxel Dörfler devices[1] = NULL; 58961604e48SAxel Dörfler 59061604e48SAxel Dörfler UnregisterDevices(devices); 59161604e48SAxel Dörfler 59261604e48SAxel Dörfler delete device; 59361604e48SAxel Dörfler return B_OK; 59461604e48SAxel Dörfler } 59561604e48SAxel Dörfler 59661604e48SAxel Dörfler 59761604e48SAxel Dörfler void 59861604e48SAxel Dörfler MouseInputDevice::_RecursiveScan(const char* directory) 59961604e48SAxel Dörfler { 60061604e48SAxel Dörfler CALLED(); 60161604e48SAxel Dörfler 60261604e48SAxel Dörfler BEntry entry; 60361604e48SAxel Dörfler BDirectory dir(directory); 60461604e48SAxel Dörfler while (dir.GetNextEntry(&entry) == B_OK) { 60561604e48SAxel Dörfler BPath path; 60661604e48SAxel Dörfler entry.GetPath(&path); 60761604e48SAxel Dörfler 60861604e48SAxel Dörfler if (!strcmp(path.Leaf(), "serial")) { 60961604e48SAxel Dörfler // skip serial 61061604e48SAxel Dörfler continue; 61161604e48SAxel Dörfler } 61261604e48SAxel Dörfler 61361604e48SAxel Dörfler if (entry.IsDirectory()) 61461604e48SAxel Dörfler _RecursiveScan(path.Path()); 61561604e48SAxel Dörfler else 61661604e48SAxel Dörfler _AddDevice(path.Path()); 61761604e48SAxel Dörfler } 61861604e48SAxel Dörfler } 61961604e48SAxel Dörfler 620