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