xref: /haiku/src/add-ons/input_server/devices/mouse/MouseInputDevice.cpp (revision c5555ad3c04e295fccf9600cb0aa6eb45eadfbf5)
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"
13b6a7b204SAxel Dörfler 
14b6a7b204SAxel Dörfler #include <errno.h>
15b6a7b204SAxel Dörfler #include <new>
16b6a7b204SAxel Dörfler #include <stdio.h>
17b6a7b204SAxel Dörfler #include <stdlib.h>
18b6a7b204SAxel Dörfler #include <unistd.h>
1961d7deeeSJérôme Duval 
20c2fbfb71SJérôme Duval #include <Debug.h>
2133efb919SStefano Ceccherini #include <Directory.h>
2233efb919SStefano Ceccherini #include <Entry.h>
2333efb919SStefano Ceccherini #include <NodeMonitor.h>
2433efb919SStefano Ceccherini #include <Path.h>
2533efb919SStefano Ceccherini #include <String.h>
2661604e48SAxel Dörfler #include <View.h>
2761604e48SAxel Dörfler 
28b6a7b204SAxel Dörfler #include "kb_mouse_settings.h"
29b6a7b204SAxel Dörfler #include "kb_mouse_driver.h"
3033efb919SStefano Ceccherini 
31b6a7b204SAxel Dörfler 
32b6a7b204SAxel Dörfler //#define TRACE_MOUSE_DEVICE
33b6a7b204SAxel Dörfler #ifdef TRACE_MOUSE_DEVICE
34b6a7b204SAxel Dörfler #	define LOG(text...) debug_printf(text)
3561604e48SAxel Dörfler #	define LOG_ERR(text...) LOG(text)
363aa69c78SStefano Ceccherini #else
37b6a7b204SAxel Dörfler #	define LOG(text...) do {} while (0)
38b6a7b204SAxel Dörfler #	define LOG_ERR(text...) debug_printf(text)
393aa69c78SStefano Ceccherini #endif
403aa69c78SStefano Ceccherini 
41*c5555ad3SStephan Aßmus //#define LOG_DEVICES(text...) debug_printf(text)
42*c5555ad3SStephan Aßmus #define LOG_DEVICES(text...) LOG(text)
43*c5555ad3SStephan Aßmus 
44c2fbfb71SJérôme Duval #define CALLED() LOG("%s\n", __PRETTY_FUNCTION__)
4533efb919SStefano Ceccherini 
46b6a7b204SAxel Dörfler 
47*c5555ad3SStephan Aßmus 
4833efb919SStefano Ceccherini const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4;
4933efb919SStefano Ceccherini const static char* kMouseDevicesDirectory = "/dev/input/mouse";
5033efb919SStefano Ceccherini 
5133efb919SStefano Ceccherini 
5261604e48SAxel Dörfler class MouseDevice {
5361604e48SAxel Dörfler 	public:
54*c5555ad3SStephan Aßmus 		MouseDevice(MouseInputDevice& target, const char* path);
5561604e48SAxel Dörfler 		~MouseDevice();
5633efb919SStefano Ceccherini 
5761604e48SAxel Dörfler 		status_t Start();
5861604e48SAxel Dörfler 		void Stop();
5961604e48SAxel Dörfler 
6061604e48SAxel Dörfler 		status_t UpdateSettings();
6161604e48SAxel Dörfler 
6261604e48SAxel Dörfler 		const char* Path() const { return fPath.String(); }
6361604e48SAxel Dörfler 		input_device_ref* DeviceRef() { return &fDeviceRef; }
6461604e48SAxel Dörfler 
6561604e48SAxel Dörfler 	private:
6661604e48SAxel Dörfler 		void _Run();
6761604e48SAxel Dörfler 		static status_t _ThreadFunction(void* arg);
6861604e48SAxel Dörfler 
6961604e48SAxel Dörfler 		BMessage* _BuildMouseMessage(uint32 what, uint64 when, uint32 buttons,
7061604e48SAxel Dörfler 					int32 deltaX, int32 deltaY) const;
7161604e48SAxel Dörfler 		void _ComputeAcceleration(const mouse_movement& movements,
7261604e48SAxel Dörfler 					int32& deltaX, int32& deltaY) const;
7361604e48SAxel Dörfler 		uint32 _RemapButtons(uint32 buttons) const;
7461604e48SAxel Dörfler 
7561604e48SAxel Dörfler 		char* _BuildShortName() const;
7661604e48SAxel Dörfler 
7761604e48SAxel Dörfler 	private:
78*c5555ad3SStephan Aßmus 		MouseInputDevice&	fTarget;
7961604e48SAxel Dörfler 		BString				fPath;
8061604e48SAxel Dörfler 		int					fDevice;
8161604e48SAxel Dörfler 
8261604e48SAxel Dörfler 		input_device_ref	fDeviceRef;
8361604e48SAxel Dörfler 		mouse_settings		fSettings;
8461604e48SAxel Dörfler 		bool				fDeviceRemapsButtons;
8561604e48SAxel Dörfler 
8661604e48SAxel Dörfler 		thread_id			fThread;
8761604e48SAxel Dörfler 		volatile bool		fActive;
880dbc4befSStefano Ceccherini };
890dbc4befSStefano Ceccherini 
900dbc4befSStefano Ceccherini 
9161604e48SAxel Dörfler extern "C" BInputServerDevice*
9261d7deeeSJérôme Duval instantiate_input_device()
9361d7deeeSJérôme Duval {
94d246d9beSStefano Ceccherini 	return new(std::nothrow) MouseInputDevice();
9561d7deeeSJérôme Duval }
9661d7deeeSJérôme Duval 
9761d7deeeSJérôme Duval 
9861604e48SAxel Dörfler //	#pragma mark -
9961604e48SAxel Dörfler 
10061604e48SAxel Dörfler 
101*c5555ad3SStephan Aßmus MouseDevice::MouseDevice(MouseInputDevice& target, const char* driverPath)
10261604e48SAxel Dörfler 	:
10361604e48SAxel Dörfler 	fTarget(target),
104*c5555ad3SStephan Aßmus 	fPath(driverPath),
10561604e48SAxel Dörfler 	fDevice(-1),
10661604e48SAxel Dörfler 	fThread(-1),
10761604e48SAxel Dörfler 	fActive(false)
10861d7deeeSJérôme Duval {
10961604e48SAxel Dörfler 	fDeviceRef.name = _BuildShortName();
11061604e48SAxel Dörfler 	fDeviceRef.type = B_POINTING_DEVICE;
11161604e48SAxel Dörfler 	fDeviceRef.cookie = this;
11261604e48SAxel Dörfler 
11361604e48SAxel Dörfler #ifdef HAIKU_TARGET_PLATFORM_HAIKU
11461604e48SAxel Dörfler 	fSettings.map.button[0] = B_PRIMARY_MOUSE_BUTTON;
11561604e48SAxel Dörfler 	fSettings.map.button[1] = B_SECONDARY_MOUSE_BUTTON;
11661604e48SAxel Dörfler 	fSettings.map.button[2] = B_TERTIARY_MOUSE_BUTTON;
1173aa69c78SStefano Ceccherini #endif
11833efb919SStefano Ceccherini 
11961604e48SAxel Dörfler 	fDeviceRemapsButtons = false;
12061604e48SAxel Dörfler };
12161d7deeeSJérôme Duval 
12261d7deeeSJérôme Duval 
12361604e48SAxel Dörfler MouseDevice::~MouseDevice()
12461d7deeeSJérôme Duval {
12561604e48SAxel Dörfler 	if (fActive)
12661604e48SAxel Dörfler 		Stop();
12761d7deeeSJérôme Duval 
12861604e48SAxel Dörfler 	free(fDeviceRef.name);
12961d7deeeSJérôme Duval }
13061d7deeeSJérôme Duval 
13161d7deeeSJérôme Duval 
13261d7deeeSJérôme Duval status_t
13361604e48SAxel Dörfler MouseDevice::Start()
13453d77642SJérôme Duval {
13561604e48SAxel Dörfler 	fDevice = open(fPath.String(), O_RDWR);
13661604e48SAxel Dörfler 	if (fDevice < 0)
13761604e48SAxel Dörfler 		return errno;
13833efb919SStefano Ceccherini 
13961604e48SAxel Dörfler 	UpdateSettings();
14033efb919SStefano Ceccherini 
14133efb919SStefano Ceccherini 	char threadName[B_OS_NAME_LENGTH];
14261604e48SAxel Dörfler 	snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", fDeviceRef.name);
14333efb919SStefano Ceccherini 
14461604e48SAxel Dörfler 	fThread = spawn_thread(_ThreadFunction, threadName,
14561604e48SAxel Dörfler 		kMouseThreadPriority, (void*)this);
1464c0af4a8SStefano Ceccherini 
14733efb919SStefano Ceccherini 	status_t status;
14861604e48SAxel Dörfler 	if (fThread < B_OK)
14961604e48SAxel Dörfler 		status = fThread;
15061604e48SAxel Dörfler 	else {
15161604e48SAxel Dörfler 		fActive = true;
15261604e48SAxel Dörfler 		status = resume_thread(fThread);
15361604e48SAxel Dörfler 	}
15433efb919SStefano Ceccherini 
15561604e48SAxel Dörfler 	if (status < B_OK) {
15661604e48SAxel Dörfler 		LOG_ERR("%s: can't spawn/resume watching thread: %s\n",
15761604e48SAxel Dörfler 			fDeviceRef.name, strerror(status));
15861604e48SAxel Dörfler 		close(fDevice);
15961604e48SAxel Dörfler 		return status;
16061604e48SAxel Dörfler 	}
16161604e48SAxel Dörfler 
162c2fbfb71SJérôme Duval 	return B_OK;
16361d7deeeSJérôme Duval }
16461d7deeeSJérôme Duval 
16561d7deeeSJérôme Duval 
166c2fbfb71SJérôme Duval void
16761604e48SAxel Dörfler MouseDevice::Stop()
16861604e48SAxel Dörfler {
1691ccc2f2dSJérôme Duval 	close(fDevice);
1701ccc2f2dSJérôme Duval 	fDevice = -1;
1711ccc2f2dSJérôme Duval 
17261604e48SAxel Dörfler 	fActive = false;
17361604e48SAxel Dörfler 		// this will stop the thread as soon as it reads the next packet
17461604e48SAxel Dörfler 
17561604e48SAxel Dörfler 	if (fThread >= B_OK) {
17661604e48SAxel Dörfler 		// unblock the thread, which might wait on a semaphore.
17761604e48SAxel Dörfler 		suspend_thread(fThread);
17861604e48SAxel Dörfler 		resume_thread(fThread);
17961604e48SAxel Dörfler 
18061604e48SAxel Dörfler 		status_t dummy;
18161604e48SAxel Dörfler 		wait_for_thread(fThread, &dummy);
18261604e48SAxel Dörfler 	}
18361604e48SAxel Dörfler }
18461604e48SAxel Dörfler 
18561604e48SAxel Dörfler 
18642b505fbSAxel Dörfler status_t
18742b505fbSAxel Dörfler MouseDevice::UpdateSettings()
18842b505fbSAxel Dörfler {
18942b505fbSAxel Dörfler 	CALLED();
19042b505fbSAxel Dörfler 
19142b505fbSAxel Dörfler 	// retrieve current values
19242b505fbSAxel Dörfler 
19342b505fbSAxel Dörfler 	if (get_mouse_map(&fSettings.map) != B_OK)
19442b505fbSAxel Dörfler 		LOG_ERR("error when get_mouse_map\n");
19542b505fbSAxel Dörfler 	else
19642b505fbSAxel Dörfler 		fDeviceRemapsButtons = ioctl(fDevice, MS_SET_MAP, &fSettings.map) == B_OK;
19742b505fbSAxel Dörfler 
19842b505fbSAxel Dörfler 	if (get_click_speed(&fSettings.click_speed) != B_OK)
19942b505fbSAxel Dörfler 		LOG_ERR("error when get_click_speed\n");
20042b505fbSAxel Dörfler 	else
20142b505fbSAxel Dörfler 		ioctl(fDevice, MS_SET_CLICKSPEED, &fSettings.click_speed);
20242b505fbSAxel Dörfler 
20342b505fbSAxel Dörfler 	if (get_mouse_speed(&fSettings.accel.speed) != B_OK)
20442b505fbSAxel Dörfler 		LOG_ERR("error when get_mouse_speed\n");
20542b505fbSAxel Dörfler 	else {
20642b505fbSAxel Dörfler 		if (get_mouse_acceleration(&fSettings.accel.accel_factor) != B_OK)
20742b505fbSAxel Dörfler 			LOG_ERR("error when get_mouse_acceleration\n");
20842b505fbSAxel Dörfler 		else {
20942b505fbSAxel Dörfler 			mouse_accel accel;
21042b505fbSAxel Dörfler 			ioctl(fDevice, MS_GET_ACCEL, &accel);
21142b505fbSAxel Dörfler 			accel.speed = fSettings.accel.speed;
21242b505fbSAxel Dörfler 			accel.accel_factor = fSettings.accel.accel_factor;
21342b505fbSAxel Dörfler 			ioctl(fDevice, MS_SET_ACCEL, &fSettings.accel);
21442b505fbSAxel Dörfler 		}
21542b505fbSAxel Dörfler 	}
21642b505fbSAxel Dörfler 
21742b505fbSAxel Dörfler 	if (get_mouse_type(&fSettings.type) != B_OK)
21842b505fbSAxel Dörfler 		LOG_ERR("error when get_mouse_type\n");
21942b505fbSAxel Dörfler 	else
22042b505fbSAxel Dörfler 		ioctl(fDevice, MS_SET_TYPE, &fSettings.type);
22142b505fbSAxel Dörfler 
22242b505fbSAxel Dörfler 	return B_OK;
22342b505fbSAxel Dörfler 
22442b505fbSAxel Dörfler }
22542b505fbSAxel Dörfler 
22642b505fbSAxel Dörfler 
22761604e48SAxel Dörfler void
22861604e48SAxel Dörfler MouseDevice::_Run()
22961604e48SAxel Dörfler {
23061604e48SAxel Dörfler 	uint32 lastButtons = 0;
23161604e48SAxel Dörfler 
23261604e48SAxel Dörfler 	while (fActive) {
23361604e48SAxel Dörfler 		mouse_movement movements;
23461604e48SAxel Dörfler 		memset(&movements, 0, sizeof(movements));
23561604e48SAxel Dörfler 
236*c5555ad3SStephan Aßmus 		if (ioctl(fDevice, MS_READ, &movements) != B_OK) {
237*c5555ad3SStephan Aßmus 			fThread = -1;
238*c5555ad3SStephan Aßmus 			fTarget._RemoveDevice(fPath.String());
239*c5555ad3SStephan Aßmus 			// TOAST!
24061604e48SAxel Dörfler 			return;
241*c5555ad3SStephan Aßmus 		}
24261604e48SAxel Dörfler 
24361604e48SAxel Dörfler 		uint32 buttons = lastButtons ^ movements.buttons;
24461604e48SAxel Dörfler 
24561604e48SAxel Dörfler 		uint32 remappedButtons = _RemapButtons(movements.buttons);
24661604e48SAxel Dörfler 		int32 deltaX, deltaY;
24761604e48SAxel Dörfler 		_ComputeAcceleration(movements, deltaX, deltaY);
24861604e48SAxel Dörfler 
24961604e48SAxel Dörfler 		LOG("%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld, wheel_x:%ld, wheel_y:%ld\n",
2501ccc2f2dSJérôme Duval 			fDeviceRef.name, movements.buttons, movements.xdelta, movements.ydelta,
25161604e48SAxel Dörfler 			movements.clicks, movements.wheel_xdelta, movements.wheel_ydelta);
2521ccc2f2dSJérôme Duval 		LOG("%s: x: %ld, y: %ld\n", fDeviceRef.name, deltaX, deltaY);
25361604e48SAxel Dörfler 
25461604e48SAxel Dörfler 		// Send single messages for each event
25561604e48SAxel Dörfler 
25661604e48SAxel Dörfler 		if (buttons != 0) {
25761604e48SAxel Dörfler 			bool pressedButton = (buttons & movements.buttons) > 0;
25861604e48SAxel Dörfler 			BMessage* message = _BuildMouseMessage(
25961604e48SAxel Dörfler 				pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP,
26061604e48SAxel Dörfler 				movements.timestamp, remappedButtons, deltaX, deltaY);
26161604e48SAxel Dörfler 			if (message != NULL) {
26261604e48SAxel Dörfler 				if (pressedButton) {
26361604e48SAxel Dörfler 					message->AddInt32("clicks", movements.clicks);
26461604e48SAxel Dörfler 					LOG("B_MOUSE_DOWN\n");
26561604e48SAxel Dörfler 				} else
26661604e48SAxel Dörfler 					LOG("B_MOUSE_UP\n");
26761604e48SAxel Dörfler 
26861604e48SAxel Dörfler 				fTarget.EnqueueMessage(message);
26961604e48SAxel Dörfler 				lastButtons = movements.buttons;
27061604e48SAxel Dörfler 			}
27161604e48SAxel Dörfler 		}
27261604e48SAxel Dörfler 
27345f11ce8SStephan Aßmus 		if (movements.xdelta != 0 || movements.ydelta != 0) {
27445f11ce8SStephan Aßmus 			BMessage* message = _BuildMouseMessage(B_MOUSE_MOVED,
27545f11ce8SStephan Aßmus 				movements.timestamp, remappedButtons, deltaX, deltaY);
27645f11ce8SStephan Aßmus 			if (message != NULL)
27745f11ce8SStephan Aßmus 				fTarget.EnqueueMessage(message);
27845f11ce8SStephan Aßmus 		}
27945f11ce8SStephan Aßmus 
28061604e48SAxel Dörfler 		if ((movements.wheel_ydelta != 0) || (movements.wheel_xdelta != 0)) {
281*c5555ad3SStephan Aßmus 			BMessage* message = new BMessage(B_MOUSE_WHEEL_CHANGED);
28261604e48SAxel Dörfler 			if (message == NULL)
28361604e48SAxel Dörfler 				continue;
28461604e48SAxel Dörfler 
28561604e48SAxel Dörfler 			if (message->AddInt64("when", movements.timestamp) == B_OK
28661604e48SAxel Dörfler 				&& message->AddFloat("be:wheel_delta_x", movements.wheel_xdelta) == B_OK
28761604e48SAxel Dörfler 				&& message->AddFloat("be:wheel_delta_y", movements.wheel_ydelta) == B_OK)
28861604e48SAxel Dörfler 				fTarget.EnqueueMessage(message);
28961604e48SAxel Dörfler 			else
29061604e48SAxel Dörfler 				delete message;
29161604e48SAxel Dörfler 		}
29261604e48SAxel Dörfler 	}
29361604e48SAxel Dörfler }
29461604e48SAxel Dörfler 
29561604e48SAxel Dörfler 
29661604e48SAxel Dörfler status_t
29761604e48SAxel Dörfler MouseDevice::_ThreadFunction(void* arg)
29861604e48SAxel Dörfler {
29961604e48SAxel Dörfler 	MouseDevice* device = (MouseDevice*)arg;
30061604e48SAxel Dörfler 	device->_Run();
30161604e48SAxel Dörfler 	return B_OK;
30261604e48SAxel Dörfler }
30361604e48SAxel Dörfler 
30461604e48SAxel Dörfler 
30561604e48SAxel Dörfler BMessage*
30661604e48SAxel Dörfler MouseDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons,
30761604e48SAxel Dörfler 	int32 deltaX, int32 deltaY) const
30861604e48SAxel Dörfler {
30961604e48SAxel Dörfler 	BMessage* message = new BMessage(what);
31061604e48SAxel Dörfler 	if (message == NULL)
31161604e48SAxel Dörfler 		return NULL;
31261604e48SAxel Dörfler 
31361604e48SAxel Dörfler 	if (message->AddInt64("when", when) < B_OK
31461604e48SAxel Dörfler 		|| message->AddInt32("buttons", buttons) < B_OK
31561604e48SAxel Dörfler 		|| message->AddInt32("x", deltaX) < B_OK
31661604e48SAxel Dörfler 		|| message->AddInt32("y", deltaY) < B_OK) {
31761604e48SAxel Dörfler 		delete message;
31861604e48SAxel Dörfler 		return NULL;
31961604e48SAxel Dörfler 	}
32061604e48SAxel Dörfler 
32161604e48SAxel Dörfler 	return message;
32261604e48SAxel Dörfler }
32361604e48SAxel Dörfler 
32461604e48SAxel Dörfler 
32561604e48SAxel Dörfler void
32661604e48SAxel Dörfler MouseDevice::_ComputeAcceleration(const mouse_movement& movements,
32761604e48SAxel Dörfler 	int32& deltaX, int32& deltaY) const
32861604e48SAxel Dörfler {
32942b505fbSAxel Dörfler 	// basic mouse speed
33042b505fbSAxel Dörfler 	deltaX = movements.xdelta * fSettings.accel.speed >> 16;
33142b505fbSAxel Dörfler 	deltaY = movements.ydelta * fSettings.accel.speed >> 16;
33242b505fbSAxel Dörfler 
33342b505fbSAxel Dörfler 	// acceleration
33442b505fbSAxel Dörfler 	double acceleration = 1;
33542b505fbSAxel Dörfler 	if (fSettings.accel.accel_factor) {
336fafab827SAxel Dörfler 		acceleration = 1 + sqrt(deltaX * deltaX + deltaY * deltaY)
33774ef1621SAxel Dörfler 			* fSettings.accel.accel_factor / 524288.0;
33842b505fbSAxel Dörfler 	}
33942b505fbSAxel Dörfler 
34042b505fbSAxel Dörfler 	// make sure that we move at least one pixel (if there was a movement)
34142b505fbSAxel Dörfler 	if (deltaX > 0)
34242b505fbSAxel Dörfler 		deltaX = (int32)floor(deltaX * acceleration);
343fafab827SAxel Dörfler 	else
344fafab827SAxel Dörfler 		deltaX = (int32)ceil(deltaX * acceleration);
34542b505fbSAxel Dörfler 
34642b505fbSAxel Dörfler 	if (deltaY > 0)
34742b505fbSAxel Dörfler 		deltaY = (int32)floor(deltaY * acceleration);
348fafab827SAxel Dörfler 	else
349fafab827SAxel Dörfler 		deltaY = (int32)ceil(deltaY * acceleration);
35061604e48SAxel Dörfler }
35161604e48SAxel Dörfler 
35233efb919SStefano Ceccherini 
35323b47e0bSJérôme Duval uint32
35461604e48SAxel Dörfler MouseDevice::_RemapButtons(uint32 buttons) const
35523b47e0bSJérôme Duval {
35661604e48SAxel Dörfler 	if (fDeviceRemapsButtons)
35723b47e0bSJérôme Duval 		return buttons;
35823b47e0bSJérôme Duval 
35961604e48SAxel Dörfler 	uint32 newButtons = 0;
36023b47e0bSJérôme Duval 	for (int32 i = 0; buttons; i++) {
36123b47e0bSJérôme Duval 		if (buttons & 0x1) {
36221631085SStephan Aßmus #if defined(HAIKU_TARGET_PLATFORM_HAIKU) || defined(HAIKU_TARGET_PLATFORM_DANO)
36361604e48SAxel Dörfler 			newButtons |= fSettings.map.button[i];
36423b47e0bSJérôme Duval #else
36523b47e0bSJérôme Duval 			if (i == 0)
36661604e48SAxel Dörfler 				newButtons |= fSettings.map.left;
36723b47e0bSJérôme Duval 			if (i == 1)
36861604e48SAxel Dörfler 				newButtons |= fSettings.map.right;
36923b47e0bSJérôme Duval 			if (i == 2)
37061604e48SAxel Dörfler 				newButtons |= fSettings.map.middle;
37123b47e0bSJérôme Duval #endif
37223b47e0bSJérôme Duval 		}
37323b47e0bSJérôme Duval 		buttons >>= 1;
37423b47e0bSJérôme Duval 	}
37523b47e0bSJérôme Duval 
37661604e48SAxel Dörfler 	return newButtons;
37723b47e0bSJérôme Duval }
37823b47e0bSJérôme Duval 
37923b47e0bSJérôme Duval 
38061604e48SAxel Dörfler char*
38161604e48SAxel Dörfler MouseDevice::_BuildShortName() const
3824c0af4a8SStefano Ceccherini {
38361604e48SAxel Dörfler 	BString string(fPath);
38433efb919SStefano Ceccherini 	BString name;
38533efb919SStefano Ceccherini 
38633efb919SStefano Ceccherini 	int32 slash = string.FindLast("/");
3877dcdcad2SJérôme Duval 	string.CopyInto(name, slash + 1, string.Length() - slash);
3887dcdcad2SJérôme Duval 	int32 index = atoi(name.String()) + 1;
38933efb919SStefano Ceccherini 
3907dcdcad2SJérôme Duval 	int32 previousSlash = string.FindLast("/", slash);
3917dcdcad2SJérôme Duval 	string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1);
392497d01f0SAxel Dörfler 
393497d01f0SAxel Dörfler 	if (name == "ps2")
394497d01f0SAxel Dörfler 		name = "PS/2";
395497d01f0SAxel Dörfler 	else
396497d01f0SAxel Dörfler 		name.Capitalize();
397497d01f0SAxel Dörfler 
3987dcdcad2SJérôme Duval 	name << " Mouse " << index;
39933efb919SStefano Ceccherini 
40033efb919SStefano Ceccherini 	return strdup(name.String());
40133efb919SStefano Ceccherini }
40261604e48SAxel Dörfler 
40361604e48SAxel Dörfler 
40461604e48SAxel Dörfler //	#pragma mark -
40561604e48SAxel Dörfler 
40661604e48SAxel Dörfler 
40761604e48SAxel Dörfler MouseInputDevice::MouseInputDevice()
408b6a7b204SAxel Dörfler 	:
409b6a7b204SAxel Dörfler 	fDevices(2, true)
41061604e48SAxel Dörfler {
41161604e48SAxel Dörfler 	CALLED();
41261604e48SAxel Dörfler 
41361604e48SAxel Dörfler 	_RecursiveScan(kMouseDevicesDirectory);
414*c5555ad3SStephan Aßmus 	StartMonitoringDevice(kMouseDevicesDirectory);
41561604e48SAxel Dörfler }
41661604e48SAxel Dörfler 
41761604e48SAxel Dörfler 
41861604e48SAxel Dörfler MouseInputDevice::~MouseInputDevice()
41961604e48SAxel Dörfler {
42061604e48SAxel Dörfler 	CALLED();
421b6a7b204SAxel Dörfler 	StopMonitoringDevice(kMouseDevicesDirectory);
42261604e48SAxel Dörfler }
42361604e48SAxel Dörfler 
42461604e48SAxel Dörfler 
42561604e48SAxel Dörfler status_t
42661604e48SAxel Dörfler MouseInputDevice::InitCheck()
42761604e48SAxel Dörfler {
42861604e48SAxel Dörfler 	CALLED();
429d246d9beSStefano Ceccherini 	return BInputServerDevice::InitCheck();
43061604e48SAxel Dörfler }
43161604e48SAxel Dörfler 
43261604e48SAxel Dörfler 
43361604e48SAxel Dörfler status_t
43461604e48SAxel Dörfler MouseInputDevice::Start(const char* name, void* cookie)
43561604e48SAxel Dörfler {
43661604e48SAxel Dörfler 	LOG("%s(%s)\n", __PRETTY_FUNCTION__, name);
43761604e48SAxel Dörfler 	MouseDevice* device = (MouseDevice*)cookie;
43861604e48SAxel Dörfler 
43961604e48SAxel Dörfler 	return device->Start();
44061604e48SAxel Dörfler }
44161604e48SAxel Dörfler 
44261604e48SAxel Dörfler 
44361604e48SAxel Dörfler status_t
44461604e48SAxel Dörfler MouseInputDevice::Stop(const char* name, void* cookie)
44561604e48SAxel Dörfler {
44661604e48SAxel Dörfler 	LOG("%s(%s)\n", __PRETTY_FUNCTION__, name);
44761604e48SAxel Dörfler 	MouseDevice* device = (MouseDevice*)cookie;
44861604e48SAxel Dörfler 
44961604e48SAxel Dörfler 	device->Stop();
45061604e48SAxel Dörfler 	return B_OK;
45161604e48SAxel Dörfler }
45261604e48SAxel Dörfler 
45361604e48SAxel Dörfler 
45461604e48SAxel Dörfler status_t
45561604e48SAxel Dörfler MouseInputDevice::Control(const char* name, void* cookie,
45661604e48SAxel Dörfler 	uint32 command, BMessage* message)
45761604e48SAxel Dörfler {
45861604e48SAxel Dörfler 	LOG("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command);
45961604e48SAxel Dörfler 	MouseDevice* device = (MouseDevice*)cookie;
46061604e48SAxel Dörfler 
46161604e48SAxel Dörfler 	if (command == B_NODE_MONITOR)
46261604e48SAxel Dörfler 		return _HandleMonitor(message);
46361604e48SAxel Dörfler 
46461604e48SAxel Dörfler 	if (command >= B_MOUSE_TYPE_CHANGED
46561604e48SAxel Dörfler 		&& command <= B_MOUSE_ACCELERATION_CHANGED)
46661604e48SAxel Dörfler 		return device->UpdateSettings();
46761604e48SAxel Dörfler 
46861604e48SAxel Dörfler 	return B_BAD_VALUE;
46961604e48SAxel Dörfler }
47061604e48SAxel Dörfler 
47161604e48SAxel Dörfler 
47261604e48SAxel Dörfler status_t
47361604e48SAxel Dörfler MouseInputDevice::_HandleMonitor(BMessage* message)
47461604e48SAxel Dörfler {
47561604e48SAxel Dörfler 	CALLED();
47661604e48SAxel Dörfler 
477b6a7b204SAxel Dörfler 	const char* path;
47861604e48SAxel Dörfler 	int32 opcode;
479b6a7b204SAxel Dörfler 	if (message->FindInt32("opcode", &opcode) != B_OK
480*c5555ad3SStephan Aßmus 		|| (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED)
481b6a7b204SAxel Dörfler 		|| message->FindString("path", &path) != B_OK)
48261604e48SAxel Dörfler 		return B_BAD_VALUE;
48361604e48SAxel Dörfler 
48461604e48SAxel Dörfler 	if (opcode == B_ENTRY_CREATED)
485b6a7b204SAxel Dörfler 		return _AddDevice(path);
48661604e48SAxel Dörfler 
487*c5555ad3SStephan Aßmus #if 0
488b6a7b204SAxel Dörfler 	return _RemoveDevice(path);
489*c5555ad3SStephan Aßmus #else
490*c5555ad3SStephan Aßmus 	// Don't handle B_ENTRY_REMOVED, let the control thread take care of it.
491*c5555ad3SStephan Aßmus 	return B_OK;
492*c5555ad3SStephan Aßmus #endif
49361604e48SAxel Dörfler }
49461604e48SAxel Dörfler 
49561604e48SAxel Dörfler 
49661604e48SAxel Dörfler MouseDevice*
49761604e48SAxel Dörfler MouseInputDevice::_FindDevice(const char* path)
49861604e48SAxel Dörfler {
49961604e48SAxel Dörfler 	CALLED();
50061604e48SAxel Dörfler 
501*c5555ad3SStephan Aßmus 	for (int32 i = fDevices.CountItems() - 1; i >= 0; i--) {
502b6a7b204SAxel Dörfler 		MouseDevice* device = fDevices.ItemAt(i);
503*c5555ad3SStephan Aßmus 		if (strcmp(device->Path(), path) == 0)
50461604e48SAxel Dörfler 			return device;
50561604e48SAxel Dörfler 	}
50661604e48SAxel Dörfler 
50761604e48SAxel Dörfler 	return NULL;
50861604e48SAxel Dörfler }
50961604e48SAxel Dörfler 
51061604e48SAxel Dörfler 
51161604e48SAxel Dörfler status_t
51261604e48SAxel Dörfler MouseInputDevice::_AddDevice(const char* path)
51361604e48SAxel Dörfler {
51461604e48SAxel Dörfler 	CALLED();
51561604e48SAxel Dörfler 
516*c5555ad3SStephan Aßmus 	_RemoveDevice(path);
517*c5555ad3SStephan Aßmus 
51861604e48SAxel Dörfler 	MouseDevice* device = new(std::nothrow) MouseDevice(*this, path);
51961604e48SAxel Dörfler 	if (!device) {
520*c5555ad3SStephan Aßmus 		LOG("MouseInputDevice::_AddDevice() - No memory\n");
52161604e48SAxel Dörfler 		return B_NO_MEMORY;
52261604e48SAxel Dörfler 	}
52361604e48SAxel Dörfler 
52461604e48SAxel Dörfler 	if (!fDevices.AddItem(device)) {
52561604e48SAxel Dörfler 		delete device;
52661604e48SAxel Dörfler 		return B_NO_MEMORY;
52761604e48SAxel Dörfler 	}
52861604e48SAxel Dörfler 
52961604e48SAxel Dörfler 	input_device_ref* devices[2];
53061604e48SAxel Dörfler 	devices[0] = device->DeviceRef();
53161604e48SAxel Dörfler 	devices[1] = NULL;
53261604e48SAxel Dörfler 
533*c5555ad3SStephan Aßmus 	LOG_DEVICES("MouseInputDevice::_AddDevice(%s), name: %s\n", path,
534*c5555ad3SStephan Aßmus 		devices[0]->name);
535*c5555ad3SStephan Aßmus 
53661604e48SAxel Dörfler 	return RegisterDevices(devices);
53761604e48SAxel Dörfler }
53861604e48SAxel Dörfler 
53961604e48SAxel Dörfler 
54061604e48SAxel Dörfler status_t
54161604e48SAxel Dörfler MouseInputDevice::_RemoveDevice(const char* path)
54261604e48SAxel Dörfler {
54361604e48SAxel Dörfler 	CALLED();
54461604e48SAxel Dörfler 
54561604e48SAxel Dörfler 	MouseDevice* device = _FindDevice(path);
54661604e48SAxel Dörfler 	if (device == NULL)
54761604e48SAxel Dörfler 		return B_ENTRY_NOT_FOUND;
54861604e48SAxel Dörfler 
54961604e48SAxel Dörfler 	input_device_ref* devices[2];
55061604e48SAxel Dörfler 	devices[0] = device->DeviceRef();
55161604e48SAxel Dörfler 	devices[1] = NULL;
55261604e48SAxel Dörfler 
553*c5555ad3SStephan Aßmus 	LOG_DEVICES("MouseInputDevice::_RemoveDevice(%s), name: %s\n", path,
554*c5555ad3SStephan Aßmus 		devices[0]->name);
555*c5555ad3SStephan Aßmus 
55661604e48SAxel Dörfler 	UnregisterDevices(devices);
55761604e48SAxel Dörfler 
558*c5555ad3SStephan Aßmus 	fDevices.RemoveItem(device);
559*c5555ad3SStephan Aßmus 
56061604e48SAxel Dörfler 	return B_OK;
56161604e48SAxel Dörfler }
56261604e48SAxel Dörfler 
56361604e48SAxel Dörfler 
56461604e48SAxel Dörfler void
56561604e48SAxel Dörfler MouseInputDevice::_RecursiveScan(const char* directory)
56661604e48SAxel Dörfler {
56761604e48SAxel Dörfler 	CALLED();
56861604e48SAxel Dörfler 
56961604e48SAxel Dörfler 	BEntry entry;
57061604e48SAxel Dörfler 	BDirectory dir(directory);
57161604e48SAxel Dörfler 	while (dir.GetNextEntry(&entry) == B_OK) {
57261604e48SAxel Dörfler 		BPath path;
57361604e48SAxel Dörfler 		entry.GetPath(&path);
57461604e48SAxel Dörfler 
57561604e48SAxel Dörfler 		if (!strcmp(path.Leaf(), "serial")) {
57661604e48SAxel Dörfler 			// skip serial
57761604e48SAxel Dörfler 			continue;
57861604e48SAxel Dörfler 		}
57961604e48SAxel Dörfler 
58061604e48SAxel Dörfler 		if (entry.IsDirectory())
58161604e48SAxel Dörfler 			_RecursiveScan(path.Path());
58261604e48SAxel Dörfler 		else
58361604e48SAxel Dörfler 			_AddDevice(path.Path());
58461604e48SAxel Dörfler 	}
58561604e48SAxel Dörfler }
58661604e48SAxel Dörfler 
587