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" 13fc2045eeSJérôme Duval #include "kb_mouse_settings.h" 14fc2045eeSJérôme Duval #include "kb_mouse_driver.h" 1561d7deeeSJérôme Duval 16c2fbfb71SJérôme Duval #include <Debug.h> 1733efb919SStefano Ceccherini #include <Directory.h> 1833efb919SStefano Ceccherini #include <Entry.h> 1933efb919SStefano Ceccherini #include <NodeMonitor.h> 2033efb919SStefano Ceccherini #include <Path.h> 2133efb919SStefano Ceccherini #include <String.h> 2261604e48SAxel Dörfler #include <View.h> 2361604e48SAxel Dörfler 2461604e48SAxel Dörfler #include <errno.h> 2561604e48SAxel Dörfler #include <new> 2661604e48SAxel Dörfler #include <stdio.h> 2761604e48SAxel Dörfler #include <stdlib.h> 2861604e48SAxel Dörfler #include <unistd.h> 2933efb919SStefano Ceccherini 303aa69c78SStefano Ceccherini #if DEBUG 31c2fbfb71SJérôme Duval FILE *MouseInputDevice::sLogFile = NULL; 3261604e48SAxel Dörfler # define LOG_ERR(text...) LOG(text) 333aa69c78SStefano Ceccherini #else 34c2fbfb71SJérôme Duval # define LOG(text...) 35c2fbfb71SJérôme Duval # define LOG_ERR(text...) fprintf(stderr, text) 363aa69c78SStefano Ceccherini #endif 373aa69c78SStefano Ceccherini 38c2fbfb71SJérôme Duval #define CALLED() LOG("%s\n", __PRETTY_FUNCTION__) 3933efb919SStefano Ceccherini 4033efb919SStefano Ceccherini const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4; 4133efb919SStefano Ceccherini const static char *kMouseDevicesDirectory = "/dev/input/mouse"; 4233efb919SStefano Ceccherini 4333efb919SStefano Ceccherini // "/dev/" is automatically prepended by StartMonitoringDevice() 44f0bac935SJérôme Duval const static char *kMouseDevicesDirectoryPS2 = "input/mouse/ps2"; 4533efb919SStefano Ceccherini const static char *kMouseDevicesDirectoryUSB = "input/mouse/usb"; 4633efb919SStefano Ceccherini 4761604e48SAxel Dörfler class MouseDevice { 4861604e48SAxel Dörfler public: 4961604e48SAxel Dörfler MouseDevice(BInputServerDevice& target, const char* path); 5061604e48SAxel Dörfler ~MouseDevice(); 5133efb919SStefano Ceccherini 5261604e48SAxel Dörfler status_t Start(); 5361604e48SAxel Dörfler void Stop(); 5461604e48SAxel Dörfler 5561604e48SAxel Dörfler status_t UpdateSettings(); 5661604e48SAxel Dörfler 5761604e48SAxel Dörfler const char* Path() const { return fPath.String(); } 5861604e48SAxel Dörfler input_device_ref* DeviceRef() { return &fDeviceRef; } 5961604e48SAxel Dörfler 6061604e48SAxel Dörfler private: 6161604e48SAxel Dörfler void _Run(); 6261604e48SAxel Dörfler static status_t _ThreadFunction(void *arg); 6361604e48SAxel Dörfler 6461604e48SAxel Dörfler BMessage* _BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, 6561604e48SAxel Dörfler int32 deltaX, int32 deltaY) const; 6661604e48SAxel Dörfler void _ComputeAcceleration(const mouse_movement& movements, 6761604e48SAxel Dörfler int32& deltaX, int32& deltaY) const; 6861604e48SAxel Dörfler uint32 _RemapButtons(uint32 buttons) const; 6961604e48SAxel Dörfler 7061604e48SAxel Dörfler char* _BuildShortName() const; 7161604e48SAxel Dörfler 7261604e48SAxel Dörfler private: 7361604e48SAxel Dörfler BInputServerDevice& fTarget; 7461604e48SAxel Dörfler BString fPath; 7561604e48SAxel Dörfler int fDevice; 7661604e48SAxel Dörfler 7761604e48SAxel Dörfler input_device_ref fDeviceRef; 7861604e48SAxel Dörfler mouse_settings fSettings; 7961604e48SAxel Dörfler bool fDeviceRemapsButtons; 8061604e48SAxel Dörfler 8161604e48SAxel Dörfler thread_id fThread; 8261604e48SAxel Dörfler volatile bool fActive; 830dbc4befSStefano Ceccherini }; 840dbc4befSStefano Ceccherini 850dbc4befSStefano Ceccherini 8661604e48SAxel Dörfler #if DEBUG 8761604e48SAxel Dörfler inline void 8861604e48SAxel Dörfler LOG(const char *fmt, ...) 8961604e48SAxel Dörfler { 9061604e48SAxel Dörfler char buf[1024]; 9161604e48SAxel Dörfler va_list ap; 9261604e48SAxel Dörfler va_start(ap, fmt); 9361604e48SAxel Dörfler vsprintf(buf, fmt, ap); va_end(ap); 9461604e48SAxel Dörfler fputs(buf, MouseInputDevice::sLogFile); fflush(MouseInputDevice::sLogFile); 9561604e48SAxel Dörfler } 9661604e48SAxel Dörfler #endif 974c0af4a8SStefano Ceccherini 984c0af4a8SStefano Ceccherini 9961604e48SAxel Dörfler extern "C" BInputServerDevice * 10061d7deeeSJérôme Duval instantiate_input_device() 10161d7deeeSJérôme Duval { 102d246d9beSStefano Ceccherini return new (std::nothrow) MouseInputDevice(); 10361d7deeeSJérôme Duval } 10461d7deeeSJérôme Duval 10561d7deeeSJérôme Duval 10661604e48SAxel Dörfler // #pragma mark - 10761604e48SAxel Dörfler 10861604e48SAxel Dörfler 10961604e48SAxel Dörfler MouseDevice::MouseDevice(BInputServerDevice& target, const char *driverPath) 11061604e48SAxel Dörfler : 11161604e48SAxel Dörfler fTarget(target), 11261604e48SAxel Dörfler fDevice(-1), 11361604e48SAxel Dörfler fThread(-1), 11461604e48SAxel Dörfler fActive(false) 11561d7deeeSJérôme Duval { 11661604e48SAxel Dörfler fPath = driverPath; 11761604e48SAxel Dörfler 11861604e48SAxel Dörfler fDeviceRef.name = _BuildShortName(); 11961604e48SAxel Dörfler fDeviceRef.type = B_POINTING_DEVICE; 12061604e48SAxel Dörfler fDeviceRef.cookie = this; 12161604e48SAxel Dörfler 12261604e48SAxel Dörfler #ifdef HAIKU_TARGET_PLATFORM_HAIKU 12361604e48SAxel Dörfler fSettings.map.button[0] = B_PRIMARY_MOUSE_BUTTON; 12461604e48SAxel Dörfler fSettings.map.button[1] = B_SECONDARY_MOUSE_BUTTON; 12561604e48SAxel Dörfler fSettings.map.button[2] = B_TERTIARY_MOUSE_BUTTON; 1263aa69c78SStefano Ceccherini #endif 12733efb919SStefano Ceccherini 12861604e48SAxel Dörfler fDeviceRemapsButtons = false; 12961604e48SAxel Dörfler }; 13061d7deeeSJérôme Duval 13161d7deeeSJérôme Duval 13261604e48SAxel Dörfler MouseDevice::~MouseDevice() 13361d7deeeSJérôme Duval { 13461604e48SAxel Dörfler if (fActive) 13561604e48SAxel Dörfler Stop(); 13661d7deeeSJérôme Duval 13761604e48SAxel Dörfler free(fDeviceRef.name); 13861d7deeeSJérôme Duval } 13961d7deeeSJérôme Duval 14061d7deeeSJérôme Duval 14161d7deeeSJérôme Duval status_t 14261604e48SAxel Dörfler MouseDevice::Start() 14353d77642SJérôme Duval { 14461604e48SAxel Dörfler fDevice = open(fPath.String(), O_RDWR); 14561604e48SAxel Dörfler if (fDevice < 0) 14661604e48SAxel Dörfler return errno; 14733efb919SStefano Ceccherini 14861604e48SAxel Dörfler UpdateSettings(); 14933efb919SStefano Ceccherini 15033efb919SStefano Ceccherini char threadName[B_OS_NAME_LENGTH]; 15161604e48SAxel Dörfler snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", fDeviceRef.name); 15233efb919SStefano Ceccherini 15361604e48SAxel Dörfler fThread = spawn_thread(_ThreadFunction, threadName, 15461604e48SAxel Dörfler kMouseThreadPriority, (void *)this); 1554c0af4a8SStefano Ceccherini 15633efb919SStefano Ceccherini status_t status; 15761604e48SAxel Dörfler if (fThread < B_OK) 15861604e48SAxel Dörfler status = fThread; 15961604e48SAxel Dörfler else { 16061604e48SAxel Dörfler fActive = true; 16161604e48SAxel Dörfler status = resume_thread(fThread); 16261604e48SAxel Dörfler } 16333efb919SStefano Ceccherini 16461604e48SAxel Dörfler if (status < B_OK) { 16561604e48SAxel Dörfler LOG_ERR("%s: can't spawn/resume watching thread: %s\n", 16661604e48SAxel Dörfler fDeviceRef.name, strerror(status)); 16761604e48SAxel Dörfler close(fDevice); 16861604e48SAxel Dörfler return status; 16961604e48SAxel Dörfler } 17061604e48SAxel Dörfler 171c2fbfb71SJérôme Duval return B_OK; 17261d7deeeSJérôme Duval } 17361d7deeeSJérôme Duval 17461d7deeeSJérôme Duval 175c2fbfb71SJérôme Duval void 17661604e48SAxel Dörfler MouseDevice::Stop() 17761604e48SAxel Dörfler { 17861604e48SAxel Dörfler fActive = false; 17961604e48SAxel Dörfler // this will stop the thread as soon as it reads the next packet 18061604e48SAxel Dörfler 18161604e48SAxel Dörfler if (fThread >= B_OK) { 18261604e48SAxel Dörfler // unblock the thread, which might wait on a semaphore. 18361604e48SAxel Dörfler suspend_thread(fThread); 18461604e48SAxel Dörfler resume_thread(fThread); 18561604e48SAxel Dörfler 18661604e48SAxel Dörfler status_t dummy; 18761604e48SAxel Dörfler wait_for_thread(fThread, &dummy); 18861604e48SAxel Dörfler } 18961604e48SAxel Dörfler 19061604e48SAxel Dörfler close(fDevice); 19161604e48SAxel Dörfler } 19261604e48SAxel Dörfler 19361604e48SAxel Dörfler 19442b505fbSAxel Dörfler status_t 19542b505fbSAxel Dörfler MouseDevice::UpdateSettings() 19642b505fbSAxel Dörfler { 19742b505fbSAxel Dörfler CALLED(); 19842b505fbSAxel Dörfler 19942b505fbSAxel Dörfler // retrieve current values 20042b505fbSAxel Dörfler 20142b505fbSAxel Dörfler if (get_mouse_map(&fSettings.map) != B_OK) 20242b505fbSAxel Dörfler LOG_ERR("error when get_mouse_map\n"); 20342b505fbSAxel Dörfler else 20442b505fbSAxel Dörfler fDeviceRemapsButtons = ioctl(fDevice, MS_SET_MAP, &fSettings.map) == B_OK; 20542b505fbSAxel Dörfler 20642b505fbSAxel Dörfler if (get_click_speed(&fSettings.click_speed) != B_OK) 20742b505fbSAxel Dörfler LOG_ERR("error when get_click_speed\n"); 20842b505fbSAxel Dörfler else 20942b505fbSAxel Dörfler ioctl(fDevice, MS_SET_CLICKSPEED, &fSettings.click_speed); 21042b505fbSAxel Dörfler 21142b505fbSAxel Dörfler if (get_mouse_speed(&fSettings.accel.speed) != B_OK) 21242b505fbSAxel Dörfler LOG_ERR("error when get_mouse_speed\n"); 21342b505fbSAxel Dörfler else { 21442b505fbSAxel Dörfler if (get_mouse_acceleration(&fSettings.accel.accel_factor) != B_OK) 21542b505fbSAxel Dörfler LOG_ERR("error when get_mouse_acceleration\n"); 21642b505fbSAxel Dörfler else { 21742b505fbSAxel Dörfler mouse_accel accel; 21842b505fbSAxel Dörfler ioctl(fDevice, MS_GET_ACCEL, &accel); 21942b505fbSAxel Dörfler accel.speed = fSettings.accel.speed; 22042b505fbSAxel Dörfler accel.accel_factor = fSettings.accel.accel_factor; 22142b505fbSAxel Dörfler ioctl(fDevice, MS_SET_ACCEL, &fSettings.accel); 22242b505fbSAxel Dörfler } 22342b505fbSAxel Dörfler } 22442b505fbSAxel Dörfler 22542b505fbSAxel Dörfler if (get_mouse_type(&fSettings.type) != B_OK) 22642b505fbSAxel Dörfler LOG_ERR("error when get_mouse_type\n"); 22742b505fbSAxel Dörfler else 22842b505fbSAxel Dörfler ioctl(fDevice, MS_SET_TYPE, &fSettings.type); 22942b505fbSAxel Dörfler 23042b505fbSAxel Dörfler return B_OK; 23142b505fbSAxel Dörfler 23242b505fbSAxel Dörfler } 23342b505fbSAxel Dörfler 23442b505fbSAxel Dörfler 23561604e48SAxel Dörfler void 23661604e48SAxel Dörfler MouseDevice::_Run() 23761604e48SAxel Dörfler { 23861604e48SAxel Dörfler uint32 lastButtons = 0; 23961604e48SAxel Dörfler 24061604e48SAxel Dörfler while (fActive) { 24161604e48SAxel Dörfler mouse_movement movements; 24261604e48SAxel Dörfler memset(&movements, 0, sizeof(movements)); 24361604e48SAxel Dörfler 24461604e48SAxel Dörfler if (ioctl(fDevice, MS_READ, &movements) != B_OK) 24561604e48SAxel Dörfler return; 24661604e48SAxel Dörfler 24761604e48SAxel Dörfler uint32 buttons = lastButtons ^ movements.buttons; 24861604e48SAxel Dörfler 24961604e48SAxel Dörfler uint32 remappedButtons = _RemapButtons(movements.buttons); 25061604e48SAxel Dörfler int32 deltaX, deltaY; 25161604e48SAxel Dörfler _ComputeAcceleration(movements, deltaX, deltaY); 25261604e48SAxel Dörfler 25361604e48SAxel Dörfler LOG("%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld, wheel_x:%ld, wheel_y:%ld\n", 25461604e48SAxel Dörfler device->device_ref.name, movements.buttons, movements.xdelta, movements.ydelta, 25561604e48SAxel Dörfler movements.clicks, movements.wheel_xdelta, movements.wheel_ydelta); 25661604e48SAxel Dörfler LOG("%s: x: %ld, y: %ld\n", device->device_ref.name, deltaX, deltaY); 25761604e48SAxel Dörfler 25861604e48SAxel Dörfler BMessage *message = NULL; 25961604e48SAxel Dörfler 26061604e48SAxel Dörfler // Send single messages for each event 26161604e48SAxel Dörfler 26261604e48SAxel Dörfler if (movements.xdelta != 0 || movements.ydelta != 0) { 26361604e48SAxel Dörfler BMessage* message = _BuildMouseMessage(B_MOUSE_MOVED, movements.timestamp, 26461604e48SAxel Dörfler remappedButtons, deltaX, deltaY); 26561604e48SAxel Dörfler if (message != NULL) 26661604e48SAxel Dörfler fTarget.EnqueueMessage(message); 26761604e48SAxel Dörfler } 26861604e48SAxel Dörfler 26961604e48SAxel Dörfler if (buttons != 0) { 27061604e48SAxel Dörfler bool pressedButton = (buttons & movements.buttons) > 0; 27161604e48SAxel Dörfler BMessage* message = _BuildMouseMessage( 27261604e48SAxel Dörfler pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP, 27361604e48SAxel Dörfler movements.timestamp, remappedButtons, deltaX, deltaY); 27461604e48SAxel Dörfler if (message != NULL) { 27561604e48SAxel Dörfler if (pressedButton) { 27661604e48SAxel Dörfler message->AddInt32("clicks", movements.clicks); 27761604e48SAxel Dörfler LOG("B_MOUSE_DOWN\n"); 27861604e48SAxel Dörfler } else 27961604e48SAxel Dörfler LOG("B_MOUSE_UP\n"); 28061604e48SAxel Dörfler 28161604e48SAxel Dörfler fTarget.EnqueueMessage(message); 28261604e48SAxel Dörfler lastButtons = movements.buttons; 28361604e48SAxel Dörfler } 28461604e48SAxel Dörfler } 28561604e48SAxel Dörfler 28661604e48SAxel Dörfler if ((movements.wheel_ydelta != 0) || (movements.wheel_xdelta != 0)) { 28761604e48SAxel Dörfler message = new BMessage(B_MOUSE_WHEEL_CHANGED); 28861604e48SAxel Dörfler if (message == NULL) 28961604e48SAxel Dörfler continue; 29061604e48SAxel Dörfler 29161604e48SAxel Dörfler if (message->AddInt64("when", movements.timestamp) == B_OK 29261604e48SAxel Dörfler && message->AddFloat("be:wheel_delta_x", movements.wheel_xdelta) == B_OK 29361604e48SAxel Dörfler && message->AddFloat("be:wheel_delta_y", movements.wheel_ydelta) == B_OK) 29461604e48SAxel Dörfler fTarget.EnqueueMessage(message); 29561604e48SAxel Dörfler else 29661604e48SAxel Dörfler delete message; 29761604e48SAxel Dörfler } 29861604e48SAxel Dörfler } 29961604e48SAxel Dörfler } 30061604e48SAxel Dörfler 30161604e48SAxel Dörfler 30261604e48SAxel Dörfler status_t 30361604e48SAxel Dörfler MouseDevice::_ThreadFunction(void* arg) 30461604e48SAxel Dörfler { 30561604e48SAxel Dörfler MouseDevice* device = (MouseDevice *)arg; 30661604e48SAxel Dörfler device->_Run(); 30761604e48SAxel Dörfler return B_OK; 30861604e48SAxel Dörfler } 30961604e48SAxel Dörfler 31061604e48SAxel Dörfler 31161604e48SAxel Dörfler BMessage* 31261604e48SAxel Dörfler MouseDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, 31361604e48SAxel Dörfler int32 deltaX, int32 deltaY) const 31461604e48SAxel Dörfler { 31561604e48SAxel Dörfler BMessage* message = new BMessage(what); 31661604e48SAxel Dörfler if (message == NULL) 31761604e48SAxel Dörfler return NULL; 31861604e48SAxel Dörfler 31961604e48SAxel Dörfler if (message->AddInt64("when", when) < B_OK 32061604e48SAxel Dörfler || message->AddInt32("buttons", buttons) < B_OK 32161604e48SAxel Dörfler || message->AddInt32("x", deltaX) < B_OK 32261604e48SAxel Dörfler || message->AddInt32("y", deltaY) < B_OK) { 32361604e48SAxel Dörfler delete message; 32461604e48SAxel Dörfler return NULL; 32561604e48SAxel Dörfler } 32661604e48SAxel Dörfler 32761604e48SAxel Dörfler return message; 32861604e48SAxel Dörfler } 32961604e48SAxel Dörfler 33061604e48SAxel Dörfler 33161604e48SAxel Dörfler void 33261604e48SAxel Dörfler MouseDevice::_ComputeAcceleration(const mouse_movement& movements, 33361604e48SAxel Dörfler int32& deltaX, int32& deltaY) const 33461604e48SAxel Dörfler { 33542b505fbSAxel Dörfler // basic mouse speed 33642b505fbSAxel Dörfler deltaX = movements.xdelta * fSettings.accel.speed >> 16; 33742b505fbSAxel Dörfler deltaY = movements.ydelta * fSettings.accel.speed >> 16; 33842b505fbSAxel Dörfler 33942b505fbSAxel Dörfler // acceleration 34042b505fbSAxel Dörfler double acceleration = 1; 34142b505fbSAxel Dörfler if (fSettings.accel.accel_factor) { 342fafab827SAxel Dörfler acceleration = 1 + sqrt(deltaX * deltaX + deltaY * deltaY) 34374ef1621SAxel Dörfler * fSettings.accel.accel_factor / 524288.0; 34442b505fbSAxel Dörfler } 34542b505fbSAxel Dörfler 34642b505fbSAxel Dörfler // make sure that we move at least one pixel (if there was a movement) 34742b505fbSAxel Dörfler if (deltaX > 0) 34842b505fbSAxel Dörfler deltaX = (int32)floor(deltaX * acceleration); 349fafab827SAxel Dörfler else 350fafab827SAxel Dörfler deltaX = (int32)ceil(deltaX * acceleration); 35142b505fbSAxel Dörfler 35242b505fbSAxel Dörfler if (deltaY > 0) 35342b505fbSAxel Dörfler deltaY = (int32)floor(deltaY * acceleration); 354fafab827SAxel Dörfler else 355fafab827SAxel Dörfler deltaY = (int32)ceil(deltaY * acceleration); 35661604e48SAxel Dörfler } 35761604e48SAxel Dörfler 35833efb919SStefano Ceccherini 35923b47e0bSJérôme Duval uint32 36061604e48SAxel Dörfler MouseDevice::_RemapButtons(uint32 buttons) const 36123b47e0bSJérôme Duval { 36261604e48SAxel Dörfler if (fDeviceRemapsButtons) 36323b47e0bSJérôme Duval return buttons; 36423b47e0bSJérôme Duval 36561604e48SAxel Dörfler uint32 newButtons = 0; 36623b47e0bSJérôme Duval for (int32 i = 0; buttons; i++) { 36723b47e0bSJérôme Duval if (buttons & 0x1) { 368*21631085SStephan Aßmus #if defined(HAIKU_TARGET_PLATFORM_HAIKU) || defined(HAIKU_TARGET_PLATFORM_DANO) 36961604e48SAxel Dörfler newButtons |= fSettings.map.button[i]; 37023b47e0bSJérôme Duval #else 37123b47e0bSJérôme Duval if (i == 0) 37261604e48SAxel Dörfler newButtons |= fSettings.map.left; 37323b47e0bSJérôme Duval if (i == 1) 37461604e48SAxel Dörfler newButtons |= fSettings.map.right; 37523b47e0bSJérôme Duval if (i == 2) 37661604e48SAxel Dörfler newButtons |= fSettings.map.middle; 37723b47e0bSJérôme Duval #endif 37823b47e0bSJérôme Duval } 37923b47e0bSJérôme Duval buttons >>= 1; 38023b47e0bSJérôme Duval } 38123b47e0bSJérôme Duval 38261604e48SAxel Dörfler return newButtons; 38323b47e0bSJérôme Duval } 38423b47e0bSJérôme Duval 38523b47e0bSJérôme Duval 38661604e48SAxel Dörfler char * 38761604e48SAxel Dörfler MouseDevice::_BuildShortName() const 3884c0af4a8SStefano Ceccherini { 38961604e48SAxel Dörfler BString string(fPath); 39033efb919SStefano Ceccherini BString name; 39133efb919SStefano Ceccherini 39233efb919SStefano Ceccherini int32 slash = string.FindLast("/"); 3937dcdcad2SJérôme Duval string.CopyInto(name, slash + 1, string.Length() - slash); 3947dcdcad2SJérôme Duval int32 index = atoi(name.String()) + 1; 39533efb919SStefano Ceccherini 3967dcdcad2SJérôme Duval int32 previousSlash = string.FindLast("/", slash); 3977dcdcad2SJérôme Duval string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1); 398497d01f0SAxel Dörfler 399497d01f0SAxel Dörfler if (name == "ps2") 400497d01f0SAxel Dörfler name = "PS/2"; 401497d01f0SAxel Dörfler else 402497d01f0SAxel Dörfler name.Capitalize(); 403497d01f0SAxel Dörfler 4047dcdcad2SJérôme Duval name << " Mouse " << index; 40533efb919SStefano Ceccherini 40633efb919SStefano Ceccherini return strdup(name.String()); 40733efb919SStefano Ceccherini } 40861604e48SAxel Dörfler 40961604e48SAxel Dörfler 41061604e48SAxel Dörfler // #pragma mark - 41161604e48SAxel Dörfler 41261604e48SAxel Dörfler 41361604e48SAxel Dörfler MouseInputDevice::MouseInputDevice() 41461604e48SAxel Dörfler { 41561604e48SAxel Dörfler #if DEBUG 41661604e48SAxel Dörfler sLogFile = fopen("/var/log/mouse_device_log.log", "a"); 41761604e48SAxel Dörfler #endif 41861604e48SAxel Dörfler CALLED(); 41961604e48SAxel Dörfler 42061604e48SAxel Dörfler StartMonitoringDevice(kMouseDevicesDirectoryPS2); 42161604e48SAxel Dörfler StartMonitoringDevice(kMouseDevicesDirectoryUSB); 42261604e48SAxel Dörfler 42361604e48SAxel Dörfler _RecursiveScan(kMouseDevicesDirectory); 42461604e48SAxel Dörfler } 42561604e48SAxel Dörfler 42661604e48SAxel Dörfler 42761604e48SAxel Dörfler MouseInputDevice::~MouseInputDevice() 42861604e48SAxel Dörfler { 42961604e48SAxel Dörfler CALLED(); 43061604e48SAxel Dörfler StopMonitoringDevice(kMouseDevicesDirectoryUSB); 43161604e48SAxel Dörfler StopMonitoringDevice(kMouseDevicesDirectoryPS2); 43261604e48SAxel Dörfler 43361604e48SAxel Dörfler int32 count = fDevices.CountItems(); 43461604e48SAxel Dörfler while (count-- > 0) { 43561604e48SAxel Dörfler delete (MouseDevice *)fDevices.RemoveItem(count); 43661604e48SAxel Dörfler } 43761604e48SAxel Dörfler 43861604e48SAxel Dörfler #if DEBUG 43961604e48SAxel Dörfler fclose(sLogFile); 44061604e48SAxel Dörfler #endif 44161604e48SAxel Dörfler } 44261604e48SAxel Dörfler 44361604e48SAxel Dörfler 44461604e48SAxel Dörfler status_t 44561604e48SAxel Dörfler MouseInputDevice::InitCheck() 44661604e48SAxel Dörfler { 44761604e48SAxel Dörfler CALLED(); 448d246d9beSStefano Ceccherini return BInputServerDevice::InitCheck(); 44961604e48SAxel Dörfler } 45061604e48SAxel Dörfler 45161604e48SAxel Dörfler 45261604e48SAxel Dörfler status_t 45361604e48SAxel Dörfler MouseInputDevice::Start(const char *name, void *cookie) 45461604e48SAxel Dörfler { 45561604e48SAxel Dörfler LOG("%s(%s)\n", __PRETTY_FUNCTION__, name); 45661604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 45761604e48SAxel Dörfler 45861604e48SAxel Dörfler return device->Start(); 45961604e48SAxel Dörfler } 46061604e48SAxel Dörfler 46161604e48SAxel Dörfler 46261604e48SAxel Dörfler status_t 46361604e48SAxel Dörfler MouseInputDevice::Stop(const char *name, void *cookie) 46461604e48SAxel Dörfler { 46561604e48SAxel Dörfler LOG("%s(%s)\n", __PRETTY_FUNCTION__, name); 46661604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 46761604e48SAxel Dörfler 46861604e48SAxel Dörfler device->Stop(); 46961604e48SAxel Dörfler return B_OK; 47061604e48SAxel Dörfler } 47161604e48SAxel Dörfler 47261604e48SAxel Dörfler 47361604e48SAxel Dörfler status_t 47461604e48SAxel Dörfler MouseInputDevice::Control(const char* name, void* cookie, 47561604e48SAxel Dörfler uint32 command, BMessage* message) 47661604e48SAxel Dörfler { 47761604e48SAxel Dörfler LOG("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command); 47861604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie; 47961604e48SAxel Dörfler 48061604e48SAxel Dörfler if (command == B_NODE_MONITOR) 48161604e48SAxel Dörfler return _HandleMonitor(message); 48261604e48SAxel Dörfler 48361604e48SAxel Dörfler if (command >= B_MOUSE_TYPE_CHANGED 48461604e48SAxel Dörfler && command <= B_MOUSE_ACCELERATION_CHANGED) 48561604e48SAxel Dörfler return device->UpdateSettings(); 48661604e48SAxel Dörfler 48761604e48SAxel Dörfler return B_BAD_VALUE; 48861604e48SAxel Dörfler } 48961604e48SAxel Dörfler 49061604e48SAxel Dörfler 49161604e48SAxel Dörfler // TODO: Test this. USB doesn't work on my machine 49261604e48SAxel Dörfler status_t 49361604e48SAxel Dörfler MouseInputDevice::_HandleMonitor(BMessage* message) 49461604e48SAxel Dörfler { 49561604e48SAxel Dörfler CALLED(); 49661604e48SAxel Dörfler 49761604e48SAxel Dörfler int32 opcode; 49861604e48SAxel Dörfler if (message->FindInt32("opcode", &opcode) < B_OK) 49961604e48SAxel Dörfler return B_BAD_VALUE; 50061604e48SAxel Dörfler 50161604e48SAxel Dörfler if (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED) 50261604e48SAxel Dörfler return B_OK; 50361604e48SAxel Dörfler 50461604e48SAxel Dörfler BEntry entry; 50561604e48SAxel Dörfler BPath path; 50661604e48SAxel Dörfler dev_t device; 50761604e48SAxel Dörfler ino_t directory; 50861604e48SAxel Dörfler const char *name; 50961604e48SAxel Dörfler 51061604e48SAxel Dörfler if (message->FindInt32("device", &device) < B_OK 51161604e48SAxel Dörfler || message->FindInt64("directory", &directory) < B_OK 51261604e48SAxel Dörfler || message->FindString("name", &name) < B_OK) 51361604e48SAxel Dörfler return B_BAD_VALUE; 51461604e48SAxel Dörfler 51561604e48SAxel Dörfler entry_ref ref(device, directory, name); 51661604e48SAxel Dörfler status_t status; 51761604e48SAxel Dörfler 51861604e48SAxel Dörfler if ((status = entry.SetTo(&ref)) != B_OK) 51961604e48SAxel Dörfler return status; 52061604e48SAxel Dörfler if ((status = entry.GetPath(&path)) != B_OK) 52161604e48SAxel Dörfler return status; 52261604e48SAxel Dörfler if ((status = path.InitCheck()) != B_OK) 52361604e48SAxel Dörfler return status; 52461604e48SAxel Dörfler 52561604e48SAxel Dörfler if (opcode == B_ENTRY_CREATED) 52661604e48SAxel Dörfler status = _AddDevice(path.Path()); 52761604e48SAxel Dörfler else 52861604e48SAxel Dörfler status = _RemoveDevice(path.Path()); 52961604e48SAxel Dörfler 53061604e48SAxel Dörfler return status; 53161604e48SAxel Dörfler } 53261604e48SAxel Dörfler 53361604e48SAxel Dörfler 53461604e48SAxel Dörfler MouseDevice* 53561604e48SAxel Dörfler MouseInputDevice::_FindDevice(const char *path) 53661604e48SAxel Dörfler { 53761604e48SAxel Dörfler CALLED(); 53861604e48SAxel Dörfler 53961604e48SAxel Dörfler for (int32 i = fDevices.CountItems(); i-- > 0;) { 54061604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)fDevices.ItemAt(i); 54161604e48SAxel Dörfler if (!strcmp(device->Path(), path)) 54261604e48SAxel Dörfler return device; 54361604e48SAxel Dörfler } 54461604e48SAxel Dörfler 54561604e48SAxel Dörfler return NULL; 54661604e48SAxel Dörfler } 54761604e48SAxel Dörfler 54861604e48SAxel Dörfler 54961604e48SAxel Dörfler status_t 55061604e48SAxel Dörfler MouseInputDevice::_AddDevice(const char *path) 55161604e48SAxel Dörfler { 55261604e48SAxel Dörfler CALLED(); 55361604e48SAxel Dörfler 55461604e48SAxel Dörfler MouseDevice* device = new (std::nothrow) MouseDevice(*this, path); 55561604e48SAxel Dörfler if (!device) { 55661604e48SAxel Dörfler LOG("No memory\n"); 55761604e48SAxel Dörfler return B_NO_MEMORY; 55861604e48SAxel Dörfler } 55961604e48SAxel Dörfler 56061604e48SAxel Dörfler if (!fDevices.AddItem(device)) { 56161604e48SAxel Dörfler delete device; 56261604e48SAxel Dörfler return B_NO_MEMORY; 56361604e48SAxel Dörfler } 56461604e48SAxel Dörfler 56561604e48SAxel Dörfler input_device_ref *devices[2]; 56661604e48SAxel Dörfler devices[0] = device->DeviceRef(); 56761604e48SAxel Dörfler devices[1] = NULL; 56861604e48SAxel Dörfler 56961604e48SAxel Dörfler return RegisterDevices(devices); 57061604e48SAxel Dörfler } 57161604e48SAxel Dörfler 57261604e48SAxel Dörfler 57361604e48SAxel Dörfler status_t 57461604e48SAxel Dörfler MouseInputDevice::_RemoveDevice(const char *path) 57561604e48SAxel Dörfler { 57661604e48SAxel Dörfler CALLED(); 57761604e48SAxel Dörfler 57861604e48SAxel Dörfler MouseDevice* device = _FindDevice(path); 57961604e48SAxel Dörfler if (device == NULL) 58061604e48SAxel Dörfler return B_ENTRY_NOT_FOUND; 58161604e48SAxel Dörfler 58261604e48SAxel Dörfler fDevices.RemoveItem(device); 58361604e48SAxel Dörfler 58461604e48SAxel Dörfler input_device_ref *devices[2]; 58561604e48SAxel Dörfler devices[0] = device->DeviceRef(); 58661604e48SAxel Dörfler devices[1] = NULL; 58761604e48SAxel Dörfler 58861604e48SAxel Dörfler UnregisterDevices(devices); 58961604e48SAxel Dörfler 59061604e48SAxel Dörfler delete device; 59161604e48SAxel Dörfler return B_OK; 59261604e48SAxel Dörfler } 59361604e48SAxel Dörfler 59461604e48SAxel Dörfler 59561604e48SAxel Dörfler void 59661604e48SAxel Dörfler MouseInputDevice::_RecursiveScan(const char* directory) 59761604e48SAxel Dörfler { 59861604e48SAxel Dörfler CALLED(); 59961604e48SAxel Dörfler 60061604e48SAxel Dörfler BEntry entry; 60161604e48SAxel Dörfler BDirectory dir(directory); 60261604e48SAxel Dörfler while (dir.GetNextEntry(&entry) == B_OK) { 60361604e48SAxel Dörfler BPath path; 60461604e48SAxel Dörfler entry.GetPath(&path); 60561604e48SAxel Dörfler 60661604e48SAxel Dörfler if (!strcmp(path.Leaf(), "serial")) { 60761604e48SAxel Dörfler // skip serial 60861604e48SAxel Dörfler continue; 60961604e48SAxel Dörfler } 61061604e48SAxel Dörfler 61161604e48SAxel Dörfler if (entry.IsDirectory()) 61261604e48SAxel Dörfler _RecursiveScan(path.Path()); 61361604e48SAxel Dörfler else 61461604e48SAxel Dörfler _AddDevice(path.Path()); 61561604e48SAxel Dörfler } 61661604e48SAxel Dörfler } 61761604e48SAxel Dörfler 618