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