xref: /haiku/src/add-ons/input_server/devices/mouse/MouseInputDevice.cpp (revision 61604e487540ca4fe90f8d47e309e5b698bf23d0)
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>
20*61604e48SAxel Dörfler #include <View.h>
21*61604e48SAxel Dörfler 
22*61604e48SAxel Dörfler #include <errno.h>
23*61604e48SAxel Dörfler #include <new>
24*61604e48SAxel Dörfler #include <stdio.h>
25*61604e48SAxel Dörfler #include <stdlib.h>
26*61604e48SAxel Dörfler #include <unistd.h>
2733efb919SStefano Ceccherini 
283aa69c78SStefano Ceccherini #if DEBUG
29c2fbfb71SJérôme Duval FILE *MouseInputDevice::sLogFile = NULL;
30*61604e48SAxel Dörfler #	define LOG_ERR(text...) LOG(text)
313aa69c78SStefano Ceccherini #else
32c2fbfb71SJérôme Duval #	define LOG(text...)
33c2fbfb71SJérôme Duval #	define LOG_ERR(text...) fprintf(stderr, text)
343aa69c78SStefano Ceccherini #endif
353aa69c78SStefano Ceccherini 
36c2fbfb71SJérôme Duval #define CALLED() LOG("%s\n", __PRETTY_FUNCTION__)
3733efb919SStefano Ceccherini 
3823b47e0bSJérôme Duval #ifndef B_FIRST_REAL_TIME_PRIORITY
3923b47e0bSJérôme Duval #	define B_FIRST_REAL_TIME_PRIORITY B_REAL_TIME_DISPLAY_PRIORITY
4023b47e0bSJérôme Duval #endif
41*61604e48SAxel Dörfler 
4233efb919SStefano Ceccherini const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4;
4333efb919SStefano Ceccherini const static char *kMouseDevicesDirectory = "/dev/input/mouse";
4433efb919SStefano Ceccherini 
4533efb919SStefano Ceccherini // "/dev/" is automatically prepended by StartMonitoringDevice()
46f0bac935SJérôme Duval const static char *kMouseDevicesDirectoryPS2 = "input/mouse/ps2";
4733efb919SStefano Ceccherini const static char *kMouseDevicesDirectoryUSB = "input/mouse/usb";
4833efb919SStefano Ceccherini 
49*61604e48SAxel Dörfler class MouseDevice {
50*61604e48SAxel Dörfler 	public:
51*61604e48SAxel Dörfler 		MouseDevice(BInputServerDevice& target, const char* path);
52*61604e48SAxel Dörfler 		~MouseDevice();
5333efb919SStefano Ceccherini 
54*61604e48SAxel Dörfler 		status_t Start();
55*61604e48SAxel Dörfler 		void Stop();
56*61604e48SAxel Dörfler 
57*61604e48SAxel Dörfler 		status_t UpdateSettings();
58*61604e48SAxel Dörfler 
59*61604e48SAxel Dörfler 		const char* Path() const { return fPath.String(); }
60*61604e48SAxel Dörfler 		input_device_ref* DeviceRef() { return &fDeviceRef; }
61*61604e48SAxel Dörfler 
62*61604e48SAxel Dörfler 	private:
63*61604e48SAxel Dörfler 		void _Run();
64*61604e48SAxel Dörfler 		static status_t _ThreadFunction(void *arg);
65*61604e48SAxel Dörfler 
66*61604e48SAxel Dörfler 		BMessage* _BuildMouseMessage(uint32 what, uint64 when, uint32 buttons,
67*61604e48SAxel Dörfler 					int32 deltaX, int32 deltaY) const;
68*61604e48SAxel Dörfler 		void _ComputeAcceleration(const mouse_movement& movements,
69*61604e48SAxel Dörfler 					int32& deltaX, int32& deltaY) const;
70*61604e48SAxel Dörfler 		uint32 _RemapButtons(uint32 buttons) const;
71*61604e48SAxel Dörfler 
72*61604e48SAxel Dörfler 		char* _BuildShortName() const;
73*61604e48SAxel Dörfler 
74*61604e48SAxel Dörfler 	private:
75*61604e48SAxel Dörfler 		BInputServerDevice& fTarget;
76*61604e48SAxel Dörfler 		BString	fPath;
77*61604e48SAxel Dörfler 		int fDevice;
78*61604e48SAxel Dörfler 
79*61604e48SAxel Dörfler 		input_device_ref fDeviceRef;
80*61604e48SAxel Dörfler 		mouse_settings fSettings;
81*61604e48SAxel Dörfler 		bool fDeviceRemapsButtons;
82*61604e48SAxel Dörfler 
83*61604e48SAxel Dörfler 		thread_id fThread;
84*61604e48SAxel Dörfler 		volatile bool fActive;
850dbc4befSStefano Ceccherini };
860dbc4befSStefano Ceccherini 
870dbc4befSStefano Ceccherini 
88*61604e48SAxel Dörfler #if DEBUG
89*61604e48SAxel Dörfler inline void
90*61604e48SAxel Dörfler LOG(const char *fmt, ...)
91*61604e48SAxel Dörfler {
92*61604e48SAxel Dörfler 	char buf[1024];
93*61604e48SAxel Dörfler 	va_list ap;
94*61604e48SAxel Dörfler 	va_start(ap, fmt);
95*61604e48SAxel Dörfler 	vsprintf(buf, fmt, ap); va_end(ap);
96*61604e48SAxel Dörfler     fputs(buf, MouseInputDevice::sLogFile); fflush(MouseInputDevice::sLogFile);
97*61604e48SAxel Dörfler }
98*61604e48SAxel Dörfler #endif
994c0af4a8SStefano Ceccherini 
1004c0af4a8SStefano Ceccherini 
101*61604e48SAxel Dörfler extern "C" BInputServerDevice *
10261d7deeeSJérôme Duval instantiate_input_device()
10361d7deeeSJérôme Duval {
10461d7deeeSJérôme Duval 	return new MouseInputDevice();
10561d7deeeSJérôme Duval }
10661d7deeeSJérôme Duval 
10761d7deeeSJérôme Duval 
108*61604e48SAxel Dörfler //	#pragma mark -
109*61604e48SAxel Dörfler 
110*61604e48SAxel Dörfler 
111*61604e48SAxel Dörfler MouseDevice::MouseDevice(BInputServerDevice& target, const char *driverPath)
112*61604e48SAxel Dörfler 	:
113*61604e48SAxel Dörfler 	fTarget(target),
114*61604e48SAxel Dörfler 	fDevice(-1),
115*61604e48SAxel Dörfler 	fThread(-1),
116*61604e48SAxel Dörfler 	fActive(false)
11761d7deeeSJérôme Duval {
118*61604e48SAxel Dörfler 	fPath = driverPath;
119*61604e48SAxel Dörfler 
120*61604e48SAxel Dörfler 	fDeviceRef.name = _BuildShortName();
121*61604e48SAxel Dörfler 	fDeviceRef.type = B_POINTING_DEVICE;
122*61604e48SAxel Dörfler 	fDeviceRef.cookie = this;
123*61604e48SAxel Dörfler 
124*61604e48SAxel Dörfler #ifdef HAIKU_TARGET_PLATFORM_HAIKU
125*61604e48SAxel Dörfler 	fSettings.map.button[0] = B_PRIMARY_MOUSE_BUTTON;
126*61604e48SAxel Dörfler 	fSettings.map.button[1] = B_SECONDARY_MOUSE_BUTTON;
127*61604e48SAxel Dörfler 	fSettings.map.button[2] = B_TERTIARY_MOUSE_BUTTON;
1283aa69c78SStefano Ceccherini #endif
12933efb919SStefano Ceccherini 
130*61604e48SAxel Dörfler 	fDeviceRemapsButtons = false;
131*61604e48SAxel Dörfler };
13261d7deeeSJérôme Duval 
13361d7deeeSJérôme Duval 
134*61604e48SAxel Dörfler MouseDevice::~MouseDevice()
13561d7deeeSJérôme Duval {
136*61604e48SAxel Dörfler 	if (fActive)
137*61604e48SAxel Dörfler 		Stop();
13861d7deeeSJérôme Duval 
139*61604e48SAxel Dörfler 	free(fDeviceRef.name);
14061d7deeeSJérôme Duval }
14161d7deeeSJérôme Duval 
14261d7deeeSJérôme Duval 
14361d7deeeSJérôme Duval status_t
144*61604e48SAxel Dörfler MouseDevice::Start()
14553d77642SJérôme Duval {
146*61604e48SAxel Dörfler 	fDevice = open(fPath.String(), O_RDWR);
147*61604e48SAxel Dörfler 	if (fDevice < 0)
148*61604e48SAxel Dörfler 		return errno;
14933efb919SStefano Ceccherini 
150*61604e48SAxel Dörfler 	UpdateSettings();
15133efb919SStefano Ceccherini 
15233efb919SStefano Ceccherini 	char threadName[B_OS_NAME_LENGTH];
153*61604e48SAxel Dörfler 	snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", fDeviceRef.name);
15433efb919SStefano Ceccherini 
155*61604e48SAxel Dörfler 	fThread = spawn_thread(_ThreadFunction, threadName,
156*61604e48SAxel Dörfler 		kMouseThreadPriority, (void *)this);
1574c0af4a8SStefano Ceccherini 
15833efb919SStefano Ceccherini 	status_t status;
159*61604e48SAxel Dörfler 	if (fThread < B_OK)
160*61604e48SAxel Dörfler 		status = fThread;
161*61604e48SAxel Dörfler 	else {
162*61604e48SAxel Dörfler 		fActive = true;
163*61604e48SAxel Dörfler 		status = resume_thread(fThread);
164*61604e48SAxel Dörfler 	}
16533efb919SStefano Ceccherini 
166*61604e48SAxel Dörfler 	if (status < B_OK) {
167*61604e48SAxel Dörfler 		LOG_ERR("%s: can't spawn/resume watching thread: %s\n",
168*61604e48SAxel Dörfler 			fDeviceRef.name, strerror(status));
169*61604e48SAxel Dörfler 		close(fDevice);
170*61604e48SAxel Dörfler 		return status;
171*61604e48SAxel Dörfler 	}
172*61604e48SAxel Dörfler 
173c2fbfb71SJérôme Duval 	return B_OK;
17461d7deeeSJérôme Duval }
17561d7deeeSJérôme Duval 
17661d7deeeSJérôme Duval 
177c2fbfb71SJérôme Duval void
178*61604e48SAxel Dörfler MouseDevice::Stop()
179*61604e48SAxel Dörfler {
180*61604e48SAxel Dörfler 	fActive = false;
181*61604e48SAxel Dörfler 		// this will stop the thread as soon as it reads the next packet
182*61604e48SAxel Dörfler 
183*61604e48SAxel Dörfler 	if (fThread >= B_OK) {
184*61604e48SAxel Dörfler 		// unblock the thread, which might wait on a semaphore.
185*61604e48SAxel Dörfler 		suspend_thread(fThread);
186*61604e48SAxel Dörfler 		resume_thread(fThread);
187*61604e48SAxel Dörfler 
188*61604e48SAxel Dörfler 		status_t dummy;
189*61604e48SAxel Dörfler 		wait_for_thread(fThread, &dummy);
190*61604e48SAxel Dörfler 	}
191*61604e48SAxel Dörfler 
192*61604e48SAxel Dörfler 	close(fDevice);
193*61604e48SAxel Dörfler }
194*61604e48SAxel Dörfler 
195*61604e48SAxel Dörfler 
196*61604e48SAxel Dörfler void
197*61604e48SAxel Dörfler MouseDevice::_Run()
198*61604e48SAxel Dörfler {
199*61604e48SAxel Dörfler 	uint32 lastButtons = 0;
200*61604e48SAxel Dörfler 
201*61604e48SAxel Dörfler 	while (fActive) {
202*61604e48SAxel Dörfler 		mouse_movement movements;
203*61604e48SAxel Dörfler 		memset(&movements, 0, sizeof(movements));
204*61604e48SAxel Dörfler 
205*61604e48SAxel Dörfler 		if (ioctl(fDevice, MS_READ, &movements) != B_OK)
206*61604e48SAxel Dörfler 			return;
207*61604e48SAxel Dörfler 
208*61604e48SAxel Dörfler 		uint32 buttons = lastButtons ^ movements.buttons;
209*61604e48SAxel Dörfler 
210*61604e48SAxel Dörfler 		uint32 remappedButtons = _RemapButtons(movements.buttons);
211*61604e48SAxel Dörfler 		int32 deltaX, deltaY;
212*61604e48SAxel Dörfler 		_ComputeAcceleration(movements, deltaX, deltaY);
213*61604e48SAxel Dörfler 
214*61604e48SAxel Dörfler 		LOG("%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld, wheel_x:%ld, wheel_y:%ld\n",
215*61604e48SAxel Dörfler 			device->device_ref.name, movements.buttons, movements.xdelta, movements.ydelta,
216*61604e48SAxel Dörfler 			movements.clicks, movements.wheel_xdelta, movements.wheel_ydelta);
217*61604e48SAxel Dörfler 		LOG("%s: x: %ld, y: %ld\n", device->device_ref.name, deltaX, deltaY);
218*61604e48SAxel Dörfler 
219*61604e48SAxel Dörfler 		BMessage *message = NULL;
220*61604e48SAxel Dörfler 
221*61604e48SAxel Dörfler 		// Send single messages for each event
222*61604e48SAxel Dörfler 
223*61604e48SAxel Dörfler 		if (movements.xdelta != 0 || movements.ydelta != 0) {
224*61604e48SAxel Dörfler 			BMessage* message = _BuildMouseMessage(B_MOUSE_MOVED, movements.timestamp,
225*61604e48SAxel Dörfler 				remappedButtons, deltaX, deltaY);
226*61604e48SAxel Dörfler 			if (message != NULL)
227*61604e48SAxel Dörfler 				fTarget.EnqueueMessage(message);
228*61604e48SAxel Dörfler 		}
229*61604e48SAxel Dörfler 
230*61604e48SAxel Dörfler 		if (buttons != 0) {
231*61604e48SAxel Dörfler 			bool pressedButton = (buttons & movements.buttons) > 0;
232*61604e48SAxel Dörfler 			BMessage* message = _BuildMouseMessage(
233*61604e48SAxel Dörfler 				pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP,
234*61604e48SAxel Dörfler 				movements.timestamp, remappedButtons, deltaX, deltaY);
235*61604e48SAxel Dörfler 			if (message != NULL) {
236*61604e48SAxel Dörfler 				if (pressedButton) {
237*61604e48SAxel Dörfler 					message->AddInt32("clicks", movements.clicks);
238*61604e48SAxel Dörfler 					LOG("B_MOUSE_DOWN\n");
239*61604e48SAxel Dörfler 				} else
240*61604e48SAxel Dörfler 					LOG("B_MOUSE_UP\n");
241*61604e48SAxel Dörfler 
242*61604e48SAxel Dörfler 				fTarget.EnqueueMessage(message);
243*61604e48SAxel Dörfler 				lastButtons = movements.buttons;
244*61604e48SAxel Dörfler 			}
245*61604e48SAxel Dörfler 		}
246*61604e48SAxel Dörfler 
247*61604e48SAxel Dörfler 		if ((movements.wheel_ydelta != 0) || (movements.wheel_xdelta != 0)) {
248*61604e48SAxel Dörfler 			message = new BMessage(B_MOUSE_WHEEL_CHANGED);
249*61604e48SAxel Dörfler 			if (message == NULL)
250*61604e48SAxel Dörfler 				continue;
251*61604e48SAxel Dörfler 
252*61604e48SAxel Dörfler 			if (message->AddInt64("when", movements.timestamp) == B_OK
253*61604e48SAxel Dörfler 				&& message->AddFloat("be:wheel_delta_x", movements.wheel_xdelta) == B_OK
254*61604e48SAxel Dörfler 				&& message->AddFloat("be:wheel_delta_y", movements.wheel_ydelta) == B_OK)
255*61604e48SAxel Dörfler 				fTarget.EnqueueMessage(message);
256*61604e48SAxel Dörfler 			else
257*61604e48SAxel Dörfler 				delete message;
258*61604e48SAxel Dörfler 		}
259*61604e48SAxel Dörfler 	}
260*61604e48SAxel Dörfler }
261*61604e48SAxel Dörfler 
262*61604e48SAxel Dörfler 
263*61604e48SAxel Dörfler status_t
264*61604e48SAxel Dörfler MouseDevice::_ThreadFunction(void* arg)
265*61604e48SAxel Dörfler {
266*61604e48SAxel Dörfler 	MouseDevice* device = (MouseDevice *)arg;
267*61604e48SAxel Dörfler 	device->_Run();
268*61604e48SAxel Dörfler 	return B_OK;
269*61604e48SAxel Dörfler }
270*61604e48SAxel Dörfler 
271*61604e48SAxel Dörfler 
272*61604e48SAxel Dörfler BMessage*
273*61604e48SAxel Dörfler MouseDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons,
274*61604e48SAxel Dörfler 	int32 deltaX, int32 deltaY) const
275*61604e48SAxel Dörfler {
276*61604e48SAxel Dörfler 	BMessage* message = new BMessage(what);
277*61604e48SAxel Dörfler 	if (message == NULL)
278*61604e48SAxel Dörfler 		return NULL;
279*61604e48SAxel Dörfler 
280*61604e48SAxel Dörfler 	if (message->AddInt64("when", when) < B_OK
281*61604e48SAxel Dörfler 		|| message->AddInt32("buttons", buttons) < B_OK
282*61604e48SAxel Dörfler 		|| message->AddInt32("x", deltaX) < B_OK
283*61604e48SAxel Dörfler 		|| message->AddInt32("y", deltaY) < B_OK) {
284*61604e48SAxel Dörfler 		delete message;
285*61604e48SAxel Dörfler 		return NULL;
286*61604e48SAxel Dörfler 	}
287*61604e48SAxel Dörfler 
288*61604e48SAxel Dörfler 	return message;
289*61604e48SAxel Dörfler }
290*61604e48SAxel Dörfler 
291*61604e48SAxel Dörfler 
292*61604e48SAxel Dörfler status_t
293*61604e48SAxel Dörfler MouseDevice::UpdateSettings()
29433efb919SStefano Ceccherini {
295c2fbfb71SJérôme Duval 	CALLED();
296497d01f0SAxel Dörfler 
297*61604e48SAxel Dörfler 	// retrieve current values
298c2fbfb71SJérôme Duval 
299*61604e48SAxel Dörfler 	if (get_mouse_map(&fSettings.map) != B_OK)
300*61604e48SAxel Dörfler 		LOG_ERR("error when get_mouse_map\n");
301c2fbfb71SJérôme Duval 	else
302*61604e48SAxel Dörfler 		fDeviceRemapsButtons = ioctl(fDevice, MS_SET_MAP, &fSettings.map) == B_OK;
303*61604e48SAxel Dörfler 
304*61604e48SAxel Dörfler 	if (get_click_speed(&fSettings.click_speed) != B_OK)
305*61604e48SAxel Dörfler 		LOG_ERR("error when get_click_speed\n");
306*61604e48SAxel Dörfler 	else
307*61604e48SAxel Dörfler 		ioctl(fDevice, MS_SET_CLICKSPEED, &fSettings.click_speed);
308*61604e48SAxel Dörfler 
309*61604e48SAxel Dörfler 	if (get_mouse_speed(&fSettings.accel.speed) != B_OK)
310*61604e48SAxel Dörfler 		LOG_ERR("error when get_mouse_speed\n");
311*61604e48SAxel Dörfler 	else {
312*61604e48SAxel Dörfler 		if (get_mouse_acceleration(&fSettings.accel.accel_factor) != B_OK)
313*61604e48SAxel Dörfler 			LOG_ERR("error when get_mouse_acceleration\n");
314*61604e48SAxel Dörfler 		else {
315*61604e48SAxel Dörfler 			mouse_accel accel;
316*61604e48SAxel Dörfler 			ioctl(fDevice, MS_GET_ACCEL, &accel);
317*61604e48SAxel Dörfler 			accel.speed = fSettings.accel.speed;
318*61604e48SAxel Dörfler 			accel.accel_factor = fSettings.accel.accel_factor;
319*61604e48SAxel Dörfler 			ioctl(fDevice, MS_SET_ACCEL, &fSettings.accel);
32033efb919SStefano Ceccherini 		}
32133efb919SStefano Ceccherini 	}
32233efb919SStefano Ceccherini 
323*61604e48SAxel Dörfler 	if (get_mouse_type(&fSettings.type) != B_OK)
324*61604e48SAxel Dörfler 		LOG_ERR("error when get_mouse_type\n");
325*61604e48SAxel Dörfler 	else
326*61604e48SAxel Dörfler 		ioctl(fDevice, MS_SET_TYPE, &fSettings.type);
327*61604e48SAxel Dörfler 
328*61604e48SAxel Dörfler 	return B_OK;
329*61604e48SAxel Dörfler 
330*61604e48SAxel Dörfler }
331*61604e48SAxel Dörfler 
332*61604e48SAxel Dörfler 
333*61604e48SAxel Dörfler void
334*61604e48SAxel Dörfler MouseDevice::_ComputeAcceleration(const mouse_movement& movements,
335*61604e48SAxel Dörfler 	int32& deltaX, int32& deltaY) const
336*61604e48SAxel Dörfler {
337*61604e48SAxel Dörfler 	// TODO: add acceleration computing
338*61604e48SAxel Dörfler 	deltaX = movements.xdelta * fSettings.accel.speed >> 15;
339*61604e48SAxel Dörfler 	deltaY = movements.ydelta * fSettings.accel.speed >> 15;
340*61604e48SAxel Dörfler }
341*61604e48SAxel Dörfler 
34233efb919SStefano Ceccherini 
34323b47e0bSJérôme Duval uint32
344*61604e48SAxel Dörfler MouseDevice::_RemapButtons(uint32 buttons) const
34523b47e0bSJérôme Duval {
346*61604e48SAxel Dörfler 	if (fDeviceRemapsButtons)
34723b47e0bSJérôme Duval 		return buttons;
34823b47e0bSJérôme Duval 
349*61604e48SAxel Dörfler 	uint32 newButtons = 0;
35023b47e0bSJérôme Duval 	for (int32 i = 0; buttons; i++) {
35123b47e0bSJérôme Duval 		if (buttons & 0x1) {
35223b47e0bSJérôme Duval #ifdef HAIKU_TARGET_PLATFORM_HAIKU
353*61604e48SAxel Dörfler 			newButtons |= fSettings.map.button[i];
35423b47e0bSJérôme Duval #else
35523b47e0bSJérôme Duval 			if (i == 0)
356*61604e48SAxel Dörfler 				newButtons |= fSettings.map.left;
35723b47e0bSJérôme Duval 			if (i == 1)
358*61604e48SAxel Dörfler 				newButtons |= fSettings.map.right;
35923b47e0bSJérôme Duval 			if (i == 2)
360*61604e48SAxel Dörfler 				newButtons |= fSettings.map.middle;
36123b47e0bSJérôme Duval #endif
36223b47e0bSJérôme Duval 		}
36323b47e0bSJérôme Duval 		buttons >>= 1;
36423b47e0bSJérôme Duval 	}
36523b47e0bSJérôme Duval 
366*61604e48SAxel Dörfler 	return newButtons;
36723b47e0bSJérôme Duval }
36823b47e0bSJérôme Duval 
36923b47e0bSJérôme Duval 
370*61604e48SAxel Dörfler char *
371*61604e48SAxel Dörfler MouseDevice::_BuildShortName() const
3724c0af4a8SStefano Ceccherini {
373*61604e48SAxel Dörfler 	BString string(fPath);
37433efb919SStefano Ceccherini 	BString name;
37533efb919SStefano Ceccherini 
37633efb919SStefano Ceccherini 	int32 slash = string.FindLast("/");
3777dcdcad2SJérôme Duval 	string.CopyInto(name, slash + 1, string.Length() - slash);
3787dcdcad2SJérôme Duval 	int32 index = atoi(name.String()) + 1;
37933efb919SStefano Ceccherini 
3807dcdcad2SJérôme Duval 	int32 previousSlash = string.FindLast("/", slash);
3817dcdcad2SJérôme Duval 	string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1);
382497d01f0SAxel Dörfler 
383497d01f0SAxel Dörfler 	if (name == "ps2")
384497d01f0SAxel Dörfler 		name = "PS/2";
385497d01f0SAxel Dörfler 	else
386497d01f0SAxel Dörfler 		name.Capitalize();
387497d01f0SAxel Dörfler 
3887dcdcad2SJérôme Duval 	name << " Mouse " << index;
38933efb919SStefano Ceccherini 
39033efb919SStefano Ceccherini 	return strdup(name.String());
39133efb919SStefano Ceccherini }
392*61604e48SAxel Dörfler 
393*61604e48SAxel Dörfler 
394*61604e48SAxel Dörfler //	#pragma mark -
395*61604e48SAxel Dörfler 
396*61604e48SAxel Dörfler 
397*61604e48SAxel Dörfler MouseInputDevice::MouseInputDevice()
398*61604e48SAxel Dörfler {
399*61604e48SAxel Dörfler #if DEBUG
400*61604e48SAxel Dörfler 	sLogFile = fopen("/var/log/mouse_device_log.log", "a");
401*61604e48SAxel Dörfler #endif
402*61604e48SAxel Dörfler 	CALLED();
403*61604e48SAxel Dörfler 
404*61604e48SAxel Dörfler 	StartMonitoringDevice(kMouseDevicesDirectoryPS2);
405*61604e48SAxel Dörfler 	StartMonitoringDevice(kMouseDevicesDirectoryUSB);
406*61604e48SAxel Dörfler 
407*61604e48SAxel Dörfler 	_RecursiveScan(kMouseDevicesDirectory);
408*61604e48SAxel Dörfler }
409*61604e48SAxel Dörfler 
410*61604e48SAxel Dörfler 
411*61604e48SAxel Dörfler MouseInputDevice::~MouseInputDevice()
412*61604e48SAxel Dörfler {
413*61604e48SAxel Dörfler 	CALLED();
414*61604e48SAxel Dörfler 	StopMonitoringDevice(kMouseDevicesDirectoryUSB);
415*61604e48SAxel Dörfler 	StopMonitoringDevice(kMouseDevicesDirectoryPS2);
416*61604e48SAxel Dörfler 
417*61604e48SAxel Dörfler 	int32 count = fDevices.CountItems();
418*61604e48SAxel Dörfler 	while (count-- > 0) {
419*61604e48SAxel Dörfler 		delete (MouseDevice *)fDevices.RemoveItem(count);
420*61604e48SAxel Dörfler 	}
421*61604e48SAxel Dörfler 
422*61604e48SAxel Dörfler #if DEBUG
423*61604e48SAxel Dörfler 	fclose(sLogFile);
424*61604e48SAxel Dörfler #endif
425*61604e48SAxel Dörfler }
426*61604e48SAxel Dörfler 
427*61604e48SAxel Dörfler 
428*61604e48SAxel Dörfler status_t
429*61604e48SAxel Dörfler MouseInputDevice::InitCheck()
430*61604e48SAxel Dörfler {
431*61604e48SAxel Dörfler 	CALLED();
432*61604e48SAxel Dörfler 	return B_OK;
433*61604e48SAxel Dörfler }
434*61604e48SAxel Dörfler 
435*61604e48SAxel Dörfler 
436*61604e48SAxel Dörfler status_t
437*61604e48SAxel Dörfler MouseInputDevice::Start(const char *name, void *cookie)
438*61604e48SAxel Dörfler {
439*61604e48SAxel Dörfler 	LOG("%s(%s)\n", __PRETTY_FUNCTION__, name);
440*61604e48SAxel Dörfler 	MouseDevice* device = (MouseDevice*)cookie;
441*61604e48SAxel Dörfler 
442*61604e48SAxel Dörfler 	return device->Start();
443*61604e48SAxel Dörfler }
444*61604e48SAxel Dörfler 
445*61604e48SAxel Dörfler 
446*61604e48SAxel Dörfler status_t
447*61604e48SAxel Dörfler MouseInputDevice::Stop(const char *name, void *cookie)
448*61604e48SAxel Dörfler {
449*61604e48SAxel Dörfler 	LOG("%s(%s)\n", __PRETTY_FUNCTION__, name);
450*61604e48SAxel Dörfler 	MouseDevice* device = (MouseDevice*)cookie;
451*61604e48SAxel Dörfler 
452*61604e48SAxel Dörfler 	device->Stop();
453*61604e48SAxel Dörfler 	return B_OK;
454*61604e48SAxel Dörfler }
455*61604e48SAxel Dörfler 
456*61604e48SAxel Dörfler 
457*61604e48SAxel Dörfler status_t
458*61604e48SAxel Dörfler MouseInputDevice::Control(const char* name, void* cookie,
459*61604e48SAxel Dörfler 	uint32 command, BMessage* message)
460*61604e48SAxel Dörfler {
461*61604e48SAxel Dörfler 	LOG("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command);
462*61604e48SAxel Dörfler 	MouseDevice* device = (MouseDevice*)cookie;
463*61604e48SAxel Dörfler 
464*61604e48SAxel Dörfler 	if (command == B_NODE_MONITOR)
465*61604e48SAxel Dörfler 		return _HandleMonitor(message);
466*61604e48SAxel Dörfler 
467*61604e48SAxel Dörfler 	if (command >= B_MOUSE_TYPE_CHANGED
468*61604e48SAxel Dörfler 		&& command <= B_MOUSE_ACCELERATION_CHANGED)
469*61604e48SAxel Dörfler 		return device->UpdateSettings();
470*61604e48SAxel Dörfler 
471*61604e48SAxel Dörfler 	return B_BAD_VALUE;
472*61604e48SAxel Dörfler }
473*61604e48SAxel Dörfler 
474*61604e48SAxel Dörfler 
475*61604e48SAxel Dörfler // TODO: Test this. USB doesn't work on my machine
476*61604e48SAxel Dörfler status_t
477*61604e48SAxel Dörfler MouseInputDevice::_HandleMonitor(BMessage* message)
478*61604e48SAxel Dörfler {
479*61604e48SAxel Dörfler 	CALLED();
480*61604e48SAxel Dörfler 
481*61604e48SAxel Dörfler 	int32 opcode;
482*61604e48SAxel Dörfler 	if (message->FindInt32("opcode", &opcode) < B_OK)
483*61604e48SAxel Dörfler 		return B_BAD_VALUE;
484*61604e48SAxel Dörfler 
485*61604e48SAxel Dörfler 	if (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED)
486*61604e48SAxel Dörfler 		return B_OK;
487*61604e48SAxel Dörfler 
488*61604e48SAxel Dörfler 	BEntry entry;
489*61604e48SAxel Dörfler 	BPath path;
490*61604e48SAxel Dörfler 	dev_t device;
491*61604e48SAxel Dörfler 	ino_t directory;
492*61604e48SAxel Dörfler 	const char *name;
493*61604e48SAxel Dörfler 
494*61604e48SAxel Dörfler 	if (message->FindInt32("device", &device) < B_OK
495*61604e48SAxel Dörfler 		|| message->FindInt64("directory", &directory) < B_OK
496*61604e48SAxel Dörfler 		|| message->FindString("name", &name) < B_OK)
497*61604e48SAxel Dörfler 		return B_BAD_VALUE;
498*61604e48SAxel Dörfler 
499*61604e48SAxel Dörfler 	entry_ref ref(device, directory, name);
500*61604e48SAxel Dörfler 	status_t status;
501*61604e48SAxel Dörfler 
502*61604e48SAxel Dörfler 	if ((status = entry.SetTo(&ref)) != B_OK)
503*61604e48SAxel Dörfler 		return status;
504*61604e48SAxel Dörfler 	if ((status = entry.GetPath(&path)) != B_OK)
505*61604e48SAxel Dörfler 		return status;
506*61604e48SAxel Dörfler 	if ((status = path.InitCheck()) != B_OK)
507*61604e48SAxel Dörfler 		return status;
508*61604e48SAxel Dörfler 
509*61604e48SAxel Dörfler 	if (opcode == B_ENTRY_CREATED)
510*61604e48SAxel Dörfler 		status = _AddDevice(path.Path());
511*61604e48SAxel Dörfler 	else
512*61604e48SAxel Dörfler 		status = _RemoveDevice(path.Path());
513*61604e48SAxel Dörfler 
514*61604e48SAxel Dörfler 	return status;
515*61604e48SAxel Dörfler }
516*61604e48SAxel Dörfler 
517*61604e48SAxel Dörfler 
518*61604e48SAxel Dörfler MouseDevice*
519*61604e48SAxel Dörfler MouseInputDevice::_FindDevice(const char *path)
520*61604e48SAxel Dörfler {
521*61604e48SAxel Dörfler 	CALLED();
522*61604e48SAxel Dörfler 
523*61604e48SAxel Dörfler 	for (int32 i = fDevices.CountItems(); i-- > 0;) {
524*61604e48SAxel Dörfler 		MouseDevice* device = (MouseDevice*)fDevices.ItemAt(i);
525*61604e48SAxel Dörfler 		if (!strcmp(device->Path(), path))
526*61604e48SAxel Dörfler 			return device;
527*61604e48SAxel Dörfler 	}
528*61604e48SAxel Dörfler 
529*61604e48SAxel Dörfler 	return NULL;
530*61604e48SAxel Dörfler }
531*61604e48SAxel Dörfler 
532*61604e48SAxel Dörfler 
533*61604e48SAxel Dörfler status_t
534*61604e48SAxel Dörfler MouseInputDevice::_AddDevice(const char *path)
535*61604e48SAxel Dörfler {
536*61604e48SAxel Dörfler 	CALLED();
537*61604e48SAxel Dörfler 
538*61604e48SAxel Dörfler 	MouseDevice* device = new (std::nothrow) MouseDevice(*this, path);
539*61604e48SAxel Dörfler 	if (!device) {
540*61604e48SAxel Dörfler 		LOG("No memory\n");
541*61604e48SAxel Dörfler 		return B_NO_MEMORY;
542*61604e48SAxel Dörfler 	}
543*61604e48SAxel Dörfler 
544*61604e48SAxel Dörfler 	if (!fDevices.AddItem(device)) {
545*61604e48SAxel Dörfler 		delete device;
546*61604e48SAxel Dörfler 		return B_NO_MEMORY;
547*61604e48SAxel Dörfler 	}
548*61604e48SAxel Dörfler 
549*61604e48SAxel Dörfler 	input_device_ref *devices[2];
550*61604e48SAxel Dörfler 	devices[0] = device->DeviceRef();
551*61604e48SAxel Dörfler 	devices[1] = NULL;
552*61604e48SAxel Dörfler 
553*61604e48SAxel Dörfler 	return RegisterDevices(devices);
554*61604e48SAxel Dörfler }
555*61604e48SAxel Dörfler 
556*61604e48SAxel Dörfler 
557*61604e48SAxel Dörfler status_t
558*61604e48SAxel Dörfler MouseInputDevice::_RemoveDevice(const char *path)
559*61604e48SAxel Dörfler {
560*61604e48SAxel Dörfler 	CALLED();
561*61604e48SAxel Dörfler 
562*61604e48SAxel Dörfler 	MouseDevice* device = _FindDevice(path);
563*61604e48SAxel Dörfler 	if (device == NULL)
564*61604e48SAxel Dörfler 		return B_ENTRY_NOT_FOUND;
565*61604e48SAxel Dörfler 
566*61604e48SAxel Dörfler 	fDevices.RemoveItem(device);
567*61604e48SAxel Dörfler 
568*61604e48SAxel Dörfler 	input_device_ref *devices[2];
569*61604e48SAxel Dörfler 	devices[0] = device->DeviceRef();
570*61604e48SAxel Dörfler 	devices[1] = NULL;
571*61604e48SAxel Dörfler 
572*61604e48SAxel Dörfler 	UnregisterDevices(devices);
573*61604e48SAxel Dörfler 
574*61604e48SAxel Dörfler 	delete device;
575*61604e48SAxel Dörfler 	return B_OK;
576*61604e48SAxel Dörfler }
577*61604e48SAxel Dörfler 
578*61604e48SAxel Dörfler 
579*61604e48SAxel Dörfler void
580*61604e48SAxel Dörfler MouseInputDevice::_RecursiveScan(const char* directory)
581*61604e48SAxel Dörfler {
582*61604e48SAxel Dörfler 	CALLED();
583*61604e48SAxel Dörfler 
584*61604e48SAxel Dörfler 	BEntry entry;
585*61604e48SAxel Dörfler 	BDirectory dir(directory);
586*61604e48SAxel Dörfler 	while (dir.GetNextEntry(&entry) == B_OK) {
587*61604e48SAxel Dörfler 		BPath path;
588*61604e48SAxel Dörfler 		entry.GetPath(&path);
589*61604e48SAxel Dörfler 
590*61604e48SAxel Dörfler 		if (!strcmp(path.Leaf(), "serial")) {
591*61604e48SAxel Dörfler 			// skip serial
592*61604e48SAxel Dörfler 			continue;
593*61604e48SAxel Dörfler 		}
594*61604e48SAxel Dörfler 
595*61604e48SAxel Dörfler 		if (entry.IsDirectory())
596*61604e48SAxel Dörfler 			_RecursiveScan(path.Path());
597*61604e48SAxel Dörfler 		else
598*61604e48SAxel Dörfler 			_AddDevice(path.Path());
599*61604e48SAxel Dörfler 	}
600*61604e48SAxel Dörfler }
601*61604e48SAxel Dörfler 
602