xref: /haiku/src/add-ons/input_server/devices/mouse/MouseInputDevice.cpp (revision fc548b41f3e8d8b849b186e16758321279300f8f)
123b47e0bSJérôme Duval /*
27d1d7033SStephan Aßmus  * Copyright 2004-2009, 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
9167f43a2SStephan Aßmus  *		Clemens Zeidler, haiku@clemens-zeidler.de
10239fd643SStephan Aßmus  *		Stephan Aßmus, superstippi@gmx.de
1123b47e0bSJérôme Duval  */
1233efb919SStefano Ceccherini 
1333efb919SStefano Ceccherini 
1461d7deeeSJérôme Duval #include "MouseInputDevice.h"
15b6a7b204SAxel Dörfler 
16b6a7b204SAxel Dörfler #include <errno.h>
17b6a7b204SAxel Dörfler #include <new>
18b6a7b204SAxel Dörfler #include <stdio.h>
19b6a7b204SAxel Dörfler #include <stdlib.h>
20b6a7b204SAxel Dörfler #include <unistd.h>
2161d7deeeSJérôme Duval 
225125eae2SStephan Aßmus #include <Autolock.h>
23c2fbfb71SJérôme Duval #include <Debug.h>
2433efb919SStefano Ceccherini #include <Directory.h>
2533efb919SStefano Ceccherini #include <Entry.h>
26167f43a2SStephan Aßmus #include <File.h>
27167f43a2SStephan Aßmus #include <FindDirectory.h>
2833efb919SStefano Ceccherini #include <NodeMonitor.h>
2933efb919SStefano Ceccherini #include <Path.h>
3033efb919SStefano Ceccherini #include <String.h>
3161604e48SAxel Dörfler #include <View.h>
3261604e48SAxel Dörfler 
33b6a7b204SAxel Dörfler #include "kb_mouse_settings.h"
34b6a7b204SAxel Dörfler #include "kb_mouse_driver.h"
35167f43a2SStephan Aßmus #include "touchpad_settings.h"
3633efb919SStefano Ceccherini 
37b6a7b204SAxel Dörfler 
38e01a0431SStephan Aßmus #undef TRACE
39b6a7b204SAxel Dörfler //#define TRACE_MOUSE_DEVICE
40b6a7b204SAxel Dörfler #ifdef TRACE_MOUSE_DEVICE
41e01a0431SStephan Aßmus 
42e01a0431SStephan Aßmus 	class FunctionTracer {
43e01a0431SStephan Aßmus 	public:
44e01a0431SStephan Aßmus 		FunctionTracer(const void* pointer, const char* className,
45e01a0431SStephan Aßmus 				const char* functionName,
46e01a0431SStephan Aßmus 				int32& depth)
47e01a0431SStephan Aßmus 			: fFunctionName(),
48e01a0431SStephan Aßmus 			  fPrepend(),
49e01a0431SStephan Aßmus 			  fFunctionDepth(depth),
50e01a0431SStephan Aßmus 			  fPointer(pointer)
51e01a0431SStephan Aßmus 		{
52e01a0431SStephan Aßmus 			fFunctionDepth++;
53e01a0431SStephan Aßmus 			fPrepend.Append(' ', fFunctionDepth * 2);
54e01a0431SStephan Aßmus 			fFunctionName << className << "::" << functionName << "()";
55e01a0431SStephan Aßmus 
56e01a0431SStephan Aßmus 			debug_printf("%p -> %s%s {\n", fPointer, fPrepend.String(),
57e01a0431SStephan Aßmus 				fFunctionName.String());
58e01a0431SStephan Aßmus 		}
59e01a0431SStephan Aßmus 
60e01a0431SStephan Aßmus 		 ~FunctionTracer()
61e01a0431SStephan Aßmus 		{
62e01a0431SStephan Aßmus 			debug_printf("%p -> %s}\n", fPointer, fPrepend.String());
63e01a0431SStephan Aßmus 			fFunctionDepth--;
64e01a0431SStephan Aßmus 		}
65e01a0431SStephan Aßmus 
66e01a0431SStephan Aßmus 	private:
67e01a0431SStephan Aßmus 		BString	fFunctionName;
68e01a0431SStephan Aßmus 		BString	fPrepend;
69e01a0431SStephan Aßmus 		int32&	fFunctionDepth;
70e01a0431SStephan Aßmus 		const void* fPointer;
71e01a0431SStephan Aßmus 	};
72e01a0431SStephan Aßmus 
73e01a0431SStephan Aßmus 
74e01a0431SStephan Aßmus 	static int32 sFunctionDepth = -1;
75e01a0431SStephan Aßmus #	define MD_CALLED(x...)	FunctionTracer _ft(this, "MouseDevice", \
76e01a0431SStephan Aßmus 								__FUNCTION__, sFunctionDepth)
77e01a0431SStephan Aßmus #	define MID_CALLED(x...)	FunctionTracer _ft(this, "MouseInputDevice", \
78e01a0431SStephan Aßmus 								__FUNCTION__, sFunctionDepth)
79e02ed691SRene Gollent #	define TRACE(x...)	do { BString _to; \
80e01a0431SStephan Aßmus 							_to.Append(' ', (sFunctionDepth + 1) * 2); \
81e01a0431SStephan Aßmus 							debug_printf("%p -> %s", this, _to.String()); \
82e02ed691SRene Gollent 							debug_printf(x); } while (0)
83e01a0431SStephan Aßmus #	define LOG_EVENT(text...) do {} while (0)
845125eae2SStephan Aßmus #	define LOG_ERR(text...) TRACE(text)
853aa69c78SStefano Ceccherini #else
86e01a0431SStephan Aßmus #	define TRACE(x...) do {} while (0)
87e01a0431SStephan Aßmus #	define MD_CALLED(x...) TRACE(x)
88e01a0431SStephan Aßmus #	define MID_CALLED(x...) TRACE(x)
896e094221SStephan Aßmus #	define LOG_ERR(x...) debug_printf(x)
906e094221SStephan Aßmus #	define LOG_EVENT(x...) TRACE(x)
913aa69c78SStefano Ceccherini #endif
923aa69c78SStefano Ceccherini 
93e01a0431SStephan Aßmus 
9433efb919SStefano Ceccherini const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4;
9533efb919SStefano Ceccherini const static char* kMouseDevicesDirectory = "/dev/input/mouse";
96167f43a2SStephan Aßmus const static char* kTouchpadDevicesDirectory = "/dev/input/touchpad";
9733efb919SStefano Ceccherini 
9833efb919SStefano Ceccherini 
9961604e48SAxel Dörfler class MouseDevice {
10061604e48SAxel Dörfler public:
1015125eae2SStephan Aßmus 								MouseDevice(MouseInputDevice& target,
1025125eae2SStephan Aßmus 									const char* path);
10361604e48SAxel Dörfler 								~MouseDevice();
10433efb919SStefano Ceccherini 
10561604e48SAxel Dörfler 			status_t			Start();
10661604e48SAxel Dörfler 			void				Stop();
10761604e48SAxel Dörfler 
10861604e48SAxel Dörfler 			status_t			UpdateSettings();
109167f43a2SStephan Aßmus 			status_t			UpdateTouchpadSettings(const BMessage* message);
11061604e48SAxel Dörfler 
11161604e48SAxel Dörfler 			const char*			Path() const { return fPath.String(); }
11261604e48SAxel Dörfler 			input_device_ref*	DeviceRef() { return &fDeviceRef; }
11361604e48SAxel Dörfler 
11461604e48SAxel Dörfler private:
1155125eae2SStephan Aßmus 			char*				_BuildShortName() const;
11661604e48SAxel Dörfler 
1175125eae2SStephan Aßmus 	static	status_t			_ControlThreadEntry(void* arg);
1185125eae2SStephan Aßmus 			void				_ControlThread();
1195125eae2SStephan Aßmus 			void				_ControlThreadCleanup();
1205125eae2SStephan Aßmus 			void				_UpdateSettings();
1215125eae2SStephan Aßmus 
122167f43a2SStephan Aßmus 			status_t			_GetTouchpadSettingsPath(BPath& path);
123167f43a2SStephan Aßmus 			status_t			_ReadTouchpadSettingsMsg(BMessage* message);
124167f43a2SStephan Aßmus 			status_t			_UpdateTouchpadSettings();
125167f43a2SStephan Aßmus 
1265125eae2SStephan Aßmus 			BMessage*			_BuildMouseMessage(uint32 what,
1275125eae2SStephan Aßmus 									uint64 when, uint32 buttons,
12861604e48SAxel Dörfler 									int32 deltaX, int32 deltaY) const;
1295125eae2SStephan Aßmus 			void				_ComputeAcceleration(
1305125eae2SStephan Aßmus 									const mouse_movement& movements,
1316e094221SStephan Aßmus 									int32& deltaX, int32& deltaY,
1326e094221SStephan Aßmus 									float& historyDeltaX,
1336e094221SStephan Aßmus 									float& historyDeltaY) const;
13461604e48SAxel Dörfler 			uint32				_RemapButtons(uint32 buttons) const;
13561604e48SAxel Dörfler 
13661604e48SAxel Dörfler private:
137c5555ad3SStephan Aßmus 			MouseInputDevice&	fTarget;
13861604e48SAxel Dörfler 			BString				fPath;
13961604e48SAxel Dörfler 			int					fDevice;
14061604e48SAxel Dörfler 
14161604e48SAxel Dörfler 			input_device_ref	fDeviceRef;
14261604e48SAxel Dörfler 			mouse_settings		fSettings;
14361604e48SAxel Dörfler 			bool				fDeviceRemapsButtons;
14461604e48SAxel Dörfler 
14561604e48SAxel Dörfler 			thread_id			fThread;
14661604e48SAxel Dörfler 	volatile bool				fActive;
1475125eae2SStephan Aßmus 	volatile bool				fUpdateSettings;
148167f43a2SStephan Aßmus 
149167f43a2SStephan Aßmus 			bool				fIsTouchpad;
150167f43a2SStephan Aßmus 			touchpad_settings	fTouchpadSettings;
151167f43a2SStephan Aßmus 			BMessage*			fTouchpadSettingsMessage;
152167f43a2SStephan Aßmus 			BLocker				fTouchpadSettingsLock;
1530dbc4befSStefano Ceccherini };
1540dbc4befSStefano Ceccherini 
1550dbc4befSStefano Ceccherini 
15661604e48SAxel Dörfler extern "C" BInputServerDevice*
15761d7deeeSJérôme Duval instantiate_input_device()
15861d7deeeSJérôme Duval {
159d246d9beSStefano Ceccherini 	return new(std::nothrow) MouseInputDevice();
16061d7deeeSJérôme Duval }
16161d7deeeSJérôme Duval 
16261d7deeeSJérôme Duval 
16361604e48SAxel Dörfler //	#pragma mark -
16461604e48SAxel Dörfler 
16561604e48SAxel Dörfler 
166c5555ad3SStephan Aßmus MouseDevice::MouseDevice(MouseInputDevice& target, const char* driverPath)
16761604e48SAxel Dörfler 	:
16861604e48SAxel Dörfler 	fTarget(target),
169c5555ad3SStephan Aßmus 	fPath(driverPath),
17061604e48SAxel Dörfler 	fDevice(-1),
171e01a0431SStephan Aßmus 	fDeviceRemapsButtons(false),
17261604e48SAxel Dörfler 	fThread(-1),
1735125eae2SStephan Aßmus 	fActive(false),
174167f43a2SStephan Aßmus 	fUpdateSettings(false),
175167f43a2SStephan Aßmus 	fIsTouchpad(false),
176167f43a2SStephan Aßmus 	fTouchpadSettingsMessage(NULL),
177167f43a2SStephan Aßmus 	fTouchpadSettingsLock("Touchpad settings lock")
17861d7deeeSJérôme Duval {
179e01a0431SStephan Aßmus 	MD_CALLED();
180e01a0431SStephan Aßmus 
18161604e48SAxel Dörfler 	fDeviceRef.name = _BuildShortName();
18261604e48SAxel Dörfler 	fDeviceRef.type = B_POINTING_DEVICE;
18361604e48SAxel Dörfler 	fDeviceRef.cookie = this;
18461604e48SAxel Dörfler 
18561604e48SAxel Dörfler #ifdef HAIKU_TARGET_PLATFORM_HAIKU
18661604e48SAxel Dörfler 	fSettings.map.button[0] = B_PRIMARY_MOUSE_BUTTON;
18761604e48SAxel Dörfler 	fSettings.map.button[1] = B_SECONDARY_MOUSE_BUTTON;
18861604e48SAxel Dörfler 	fSettings.map.button[2] = B_TERTIARY_MOUSE_BUTTON;
1893aa69c78SStefano Ceccherini #endif
19061604e48SAxel Dörfler };
19161d7deeeSJérôme Duval 
19261d7deeeSJérôme Duval 
19361604e48SAxel Dörfler MouseDevice::~MouseDevice()
19461d7deeeSJérôme Duval {
195e01a0431SStephan Aßmus 	MD_CALLED();
196e01a0431SStephan Aßmus 	TRACE("delete\n");
197e01a0431SStephan Aßmus 
19861604e48SAxel Dörfler 	if (fActive)
19961604e48SAxel Dörfler 		Stop();
20061d7deeeSJérôme Duval 
20161604e48SAxel Dörfler 	free(fDeviceRef.name);
202167f43a2SStephan Aßmus 	delete fTouchpadSettingsMessage;
20361d7deeeSJérôme Duval }
20461d7deeeSJérôme Duval 
20561d7deeeSJérôme Duval 
20661d7deeeSJérôme Duval status_t
20761604e48SAxel Dörfler MouseDevice::Start()
20853d77642SJérôme Duval {
209e01a0431SStephan Aßmus 	MD_CALLED();
210e01a0431SStephan Aßmus 
21161604e48SAxel Dörfler 	fDevice = open(fPath.String(), O_RDWR);
2125125eae2SStephan Aßmus 		// let the control thread handle any error on opening the device
21333efb919SStefano Ceccherini 
21433efb919SStefano Ceccherini 	char threadName[B_OS_NAME_LENGTH];
21561604e48SAxel Dörfler 	snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", fDeviceRef.name);
21633efb919SStefano Ceccherini 
2175125eae2SStephan Aßmus 	fThread = spawn_thread(_ControlThreadEntry, threadName,
21861604e48SAxel Dörfler 		kMouseThreadPriority, (void*)this);
2194c0af4a8SStefano Ceccherini 
22033efb919SStefano Ceccherini 	status_t status;
22161604e48SAxel Dörfler 	if (fThread < B_OK)
22261604e48SAxel Dörfler 		status = fThread;
22361604e48SAxel Dörfler 	else {
22461604e48SAxel Dörfler 		fActive = true;
22561604e48SAxel Dörfler 		status = resume_thread(fThread);
22661604e48SAxel Dörfler 	}
22733efb919SStefano Ceccherini 
22861604e48SAxel Dörfler 	if (status < B_OK) {
22961604e48SAxel Dörfler 		LOG_ERR("%s: can't spawn/resume watching thread: %s\n",
23061604e48SAxel Dörfler 			fDeviceRef.name, strerror(status));
231167f43a2SStephan Aßmus 		close(fDevice);
23261604e48SAxel Dörfler 		return status;
23361604e48SAxel Dörfler 	}
23461604e48SAxel Dörfler 
2359195fe6eSStephan Aßmus 	return fDevice >= 0 ? B_OK : B_ERROR;
23661d7deeeSJérôme Duval }
23761d7deeeSJérôme Duval 
23861d7deeeSJérôme Duval 
239c2fbfb71SJérôme Duval void
24061604e48SAxel Dörfler MouseDevice::Stop()
24161604e48SAxel Dörfler {
242e01a0431SStephan Aßmus 	MD_CALLED();
2431ccc2f2dSJérôme Duval 
24461604e48SAxel Dörfler 	fActive = false;
24561604e48SAxel Dörfler 		// this will stop the thread as soon as it reads the next packet
24661604e48SAxel Dörfler 
247e01a0431SStephan Aßmus 	close(fDevice);
248e01a0431SStephan Aßmus 	fDevice = -1;
249e01a0431SStephan Aßmus 
25061604e48SAxel Dörfler 	if (fThread >= B_OK) {
25161604e48SAxel Dörfler 		// unblock the thread, which might wait on a semaphore.
25261604e48SAxel Dörfler 		suspend_thread(fThread);
25361604e48SAxel Dörfler 		resume_thread(fThread);
25461604e48SAxel Dörfler 
25561604e48SAxel Dörfler 		status_t dummy;
25661604e48SAxel Dörfler 		wait_for_thread(fThread, &dummy);
25761604e48SAxel Dörfler 	}
25861604e48SAxel Dörfler }
25961604e48SAxel Dörfler 
26061604e48SAxel Dörfler 
26142b505fbSAxel Dörfler status_t
26242b505fbSAxel Dörfler MouseDevice::UpdateSettings()
26342b505fbSAxel Dörfler {
264e01a0431SStephan Aßmus 	MD_CALLED();
26542b505fbSAxel Dörfler 
2665125eae2SStephan Aßmus 	if (fThread < 0)
2675125eae2SStephan Aßmus 		return B_ERROR;
26842b505fbSAxel Dörfler 
269167f43a2SStephan Aßmus 	// trigger updating the settings in the control thread
2705125eae2SStephan Aßmus 	fUpdateSettings = true;
271167f43a2SStephan Aßmus 
272167f43a2SStephan Aßmus 	return B_OK;
273167f43a2SStephan Aßmus }
274167f43a2SStephan Aßmus 
275167f43a2SStephan Aßmus 
276167f43a2SStephan Aßmus status_t
277167f43a2SStephan Aßmus MouseDevice::UpdateTouchpadSettings(const BMessage* message)
278167f43a2SStephan Aßmus {
279167f43a2SStephan Aßmus 	if (!fIsTouchpad)
280167f43a2SStephan Aßmus 		return B_BAD_TYPE;
281167f43a2SStephan Aßmus 	if (fThread < 0)
282167f43a2SStephan Aßmus 		return B_ERROR;
283167f43a2SStephan Aßmus 
284167f43a2SStephan Aßmus 	BAutolock _(fTouchpadSettingsLock);
285167f43a2SStephan Aßmus 
286167f43a2SStephan Aßmus 	// trigger updating the settings in the control thread
287167f43a2SStephan Aßmus 	fUpdateSettings = true;
288167f43a2SStephan Aßmus 
289167f43a2SStephan Aßmus 	delete fTouchpadSettingsMessage;
290167f43a2SStephan Aßmus 	fTouchpadSettingsMessage = new BMessage(*message);
29142b505fbSAxel Dörfler 
29242b505fbSAxel Dörfler 	return B_OK;
2935125eae2SStephan Aßmus }
29442b505fbSAxel Dörfler 
2955125eae2SStephan Aßmus 
2965125eae2SStephan Aßmus char*
2975125eae2SStephan Aßmus MouseDevice::_BuildShortName() const
2985125eae2SStephan Aßmus {
2995125eae2SStephan Aßmus 	BString string(fPath);
3005125eae2SStephan Aßmus 	BString name;
3015125eae2SStephan Aßmus 
3025125eae2SStephan Aßmus 	int32 slash = string.FindLast("/");
3035125eae2SStephan Aßmus 	string.CopyInto(name, slash + 1, string.Length() - slash);
3045125eae2SStephan Aßmus 	int32 index = atoi(name.String()) + 1;
3055125eae2SStephan Aßmus 
3065125eae2SStephan Aßmus 	int32 previousSlash = string.FindLast("/", slash);
3075125eae2SStephan Aßmus 	string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1);
3085125eae2SStephan Aßmus 
3095125eae2SStephan Aßmus 	if (name == "ps2")
3105125eae2SStephan Aßmus 		name = "PS/2";
311155b8260SPhilippe Houdoin 
312155b8260SPhilippe Houdoin 	if (name.Length() < 4)
313155b8260SPhilippe Houdoin 		name.ToUpper();
3145125eae2SStephan Aßmus 	else
3155125eae2SStephan Aßmus 		name.Capitalize();
3165125eae2SStephan Aßmus 
317167f43a2SStephan Aßmus 	if (string.FindFirst("touchpad") >= 0) {
318167f43a2SStephan Aßmus 		name << " Touchpad ";
319167f43a2SStephan Aßmus 	} else {
320cc442411SStephan Aßmus 		if (string.FindFirst("intelli") >= 0)
321cc442411SStephan Aßmus 			name.Prepend("Extended ");
322cc442411SStephan Aßmus 
323167f43a2SStephan Aßmus 		name << " Mouse ";
324167f43a2SStephan Aßmus 	}
325167f43a2SStephan Aßmus 	name << index;
3265125eae2SStephan Aßmus 
3275125eae2SStephan Aßmus 	return strdup(name.String());
3285125eae2SStephan Aßmus }
3295125eae2SStephan Aßmus 
3305125eae2SStephan Aßmus 
3315125eae2SStephan Aßmus // #pragma mark - control thread
3325125eae2SStephan Aßmus 
3335125eae2SStephan Aßmus 
3345125eae2SStephan Aßmus status_t
3355125eae2SStephan Aßmus MouseDevice::_ControlThreadEntry(void* arg)
3365125eae2SStephan Aßmus {
3375125eae2SStephan Aßmus 	MouseDevice* device = (MouseDevice*)arg;
3385125eae2SStephan Aßmus 	device->_ControlThread();
3395125eae2SStephan Aßmus 	return B_OK;
34042b505fbSAxel Dörfler }
34142b505fbSAxel Dörfler 
34242b505fbSAxel Dörfler 
34361604e48SAxel Dörfler void
3445125eae2SStephan Aßmus MouseDevice::_ControlThread()
34561604e48SAxel Dörfler {
346167f43a2SStephan Aßmus 	MD_CALLED();
347167f43a2SStephan Aßmus 
3485125eae2SStephan Aßmus 	if (fDevice < 0) {
3495125eae2SStephan Aßmus 		_ControlThreadCleanup();
3505125eae2SStephan Aßmus 		// TOAST!
3515125eae2SStephan Aßmus 		return;
3525125eae2SStephan Aßmus 	}
3535125eae2SStephan Aßmus 
354167f43a2SStephan Aßmus 	// touchpad settings
355167f43a2SStephan Aßmus 	if (ioctl(fDevice, MS_IS_TOUCHPAD, NULL) == B_OK) {
356167f43a2SStephan Aßmus 		TRACE("is touchpad %s\n", fPath.String());
357167f43a2SStephan Aßmus 		fIsTouchpad = true;
358167f43a2SStephan Aßmus 
359167f43a2SStephan Aßmus 		fTouchpadSettings = kDefaultTouchpadSettings;
360167f43a2SStephan Aßmus 
361167f43a2SStephan Aßmus 		BPath path;
362167f43a2SStephan Aßmus 		status_t status = _GetTouchpadSettingsPath(path);
363167f43a2SStephan Aßmus 		BFile settingsFile(path.Path(), B_READ_ONLY);
364167f43a2SStephan Aßmus 		if (status == B_OK && settingsFile.InitCheck() == B_OK) {
365167f43a2SStephan Aßmus 			if (settingsFile.Read(&fTouchpadSettings, sizeof(touchpad_settings))
366167f43a2SStephan Aßmus 					!= sizeof(touchpad_settings)) {
367167f43a2SStephan Aßmus 				TRACE("failed to load settings\n");
368167f43a2SStephan Aßmus 			}
369167f43a2SStephan Aßmus 		}
370167f43a2SStephan Aßmus 		_UpdateTouchpadSettings();
371167f43a2SStephan Aßmus 	}
372167f43a2SStephan Aßmus 
3735125eae2SStephan Aßmus 	_UpdateSettings();
3745125eae2SStephan Aßmus 
37561604e48SAxel Dörfler 	uint32 lastButtons = 0;
3766e094221SStephan Aßmus 	float historyDeltaX = 0.0;
3776e094221SStephan Aßmus 	float historyDeltaY = 0.0;
37861604e48SAxel Dörfler 
3797d1d7033SStephan Aßmus 	static const bigtime_t kTransferDelay = 1000000 / 125;
3807d1d7033SStephan Aßmus 		// 125 transfers per second should be more than enough
3815994d47aSStephan Aßmus #define USE_REGULAR_INTERVAL 1
3827d1d7033SStephan Aßmus #if USE_REGULAR_INTERVAL
3837d1d7033SStephan Aßmus 	bigtime_t nextTransferTime = system_time() + kTransferDelay;
3847d1d7033SStephan Aßmus #endif
3857d1d7033SStephan Aßmus 
38661604e48SAxel Dörfler 	while (fActive) {
38761604e48SAxel Dörfler 		mouse_movement movements;
3887d1d7033SStephan Aßmus 
3897d1d7033SStephan Aßmus #if USE_REGULAR_INTERVAL
3907d1d7033SStephan Aßmus 		snooze_until(nextTransferTime, B_SYSTEM_TIMEBASE);
3917d1d7033SStephan Aßmus 		nextTransferTime += kTransferDelay;
3927d1d7033SStephan Aßmus #endif
3937d1d7033SStephan Aßmus 
394c5555ad3SStephan Aßmus 		if (ioctl(fDevice, MS_READ, &movements) != B_OK) {
3955125eae2SStephan Aßmus 			_ControlThreadCleanup();
396c5555ad3SStephan Aßmus 			// TOAST!
39761604e48SAxel Dörfler 			return;
398c5555ad3SStephan Aßmus 		}
39961604e48SAxel Dörfler 
4005125eae2SStephan Aßmus 		// take care of updating the settings first, if necessary
4015125eae2SStephan Aßmus 		if (fUpdateSettings) {
4025125eae2SStephan Aßmus 			fUpdateSettings = false;
403167f43a2SStephan Aßmus 			if (fIsTouchpad) {
404167f43a2SStephan Aßmus 				BAutolock _(fTouchpadSettingsLock);
4053bf47305SAxel Dörfler 				if (fTouchpadSettingsMessage != NULL) {
406167f43a2SStephan Aßmus 					_ReadTouchpadSettingsMsg(fTouchpadSettingsMessage);
407167f43a2SStephan Aßmus 					_UpdateTouchpadSettings();
408167f43a2SStephan Aßmus 					delete fTouchpadSettingsMessage;
409167f43a2SStephan Aßmus 					fTouchpadSettingsMessage = NULL;
410167f43a2SStephan Aßmus 				} else
411167f43a2SStephan Aßmus 					_UpdateSettings();
412167f43a2SStephan Aßmus 			} else
413167f43a2SStephan Aßmus 				_UpdateSettings();
4145125eae2SStephan Aßmus 		}
4155125eae2SStephan Aßmus 
41661604e48SAxel Dörfler 		uint32 buttons = lastButtons ^ movements.buttons;
41761604e48SAxel Dörfler 
41861604e48SAxel Dörfler 		uint32 remappedButtons = _RemapButtons(movements.buttons);
41961604e48SAxel Dörfler 		int32 deltaX, deltaY;
4206e094221SStephan Aßmus 		_ComputeAcceleration(movements, deltaX, deltaY, historyDeltaX,
4216e094221SStephan Aßmus 			historyDeltaY);
42261604e48SAxel Dörfler 
4236e094221SStephan Aßmus 		LOG_EVENT("%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld, "
4246e094221SStephan Aßmus 			"wheel_x:%ld, wheel_y:%ld\n",
4256e094221SStephan Aßmus 			fDeviceRef.name, movements.buttons,
4266e094221SStephan Aßmus 			movements.xdelta, movements.ydelta, movements.clicks,
4276e094221SStephan Aßmus 			movements.wheel_xdelta, movements.wheel_ydelta);
4286e094221SStephan Aßmus 		LOG_EVENT("%s: x: %ld, y: %ld (%.4f, %.4f)\n", fDeviceRef.name,
4296e094221SStephan Aßmus 			deltaX, deltaY, historyDeltaX, historyDeltaY);
43061604e48SAxel Dörfler 
43161604e48SAxel Dörfler 		// Send single messages for each event
43261604e48SAxel Dörfler 
43361604e48SAxel Dörfler 		if (buttons != 0) {
43461604e48SAxel Dörfler 			bool pressedButton = (buttons & movements.buttons) > 0;
43561604e48SAxel Dörfler 			BMessage* message = _BuildMouseMessage(
43661604e48SAxel Dörfler 				pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP,
43761604e48SAxel Dörfler 				movements.timestamp, remappedButtons, deltaX, deltaY);
43861604e48SAxel Dörfler 			if (message != NULL) {
43961604e48SAxel Dörfler 				if (pressedButton) {
44061604e48SAxel Dörfler 					message->AddInt32("clicks", movements.clicks);
441e01a0431SStephan Aßmus 					LOG_EVENT("B_MOUSE_DOWN\n");
44261604e48SAxel Dörfler 				} else
443e01a0431SStephan Aßmus 					LOG_EVENT("B_MOUSE_UP\n");
44461604e48SAxel Dörfler 
44561604e48SAxel Dörfler 				fTarget.EnqueueMessage(message);
44661604e48SAxel Dörfler 				lastButtons = movements.buttons;
44761604e48SAxel Dörfler 			}
44861604e48SAxel Dörfler 		}
44961604e48SAxel Dörfler 
45045f11ce8SStephan Aßmus 		if (movements.xdelta != 0 || movements.ydelta != 0) {
45145f11ce8SStephan Aßmus 			BMessage* message = _BuildMouseMessage(B_MOUSE_MOVED,
45245f11ce8SStephan Aßmus 				movements.timestamp, remappedButtons, deltaX, deltaY);
45345f11ce8SStephan Aßmus 			if (message != NULL)
45445f11ce8SStephan Aßmus 				fTarget.EnqueueMessage(message);
45545f11ce8SStephan Aßmus 		}
45645f11ce8SStephan Aßmus 
45761604e48SAxel Dörfler 		if ((movements.wheel_ydelta != 0) || (movements.wheel_xdelta != 0)) {
458c5555ad3SStephan Aßmus 			BMessage* message = new BMessage(B_MOUSE_WHEEL_CHANGED);
45961604e48SAxel Dörfler 			if (message == NULL)
46061604e48SAxel Dörfler 				continue;
46161604e48SAxel Dörfler 
46261604e48SAxel Dörfler 			if (message->AddInt64("when", movements.timestamp) == B_OK
4633bf47305SAxel Dörfler 				&& message->AddFloat("be:wheel_delta_x",
4643bf47305SAxel Dörfler 					movements.wheel_xdelta) == B_OK
4653bf47305SAxel Dörfler 				&& message->AddFloat("be:wheel_delta_y",
4663bf47305SAxel Dörfler 					movements.wheel_ydelta) == B_OK)
46761604e48SAxel Dörfler 				fTarget.EnqueueMessage(message);
46861604e48SAxel Dörfler 			else
46961604e48SAxel Dörfler 				delete message;
47061604e48SAxel Dörfler 		}
4717d1d7033SStephan Aßmus 
4727d1d7033SStephan Aßmus #if !USE_REGULAR_INTERVAL
4737d1d7033SStephan Aßmus 		snooze(kTransferDelay);
4747d1d7033SStephan Aßmus #endif
47561604e48SAxel Dörfler 	}
47661604e48SAxel Dörfler }
47761604e48SAxel Dörfler 
47861604e48SAxel Dörfler 
4795125eae2SStephan Aßmus void
4805125eae2SStephan Aßmus MouseDevice::_ControlThreadCleanup()
48161604e48SAxel Dörfler {
4825125eae2SStephan Aßmus 	// NOTE: Only executed when the control thread detected an error
4835125eae2SStephan Aßmus 	// and from within the control thread!
4845125eae2SStephan Aßmus 
4855125eae2SStephan Aßmus 	if (fActive) {
4865125eae2SStephan Aßmus 		fThread = -1;
4875125eae2SStephan Aßmus 		fTarget._RemoveDevice(fPath.String());
4885125eae2SStephan Aßmus 	} else {
4895125eae2SStephan Aßmus 		// In case active is already false, another thread
4905125eae2SStephan Aßmus 		// waits for this thread to quit, and may already hold
4915125eae2SStephan Aßmus 		// locks that _RemoveDevice() wants to acquire. In another
4925125eae2SStephan Aßmus 		// words, the device is already being removed, so we simply
4935125eae2SStephan Aßmus 		// quit here.
4945125eae2SStephan Aßmus 	}
4955125eae2SStephan Aßmus }
4965125eae2SStephan Aßmus 
4975125eae2SStephan Aßmus 
4985125eae2SStephan Aßmus void
4995125eae2SStephan Aßmus MouseDevice::_UpdateSettings()
5005125eae2SStephan Aßmus {
5015125eae2SStephan Aßmus 	MD_CALLED();
5025125eae2SStephan Aßmus 
5035125eae2SStephan Aßmus 	// retrieve current values
5045125eae2SStephan Aßmus 
5055125eae2SStephan Aßmus 	if (get_mouse_map(&fSettings.map) != B_OK)
5065125eae2SStephan Aßmus 		LOG_ERR("error when get_mouse_map\n");
5075125eae2SStephan Aßmus 	else {
5085125eae2SStephan Aßmus 		fDeviceRemapsButtons
5095125eae2SStephan Aßmus 			= ioctl(fDevice, MS_SET_MAP, &fSettings.map) == B_OK;
5105125eae2SStephan Aßmus 	}
5115125eae2SStephan Aßmus 
5125125eae2SStephan Aßmus 	if (get_click_speed(&fSettings.click_speed) != B_OK)
5135125eae2SStephan Aßmus 		LOG_ERR("error when get_click_speed\n");
5145125eae2SStephan Aßmus 	else
5155125eae2SStephan Aßmus 		ioctl(fDevice, MS_SET_CLICKSPEED, &fSettings.click_speed);
5165125eae2SStephan Aßmus 
5175125eae2SStephan Aßmus 	if (get_mouse_speed(&fSettings.accel.speed) != B_OK)
5185125eae2SStephan Aßmus 		LOG_ERR("error when get_mouse_speed\n");
5195125eae2SStephan Aßmus 	else {
5205125eae2SStephan Aßmus 		if (get_mouse_acceleration(&fSettings.accel.accel_factor) != B_OK)
5215125eae2SStephan Aßmus 			LOG_ERR("error when get_mouse_acceleration\n");
5225125eae2SStephan Aßmus 		else {
5235125eae2SStephan Aßmus 			mouse_accel accel;
5245125eae2SStephan Aßmus 			ioctl(fDevice, MS_GET_ACCEL, &accel);
5255125eae2SStephan Aßmus 			accel.speed = fSettings.accel.speed;
5265125eae2SStephan Aßmus 			accel.accel_factor = fSettings.accel.accel_factor;
5275125eae2SStephan Aßmus 			ioctl(fDevice, MS_SET_ACCEL, &fSettings.accel);
5285125eae2SStephan Aßmus 		}
5295125eae2SStephan Aßmus 	}
5305125eae2SStephan Aßmus 
5315125eae2SStephan Aßmus 	if (get_mouse_type(&fSettings.type) != B_OK)
5325125eae2SStephan Aßmus 		LOG_ERR("error when get_mouse_type\n");
5335125eae2SStephan Aßmus 	else
5345125eae2SStephan Aßmus 		ioctl(fDevice, MS_SET_TYPE, &fSettings.type);
53561604e48SAxel Dörfler }
53661604e48SAxel Dörfler 
53761604e48SAxel Dörfler 
538167f43a2SStephan Aßmus status_t
539167f43a2SStephan Aßmus MouseDevice::_GetTouchpadSettingsPath(BPath& path)
540167f43a2SStephan Aßmus {
541167f43a2SStephan Aßmus 	status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
542167f43a2SStephan Aßmus 	if (status < B_OK)
543167f43a2SStephan Aßmus 		return status;
544167f43a2SStephan Aßmus 	return path.Append(TOUCHPAD_SETTINGS_FILE);
545167f43a2SStephan Aßmus }
546167f43a2SStephan Aßmus 
547167f43a2SStephan Aßmus 
548167f43a2SStephan Aßmus status_t
549167f43a2SStephan Aßmus MouseDevice::_ReadTouchpadSettingsMsg(BMessage* message)
550167f43a2SStephan Aßmus {
5513bf47305SAxel Dörfler 	message->FindBool("scroll_twofinger", &fTouchpadSettings.scroll_twofinger);
552*fc548b41SAxel Dörfler 	message->FindBool("scroll_twofinger_horizontal",
553*fc548b41SAxel Dörfler 		&fTouchpadSettings.scroll_twofinger_horizontal);
554167f43a2SStephan Aßmus 	message->FindFloat("scroll_rightrange",
5553bf47305SAxel Dörfler 		&fTouchpadSettings.scroll_rightrange);
556167f43a2SStephan Aßmus 	message->FindFloat("scroll_bottomrange",
5573bf47305SAxel Dörfler 		&fTouchpadSettings.scroll_bottomrange);
5583bf47305SAxel Dörfler 
559167f43a2SStephan Aßmus 	message->FindInt16("scroll_xstepsize",
5603bf47305SAxel Dörfler 		(int16*)&fTouchpadSettings.scroll_xstepsize);
561167f43a2SStephan Aßmus 	message->FindInt16("scroll_ystepsize",
5623bf47305SAxel Dörfler 		(int16*)&fTouchpadSettings.scroll_ystepsize);
563167f43a2SStephan Aßmus 	message->FindInt8("scroll_acceleration",
5643bf47305SAxel Dörfler 		(int8*)&fTouchpadSettings.scroll_acceleration);
565167f43a2SStephan Aßmus 	message->FindInt8("tapgesture_sensibility",
5663bf47305SAxel Dörfler 		(int8*)&fTouchpadSettings.tapgesture_sensibility);
567167f43a2SStephan Aßmus 
568167f43a2SStephan Aßmus 	return B_OK;
569167f43a2SStephan Aßmus }
570167f43a2SStephan Aßmus 
571167f43a2SStephan Aßmus 
572167f43a2SStephan Aßmus status_t
573167f43a2SStephan Aßmus MouseDevice::_UpdateTouchpadSettings()
574167f43a2SStephan Aßmus {
575167f43a2SStephan Aßmus 	if (fIsTouchpad) {
576167f43a2SStephan Aßmus 		ioctl(fDevice, MS_SET_TOUCHPAD_SETTINGS, &fTouchpadSettings);
577167f43a2SStephan Aßmus 		return B_OK;
578167f43a2SStephan Aßmus 	}
579167f43a2SStephan Aßmus 	return B_ERROR;
580167f43a2SStephan Aßmus }
581167f43a2SStephan Aßmus 
582167f43a2SStephan Aßmus 
58361604e48SAxel Dörfler BMessage*
58461604e48SAxel Dörfler MouseDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons,
58561604e48SAxel Dörfler 	int32 deltaX, int32 deltaY) const
58661604e48SAxel Dörfler {
58761604e48SAxel Dörfler 	BMessage* message = new BMessage(what);
58861604e48SAxel Dörfler 	if (message == NULL)
58961604e48SAxel Dörfler 		return NULL;
59061604e48SAxel Dörfler 
59161604e48SAxel Dörfler 	if (message->AddInt64("when", when) < B_OK
59261604e48SAxel Dörfler 		|| message->AddInt32("buttons", buttons) < B_OK
59361604e48SAxel Dörfler 		|| message->AddInt32("x", deltaX) < B_OK
59461604e48SAxel Dörfler 		|| message->AddInt32("y", deltaY) < B_OK) {
59561604e48SAxel Dörfler 		delete message;
59661604e48SAxel Dörfler 		return NULL;
59761604e48SAxel Dörfler 	}
59861604e48SAxel Dörfler 
59961604e48SAxel Dörfler 	return message;
60061604e48SAxel Dörfler }
60161604e48SAxel Dörfler 
60261604e48SAxel Dörfler 
60361604e48SAxel Dörfler void
60461604e48SAxel Dörfler MouseDevice::_ComputeAcceleration(const mouse_movement& movements,
6056e094221SStephan Aßmus 	int32& _deltaX, int32& _deltaY, float& historyDeltaX,
6066e094221SStephan Aßmus 	float& historyDeltaY) const
60761604e48SAxel Dörfler {
60842b505fbSAxel Dörfler 	// basic mouse speed
6096e094221SStephan Aßmus 	float deltaX = (float)movements.xdelta * fSettings.accel.speed / 65536.0
6106e094221SStephan Aßmus 		+ historyDeltaX;
6116e094221SStephan Aßmus 	float deltaY = (float)movements.ydelta * fSettings.accel.speed / 65536.0
6126e094221SStephan Aßmus 		+ historyDeltaY;
61342b505fbSAxel Dörfler 
61442b505fbSAxel Dörfler 	// acceleration
61542b505fbSAxel Dörfler 	double acceleration = 1;
61642b505fbSAxel Dörfler 	if (fSettings.accel.accel_factor) {
617fafab827SAxel Dörfler 		acceleration = 1 + sqrt(deltaX * deltaX + deltaY * deltaY)
61874ef1621SAxel Dörfler 			* fSettings.accel.accel_factor / 524288.0;
61942b505fbSAxel Dörfler 	}
62042b505fbSAxel Dörfler 
6216e094221SStephan Aßmus 	deltaX *= acceleration;
6226e094221SStephan Aßmus 	deltaY *= acceleration;
62342b505fbSAxel Dörfler 
6246e094221SStephan Aßmus 	if (deltaX >= 0)
6256e094221SStephan Aßmus 		_deltaX = (int32)floorf(deltaX);
626fafab827SAxel Dörfler 	else
6276e094221SStephan Aßmus 		_deltaX = (int32)ceilf(deltaX);
6286e094221SStephan Aßmus 
6296e094221SStephan Aßmus 	if (deltaY >= 0)
6306e094221SStephan Aßmus 		_deltaY = (int32)floorf(deltaY);
6316e094221SStephan Aßmus 	else
6326e094221SStephan Aßmus 		_deltaY = (int32)ceilf(deltaY);
6336e094221SStephan Aßmus 
6346e094221SStephan Aßmus 	historyDeltaX = deltaX - _deltaX;
6356e094221SStephan Aßmus 	historyDeltaY = deltaY - _deltaY;
63661604e48SAxel Dörfler }
63761604e48SAxel Dörfler 
63833efb919SStefano Ceccherini 
63923b47e0bSJérôme Duval uint32
64061604e48SAxel Dörfler MouseDevice::_RemapButtons(uint32 buttons) const
64123b47e0bSJérôme Duval {
64261604e48SAxel Dörfler 	if (fDeviceRemapsButtons)
64323b47e0bSJérôme Duval 		return buttons;
64423b47e0bSJérôme Duval 
64561604e48SAxel Dörfler 	uint32 newButtons = 0;
64623b47e0bSJérôme Duval 	for (int32 i = 0; buttons; i++) {
64723b47e0bSJérôme Duval 		if (buttons & 0x1) {
64821631085SStephan Aßmus #if defined(HAIKU_TARGET_PLATFORM_HAIKU) || defined(HAIKU_TARGET_PLATFORM_DANO)
64961604e48SAxel Dörfler 			newButtons |= fSettings.map.button[i];
65023b47e0bSJérôme Duval #else
65123b47e0bSJérôme Duval 			if (i == 0)
65261604e48SAxel Dörfler 				newButtons |= fSettings.map.left;
65323b47e0bSJérôme Duval 			if (i == 1)
65461604e48SAxel Dörfler 				newButtons |= fSettings.map.right;
65523b47e0bSJérôme Duval 			if (i == 2)
65661604e48SAxel Dörfler 				newButtons |= fSettings.map.middle;
65723b47e0bSJérôme Duval #endif
65823b47e0bSJérôme Duval 		}
65923b47e0bSJérôme Duval 		buttons >>= 1;
66023b47e0bSJérôme Duval 	}
66123b47e0bSJérôme Duval 
66261604e48SAxel Dörfler 	return newButtons;
66323b47e0bSJérôme Duval }
66423b47e0bSJérôme Duval 
66523b47e0bSJérôme Duval 
66661604e48SAxel Dörfler //	#pragma mark -
66761604e48SAxel Dörfler 
66861604e48SAxel Dörfler 
66961604e48SAxel Dörfler MouseInputDevice::MouseInputDevice()
670b6a7b204SAxel Dörfler 	:
6715125eae2SStephan Aßmus 	fDevices(2, true),
6725125eae2SStephan Aßmus 	fDeviceListLock("MouseInputDevice list")
67361604e48SAxel Dörfler {
674e01a0431SStephan Aßmus 	MID_CALLED();
67561604e48SAxel Dörfler 
676c5555ad3SStephan Aßmus 	StartMonitoringDevice(kMouseDevicesDirectory);
677167f43a2SStephan Aßmus 	StartMonitoringDevice(kTouchpadDevicesDirectory);
6789dd2d40eSStephan Aßmus 	_RecursiveScan(kMouseDevicesDirectory);
679167f43a2SStephan Aßmus 	_RecursiveScan(kTouchpadDevicesDirectory);
68061604e48SAxel Dörfler }
68161604e48SAxel Dörfler 
68261604e48SAxel Dörfler 
68361604e48SAxel Dörfler MouseInputDevice::~MouseInputDevice()
68461604e48SAxel Dörfler {
685e01a0431SStephan Aßmus 	MID_CALLED();
686e01a0431SStephan Aßmus 
687167f43a2SStephan Aßmus 	StopMonitoringDevice(kTouchpadDevicesDirectory);
688b6a7b204SAxel Dörfler 	StopMonitoringDevice(kMouseDevicesDirectory);
689e01a0431SStephan Aßmus 	fDevices.MakeEmpty();
69061604e48SAxel Dörfler }
69161604e48SAxel Dörfler 
69261604e48SAxel Dörfler 
69361604e48SAxel Dörfler status_t
69461604e48SAxel Dörfler MouseInputDevice::InitCheck()
69561604e48SAxel Dörfler {
696e01a0431SStephan Aßmus 	MID_CALLED();
697e01a0431SStephan Aßmus 
698d246d9beSStefano Ceccherini 	return BInputServerDevice::InitCheck();
69961604e48SAxel Dörfler }
70061604e48SAxel Dörfler 
70161604e48SAxel Dörfler 
70261604e48SAxel Dörfler status_t
70361604e48SAxel Dörfler MouseInputDevice::Start(const char* name, void* cookie)
70461604e48SAxel Dörfler {
705e01a0431SStephan Aßmus 	MID_CALLED();
706e01a0431SStephan Aßmus 
70761604e48SAxel Dörfler 	MouseDevice* device = (MouseDevice*)cookie;
70861604e48SAxel Dörfler 
70961604e48SAxel Dörfler 	return device->Start();
71061604e48SAxel Dörfler }
71161604e48SAxel Dörfler 
71261604e48SAxel Dörfler 
71361604e48SAxel Dörfler status_t
71461604e48SAxel Dörfler MouseInputDevice::Stop(const char* name, void* cookie)
71561604e48SAxel Dörfler {
716e01a0431SStephan Aßmus 	TRACE("%s(%s)\n", __PRETTY_FUNCTION__, name);
71761604e48SAxel Dörfler 
718e01a0431SStephan Aßmus 	MouseDevice* device = (MouseDevice*)cookie;
71961604e48SAxel Dörfler 	device->Stop();
720e01a0431SStephan Aßmus 
72161604e48SAxel Dörfler 	return B_OK;
72261604e48SAxel Dörfler }
72361604e48SAxel Dörfler 
72461604e48SAxel Dörfler 
72561604e48SAxel Dörfler status_t
72661604e48SAxel Dörfler MouseInputDevice::Control(const char* name, void* cookie,
72761604e48SAxel Dörfler 	uint32 command, BMessage* message)
72861604e48SAxel Dörfler {
729e01a0431SStephan Aßmus 	TRACE("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command);
730e01a0431SStephan Aßmus 
73161604e48SAxel Dörfler 	MouseDevice* device = (MouseDevice*)cookie;
73261604e48SAxel Dörfler 
73361604e48SAxel Dörfler 	if (command == B_NODE_MONITOR)
73461604e48SAxel Dörfler 		return _HandleMonitor(message);
73561604e48SAxel Dörfler 
736167f43a2SStephan Aßmus 	if (command == MS_SET_TOUCHPAD_SETTINGS)
737167f43a2SStephan Aßmus 		return device->UpdateTouchpadSettings(message);
738167f43a2SStephan Aßmus 
73961604e48SAxel Dörfler 	if (command >= B_MOUSE_TYPE_CHANGED
74061604e48SAxel Dörfler 		&& command <= B_MOUSE_ACCELERATION_CHANGED)
74161604e48SAxel Dörfler 		return device->UpdateSettings();
74261604e48SAxel Dörfler 
74361604e48SAxel Dörfler 	return B_BAD_VALUE;
74461604e48SAxel Dörfler }
74561604e48SAxel Dörfler 
74661604e48SAxel Dörfler 
74761604e48SAxel Dörfler status_t
74861604e48SAxel Dörfler MouseInputDevice::_HandleMonitor(BMessage* message)
74961604e48SAxel Dörfler {
750e01a0431SStephan Aßmus 	MID_CALLED();
75161604e48SAxel Dörfler 
752b6a7b204SAxel Dörfler 	const char* path;
75361604e48SAxel Dörfler 	int32 opcode;
754b6a7b204SAxel Dörfler 	if (message->FindInt32("opcode", &opcode) != B_OK
755c5555ad3SStephan Aßmus 		|| (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED)
756b6a7b204SAxel Dörfler 		|| message->FindString("path", &path) != B_OK)
75761604e48SAxel Dörfler 		return B_BAD_VALUE;
75861604e48SAxel Dörfler 
75961604e48SAxel Dörfler 	if (opcode == B_ENTRY_CREATED)
760b6a7b204SAxel Dörfler 		return _AddDevice(path);
76161604e48SAxel Dörfler 
762c5555ad3SStephan Aßmus #if 0
763b6a7b204SAxel Dörfler 	return _RemoveDevice(path);
764c5555ad3SStephan Aßmus #else
765c5555ad3SStephan Aßmus 	// Don't handle B_ENTRY_REMOVED, let the control thread take care of it.
766c5555ad3SStephan Aßmus 	return B_OK;
767c5555ad3SStephan Aßmus #endif
76861604e48SAxel Dörfler }
76961604e48SAxel Dörfler 
77061604e48SAxel Dörfler 
77161604e48SAxel Dörfler void
77261604e48SAxel Dörfler MouseInputDevice::_RecursiveScan(const char* directory)
77361604e48SAxel Dörfler {
774e01a0431SStephan Aßmus 	MID_CALLED();
77561604e48SAxel Dörfler 
77661604e48SAxel Dörfler 	BEntry entry;
77761604e48SAxel Dörfler 	BDirectory dir(directory);
77861604e48SAxel Dörfler 	while (dir.GetNextEntry(&entry) == B_OK) {
77961604e48SAxel Dörfler 		BPath path;
78061604e48SAxel Dörfler 		entry.GetPath(&path);
78161604e48SAxel Dörfler 
78261604e48SAxel Dörfler 		if (!strcmp(path.Leaf(), "serial")) {
78361604e48SAxel Dörfler 			// skip serial
78461604e48SAxel Dörfler 			continue;
78561604e48SAxel Dörfler 		}
78661604e48SAxel Dörfler 
78761604e48SAxel Dörfler 		if (entry.IsDirectory())
78861604e48SAxel Dörfler 			_RecursiveScan(path.Path());
78961604e48SAxel Dörfler 		else
79061604e48SAxel Dörfler 			_AddDevice(path.Path());
79161604e48SAxel Dörfler 	}
79261604e48SAxel Dörfler }
79361604e48SAxel Dörfler 
794e01a0431SStephan Aßmus 
795e01a0431SStephan Aßmus MouseDevice*
7965125eae2SStephan Aßmus MouseInputDevice::_FindDevice(const char* path) const
797e01a0431SStephan Aßmus {
798e01a0431SStephan Aßmus 	MID_CALLED();
799e01a0431SStephan Aßmus 
800e01a0431SStephan Aßmus 	for (int32 i = fDevices.CountItems() - 1; i >= 0; i--) {
801e01a0431SStephan Aßmus 		MouseDevice* device = fDevices.ItemAt(i);
802e01a0431SStephan Aßmus 		if (strcmp(device->Path(), path) == 0)
803e01a0431SStephan Aßmus 			return device;
804e01a0431SStephan Aßmus 	}
805e01a0431SStephan Aßmus 
806e01a0431SStephan Aßmus 	return NULL;
807e01a0431SStephan Aßmus }
808e01a0431SStephan Aßmus 
809e01a0431SStephan Aßmus 
810e01a0431SStephan Aßmus status_t
811e01a0431SStephan Aßmus MouseInputDevice::_AddDevice(const char* path)
812e01a0431SStephan Aßmus {
813e01a0431SStephan Aßmus 	MID_CALLED();
814e01a0431SStephan Aßmus 
8155125eae2SStephan Aßmus 	BAutolock _(fDeviceListLock);
8165125eae2SStephan Aßmus 
817e01a0431SStephan Aßmus 	_RemoveDevice(path);
818e01a0431SStephan Aßmus 
819e01a0431SStephan Aßmus 	MouseDevice* device = new(std::nothrow) MouseDevice(*this, path);
820e01a0431SStephan Aßmus 	if (!device) {
821e01a0431SStephan Aßmus 		TRACE("No memory\n");
822e01a0431SStephan Aßmus 		return B_NO_MEMORY;
823e01a0431SStephan Aßmus 	}
824e01a0431SStephan Aßmus 
825e01a0431SStephan Aßmus 	if (!fDevices.AddItem(device)) {
826e01a0431SStephan Aßmus 		TRACE("No memory in list\n");
827e01a0431SStephan Aßmus 		delete device;
828e01a0431SStephan Aßmus 		return B_NO_MEMORY;
829e01a0431SStephan Aßmus 	}
830e01a0431SStephan Aßmus 
831e01a0431SStephan Aßmus 	input_device_ref* devices[2];
832e01a0431SStephan Aßmus 	devices[0] = device->DeviceRef();
833e01a0431SStephan Aßmus 	devices[1] = NULL;
834e01a0431SStephan Aßmus 
835e01a0431SStephan Aßmus 	TRACE("adding path: %s, name: %s\n", path, devices[0]->name);
836e01a0431SStephan Aßmus 
837e01a0431SStephan Aßmus 	return RegisterDevices(devices);
838e01a0431SStephan Aßmus }
839e01a0431SStephan Aßmus 
840e01a0431SStephan Aßmus 
841e01a0431SStephan Aßmus status_t
842e01a0431SStephan Aßmus MouseInputDevice::_RemoveDevice(const char* path)
843e01a0431SStephan Aßmus {
844e01a0431SStephan Aßmus 	MID_CALLED();
845e01a0431SStephan Aßmus 
8465125eae2SStephan Aßmus 	BAutolock _(fDeviceListLock);
8475125eae2SStephan Aßmus 
848e01a0431SStephan Aßmus 	MouseDevice* device = _FindDevice(path);
849e01a0431SStephan Aßmus 	if (device == NULL) {
850e01a0431SStephan Aßmus 		TRACE("%s not found\n", path);
851e01a0431SStephan Aßmus 		return B_ENTRY_NOT_FOUND;
852e01a0431SStephan Aßmus 	}
853e01a0431SStephan Aßmus 
854e01a0431SStephan Aßmus 	input_device_ref* devices[2];
855e01a0431SStephan Aßmus 	devices[0] = device->DeviceRef();
856e01a0431SStephan Aßmus 	devices[1] = NULL;
857e01a0431SStephan Aßmus 
858e01a0431SStephan Aßmus 	TRACE("removing path: %s, name: %s\n", path, devices[0]->name);
859e01a0431SStephan Aßmus 
860e01a0431SStephan Aßmus 	UnregisterDevices(devices);
861e01a0431SStephan Aßmus 
862e01a0431SStephan Aßmus 	fDevices.RemoveItem(device);
863e01a0431SStephan Aßmus 
864e01a0431SStephan Aßmus 	return B_OK;
865e01a0431SStephan Aßmus }
866