xref: /haiku/src/add-ons/input_server/devices/mouse/MouseInputDevice.cpp (revision 216310852f51c5183d2312ae899710559ae17cbd)
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