xref: /haiku/src/add-ons/input_server/devices/mouse/MouseInputDevice.cpp (revision 23b47e0b5e13933d497a70b2274e5623ca7d0910)
1*23b47e0bSJérôme Duval /*
2*23b47e0bSJérôme Duval  * Copyright 2004-2006, Haiku.
3*23b47e0bSJérôme Duval  * Distributed under the terms of the MIT License.
4*23b47e0bSJérôme Duval  *
5*23b47e0bSJérôme Duval  * Authors:
6*23b47e0bSJérôme Duval  *		Stefano Ceccherini
7*23b47e0bSJérôme Duval  */
833efb919SStefano Ceccherini 
933efb919SStefano Ceccherini // TODO: Use strlcpy instead of strcpy
1033efb919SStefano Ceccherini 
1161d7deeeSJérôme Duval #include "MouseInputDevice.h"
12fc2045eeSJérôme Duval #include "kb_mouse_settings.h"
13fc2045eeSJérôme Duval #include "kb_mouse_driver.h"
1461d7deeeSJérôme Duval 
1561d7deeeSJérôme Duval #include <stdlib.h>
1661d7deeeSJérôme Duval #include <unistd.h>
1761d7deeeSJérôme Duval 
18c2fbfb71SJérôme Duval #include <Debug.h>
1933efb919SStefano Ceccherini #include <Directory.h>
2033efb919SStefano Ceccherini #include <Entry.h>
2133efb919SStefano Ceccherini #include <NodeMonitor.h>
2233efb919SStefano Ceccherini #include <Path.h>
2333efb919SStefano Ceccherini #include <String.h>
24*23b47e0bSJérôme Duval #include <View.h>	// for default buttons
2533efb919SStefano Ceccherini 
263aa69c78SStefano Ceccherini #if DEBUG
27c2fbfb71SJérôme Duval         inline void LOG(const char *fmt, ...) { char buf[1024]; va_list ap; va_start(ap, fmt); vsprintf(buf, fmt, ap); va_end(ap); \
28c2fbfb71SJérôme Duval                 fputs(buf, MouseInputDevice::sLogFile); fflush(MouseInputDevice::sLogFile); }
29c2fbfb71SJérôme Duval         #define LOG_ERR(text...) LOG(text)
30c2fbfb71SJérôme Duval FILE *MouseInputDevice::sLogFile = NULL;
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 
38*23b47e0bSJérôme Duval #ifndef B_FIRST_REAL_TIME_PRIORITY
39*23b47e0bSJérôme Duval #define B_FIRST_REAL_TIME_PRIORITY B_REAL_TIME_DISPLAY_PRIORITY
40*23b47e0bSJérôme Duval #endif
4133efb919SStefano Ceccherini const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4;
4233efb919SStefano Ceccherini const static char *kMouseDevicesDirectory = "/dev/input/mouse";
4333efb919SStefano Ceccherini 
4433efb919SStefano Ceccherini // "/dev/" is automatically prepended by StartMonitoringDevice()
45f0bac935SJérôme Duval const static char *kMouseDevicesDirectoryPS2 = "input/mouse/ps2";
4633efb919SStefano Ceccherini const static char *kMouseDevicesDirectoryUSB = "input/mouse/usb";
4733efb919SStefano Ceccherini 
480dbc4befSStefano Ceccherini struct mouse_device {
4933efb919SStefano Ceccherini 	mouse_device(const char *path);
5033efb919SStefano Ceccherini 	~mouse_device();
5133efb919SStefano Ceccherini 
5233efb919SStefano Ceccherini 	input_device_ref device_ref;
53c2fbfb71SJérôme Duval 	char path[B_PATH_NAME_LENGTH];
54c2fbfb71SJérôme Duval 	int fd;
550dbc4befSStefano Ceccherini 	thread_id device_watcher;
5633efb919SStefano Ceccherini 	mouse_settings settings;
57d323bbb2SMarcus Overhagen 	volatile bool active;
58*23b47e0bSJérôme Duval 	bool remap;		// device remaps buttons itself
590dbc4befSStefano Ceccherini };
600dbc4befSStefano Ceccherini 
610dbc4befSStefano Ceccherini 
624c0af4a8SStefano Ceccherini struct watcher_params {
634c0af4a8SStefano Ceccherini 	MouseInputDevice *object;
644c0af4a8SStefano Ceccherini 	mouse_device *device;
654c0af4a8SStefano Ceccherini };
664c0af4a8SStefano Ceccherini 
674c0af4a8SStefano Ceccherini 
6833efb919SStefano Ceccherini // forward declarations
6933efb919SStefano Ceccherini static char *get_short_name(const char *longName);
7033efb919SStefano Ceccherini 
7133efb919SStefano Ceccherini 
7261d7deeeSJérôme Duval extern "C"
7361d7deeeSJérôme Duval BInputServerDevice *
7461d7deeeSJérôme Duval instantiate_input_device()
7561d7deeeSJérôme Duval {
7661d7deeeSJérôme Duval 	return new MouseInputDevice();
7761d7deeeSJérôme Duval }
7861d7deeeSJérôme Duval 
7961d7deeeSJérôme Duval 
8061d7deeeSJérôme Duval MouseInputDevice::MouseInputDevice()
8161d7deeeSJérôme Duval {
823aa69c78SStefano Ceccherini #if DEBUG
835c506d7fSJérôme Duval 	sLogFile = fopen("/var/log/mouse_device_log.log", "a");
843aa69c78SStefano Ceccherini #endif
85c2fbfb71SJérôme Duval 	CALLED();
8633efb919SStefano Ceccherini 
87f0bac935SJérôme Duval 	StartMonitoringDevice(kMouseDevicesDirectoryPS2);
8833efb919SStefano Ceccherini 	StartMonitoringDevice(kMouseDevicesDirectoryUSB);
8961d7deeeSJérôme Duval }
9061d7deeeSJérôme Duval 
9161d7deeeSJérôme Duval 
9261d7deeeSJérôme Duval MouseInputDevice::~MouseInputDevice()
9361d7deeeSJérôme Duval {
94c2fbfb71SJérôme Duval 	CALLED();
9533efb919SStefano Ceccherini 	StopMonitoringDevice(kMouseDevicesDirectoryUSB);
96f0bac935SJérôme Duval 	StopMonitoringDevice(kMouseDevicesDirectoryPS2);
9761d7deeeSJérôme Duval 
98d323bbb2SMarcus Overhagen 	int count = fDevices.CountItems();
99d323bbb2SMarcus Overhagen 	while (count-- > 0)
100d323bbb2SMarcus Overhagen 		delete (mouse_device *)fDevices.RemoveItem((int32)0);
10161d7deeeSJérôme Duval 
1023aa69c78SStefano Ceccherini #if DEBUG
1033aa69c78SStefano Ceccherini 	fclose(sLogFile);
1043aa69c78SStefano Ceccherini #endif
10561d7deeeSJérôme Duval }
10661d7deeeSJérôme Duval 
10761d7deeeSJérôme Duval 
10861d7deeeSJérôme Duval status_t
10933efb919SStefano Ceccherini MouseInputDevice::InitFromSettings(void *cookie, uint32 opcode)
11053d77642SJérôme Duval {
1117dcdcad2SJérôme Duval 	CALLED();
11233efb919SStefano Ceccherini 	mouse_device *device = (mouse_device *)cookie;
11333efb919SStefano Ceccherini 
11453d77642SJérôme Duval 	// retrieve current values
11553d77642SJérôme Duval 
11633efb919SStefano Ceccherini 	if (get_mouse_map(&device->settings.map) != B_OK)
117c2fbfb71SJérôme Duval 		LOG_ERR("error when get_mouse_map\n");
11853d77642SJérôme Duval 	else
119*23b47e0bSJérôme Duval 		device->remap = B_OK == ioctl(device->fd, MS_SET_MAP, &device->settings.map);
12053d77642SJérôme Duval 
12133efb919SStefano Ceccherini 	if (get_click_speed(&device->settings.click_speed) != B_OK)
122c2fbfb71SJérôme Duval 		LOG_ERR("error when get_click_speed\n");
12353d77642SJérôme Duval 	else
124c2fbfb71SJérôme Duval 		ioctl(device->fd, MS_SET_CLICKSPEED, &device->settings.click_speed);
12553d77642SJérôme Duval 
12633efb919SStefano Ceccherini 	if (get_mouse_speed(&device->settings.accel.speed) != B_OK)
127c2fbfb71SJérôme Duval 		LOG_ERR("error when get_mouse_speed\n");
12853d77642SJérôme Duval 	else {
12933efb919SStefano Ceccherini 		if (get_mouse_acceleration(&device->settings.accel.accel_factor) != B_OK)
130c2fbfb71SJérôme Duval 			LOG_ERR("error when get_mouse_acceleration\n");
13153d77642SJérôme Duval 		else {
13253d77642SJérôme Duval 			mouse_accel accel;
133c2fbfb71SJérôme Duval 			ioctl(device->fd, MS_GET_ACCEL, &accel);
13433efb919SStefano Ceccherini 			accel.speed = device->settings.accel.speed;
13533efb919SStefano Ceccherini 			accel.accel_factor = device->settings.accel.accel_factor;
136c2fbfb71SJérôme Duval 			ioctl(device->fd, MS_SET_ACCEL, &device->settings.accel);
13753d77642SJérôme Duval 		}
13853d77642SJérôme Duval 	}
13953d77642SJérôme Duval 
14033efb919SStefano Ceccherini 	if (get_mouse_type(&device->settings.type) != B_OK)
141c2fbfb71SJérôme Duval 		LOG_ERR("error when get_mouse_type\n");
14253d77642SJérôme Duval 	else
143c2fbfb71SJérôme Duval 		ioctl(device->fd, MS_SET_TYPE, &device->settings.type);
14453d77642SJérôme Duval 
14553d77642SJérôme Duval 	return B_OK;
14633efb919SStefano Ceccherini 
14753d77642SJérôme Duval }
14853d77642SJérôme Duval 
14953d77642SJérôme Duval 
15053d77642SJérôme Duval status_t
15161d7deeeSJérôme Duval MouseInputDevice::InitCheck()
15261d7deeeSJérôme Duval {
153c2fbfb71SJérôme Duval 	CALLED();
154c2fbfb71SJérôme Duval 	RecursiveScan(kMouseDevicesDirectory);
15553d77642SJérôme Duval 
156c2fbfb71SJérôme Duval 	return B_OK;
15761d7deeeSJérôme Duval }
15861d7deeeSJérôme Duval 
15961d7deeeSJérôme Duval 
16061d7deeeSJérôme Duval status_t
16161d7deeeSJérôme Duval MouseInputDevice::Start(const char *name, void *cookie)
16261d7deeeSJérôme Duval {
16333efb919SStefano Ceccherini 	mouse_device *device = (mouse_device *)cookie;
16433efb919SStefano Ceccherini 
165c2fbfb71SJérôme Duval 	LOG("%s(%s)\n", __PRETTY_FUNCTION__, name);
1663aa69c78SStefano Ceccherini 
167c2fbfb71SJérôme Duval 	device->fd = open(device->path, O_RDWR);
168c2fbfb71SJérôme Duval 	if (device->fd < 0)
169d323bbb2SMarcus Overhagen 		return B_ERROR;
170c2fbfb71SJérôme Duval 
1716af8fc09SStefano Ceccherini 	status_t status = InitFromSettings(device);
1726af8fc09SStefano Ceccherini 	if (status < B_OK) {
1736af8fc09SStefano Ceccherini 		LOG_ERR("%s: can't initialize from settings: %s\n",
1746af8fc09SStefano Ceccherini 			name, strerror(status));
175d323bbb2SMarcus Overhagen 		close(device->fd);
1766af8fc09SStefano Ceccherini 		return status;
1776af8fc09SStefano Ceccherini 	}
17833efb919SStefano Ceccherini 
17933efb919SStefano Ceccherini 	char threadName[B_OS_NAME_LENGTH];
18033efb919SStefano Ceccherini 	snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", name);
18133efb919SStefano Ceccherini 
1824c0af4a8SStefano Ceccherini 
1834c0af4a8SStefano Ceccherini 	const watcher_params params = { this, device };
18433efb919SStefano Ceccherini 	device->active = true;
1854c0af4a8SStefano Ceccherini 	device->device_watcher = spawn_thread(ThreadFunction, threadName,
1864c0af4a8SStefano Ceccherini 		kMouseThreadPriority, (void *)&params);
18733efb919SStefano Ceccherini 
1886af8fc09SStefano Ceccherini 	if (device->device_watcher < B_OK) {
1896af8fc09SStefano Ceccherini 		LOG_ERR("%s: can't spawn watching thread: %s\n",
1906af8fc09SStefano Ceccherini 			name, strerror(device->device_watcher));
191d323bbb2SMarcus Overhagen 		close(device->fd);
1926af8fc09SStefano Ceccherini 		return device->device_watcher;
1936af8fc09SStefano Ceccherini 	}
1946af8fc09SStefano Ceccherini 
1956af8fc09SStefano Ceccherini 	status = resume_thread(device->device_watcher);
1966af8fc09SStefano Ceccherini 	if (status < B_OK) {
1976af8fc09SStefano Ceccherini 		LOG_ERR("%s: can't resume watching thread: %s\n",
1986af8fc09SStefano Ceccherini 			name, strerror(status));
199d323bbb2SMarcus Overhagen 		kill_thread(device->device_watcher);
200d323bbb2SMarcus Overhagen 		close(device->fd);
2016af8fc09SStefano Ceccherini 		return status;
2026af8fc09SStefano Ceccherini 	}
20333efb919SStefano Ceccherini 
20461d7deeeSJérôme Duval 	return B_OK;
20561d7deeeSJérôme Duval }
20661d7deeeSJérôme Duval 
20761d7deeeSJérôme Duval 
20861d7deeeSJérôme Duval status_t
2093aa69c78SStefano Ceccherini MouseInputDevice::Stop(const char *name, void *cookie)
21061d7deeeSJérôme Duval {
21133efb919SStefano Ceccherini 	mouse_device *device = (mouse_device *)cookie;
21233efb919SStefano Ceccherini 
213c2fbfb71SJérôme Duval 	LOG("%s(%s)\n", __PRETTY_FUNCTION__, name);
2143aa69c78SStefano Ceccherini 
21533efb919SStefano Ceccherini 	device->active = false;
21633efb919SStefano Ceccherini 	if (device->device_watcher >= 0) {
217d323bbb2SMarcus Overhagen 		// unblock the thread, which is waiting on a semaphore.
218c2fbfb71SJérôme Duval 		suspend_thread(device->device_watcher);
219c2fbfb71SJérôme Duval 		resume_thread(device->device_watcher);
22033efb919SStefano Ceccherini 		status_t dummy;
22133efb919SStefano Ceccherini 		wait_for_thread(device->device_watcher, &dummy);
22233efb919SStefano Ceccherini 	}
22361d7deeeSJérôme Duval 
224d323bbb2SMarcus Overhagen 	close(device->fd);
225d323bbb2SMarcus Overhagen 
22661d7deeeSJérôme Duval 	return B_OK;
22761d7deeeSJérôme Duval }
22861d7deeeSJérôme Duval 
22961d7deeeSJérôme Duval 
23061d7deeeSJérôme Duval status_t
23161d7deeeSJérôme Duval MouseInputDevice::Control(const char *name, void *cookie,
23261d7deeeSJérôme Duval 						  uint32 command, BMessage *message)
23361d7deeeSJérôme Duval {
234c2fbfb71SJérôme Duval 	LOG("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command);
2356af8fc09SStefano Ceccherini 	status_t status = B_BAD_VALUE;
23653d77642SJérôme Duval 
23753d77642SJérôme Duval 	if (command == B_NODE_MONITOR)
2386af8fc09SStefano Ceccherini 		status = HandleMonitor(message);
23953d77642SJérôme Duval 	else if (command >= B_MOUSE_TYPE_CHANGED
24053d77642SJérôme Duval 		&& command <= B_MOUSE_ACCELERATION_CHANGED) {
2416af8fc09SStefano Ceccherini 		status = InitFromSettings(cookie, command);
24253d77642SJérôme Duval 	}
2436af8fc09SStefano Ceccherini 	return status;
24453d77642SJérôme Duval }
24553d77642SJérôme Duval 
24653d77642SJérôme Duval 
24733efb919SStefano Ceccherini // TODO: Test this. USB doesn't work on my machine
24833efb919SStefano Ceccherini status_t
24933efb919SStefano Ceccherini MouseInputDevice::HandleMonitor(BMessage *message)
25033efb919SStefano Ceccherini {
251c2fbfb71SJérôme Duval 	CALLED();
25233efb919SStefano Ceccherini 	int32 opcode = 0;
25333efb919SStefano Ceccherini 	status_t status;
254c2fbfb71SJérôme Duval 	if ((status = message->FindInt32("opcode", &opcode)) < B_OK)
25533efb919SStefano Ceccherini 	        return status;
25633efb919SStefano Ceccherini 
257c2fbfb71SJérôme Duval 	if ((opcode != B_ENTRY_CREATED)
258c2fbfb71SJérôme Duval 	        && (opcode != B_ENTRY_REMOVED))
259c2fbfb71SJérôme Duval 	        return B_OK;
260c2fbfb71SJérôme Duval 
26133efb919SStefano Ceccherini 	BEntry entry;
26233efb919SStefano Ceccherini 	BPath path;
26333efb919SStefano Ceccherini 	dev_t device;
26433efb919SStefano Ceccherini 	ino_t directory;
26533efb919SStefano Ceccherini 	const char *name = NULL;
26633efb919SStefano Ceccherini 
26733efb919SStefano Ceccherini 	message->FindInt32("device", &device);
26833efb919SStefano Ceccherini 	message->FindInt64("directory", &directory);
26933efb919SStefano Ceccherini 	message->FindString("name", &name);
27033efb919SStefano Ceccherini 
27133efb919SStefano Ceccherini 	entry_ref ref(device, directory, name);
27233efb919SStefano Ceccherini 
273c2fbfb71SJérôme Duval 	if ((status = entry.SetTo(&ref)) != B_OK)
274c2fbfb71SJérôme Duval 	        return status;
275c2fbfb71SJérôme Duval 	if ((status = entry.GetPath(&path)) != B_OK)
276c2fbfb71SJérôme Duval 	        return status;
277c2fbfb71SJérôme Duval 	if ((status = path.InitCheck()) != B_OK)
278c2fbfb71SJérôme Duval 	        return status;
27933efb919SStefano Ceccherini 
280c2fbfb71SJérôme Duval 	if (opcode == B_ENTRY_CREATED)
2816af8fc09SStefano Ceccherini 		status = AddDevice(path.Path());
282c2fbfb71SJérôme Duval 	else
2836af8fc09SStefano Ceccherini 		status = RemoveDevice(path.Path());
28433efb919SStefano Ceccherini 
28533efb919SStefano Ceccherini 	return status;
28633efb919SStefano Ceccherini }
28733efb919SStefano Ceccherini 
28833efb919SStefano Ceccherini 
28953d77642SJérôme Duval status_t
29033efb919SStefano Ceccherini MouseInputDevice::AddDevice(const char *path)
29153d77642SJérôme Duval {
292c2fbfb71SJérôme Duval 	CALLED();
293c2fbfb71SJérôme Duval 
29433efb919SStefano Ceccherini 	mouse_device *device = new mouse_device(path);
29533efb919SStefano Ceccherini 	if (!device) {
29633efb919SStefano Ceccherini 		LOG("No memory\n");
29733efb919SStefano Ceccherini 		return B_NO_MEMORY;
29833efb919SStefano Ceccherini 	}
29933efb919SStefano Ceccherini 
30033efb919SStefano Ceccherini 	input_device_ref *devices[2];
30133efb919SStefano Ceccherini 	devices[0] = &device->device_ref;
30233efb919SStefano Ceccherini 	devices[1] = NULL;
30333efb919SStefano Ceccherini 
304c2fbfb71SJérôme Duval 	fDevices.AddItem(device);
30533efb919SStefano Ceccherini 
30633efb919SStefano Ceccherini 	return RegisterDevices(devices);
30733efb919SStefano Ceccherini }
30833efb919SStefano Ceccherini 
30933efb919SStefano Ceccherini 
31033efb919SStefano Ceccherini status_t
31133efb919SStefano Ceccherini MouseInputDevice::RemoveDevice(const char *path)
31233efb919SStefano Ceccherini {
313c2fbfb71SJérôme Duval 	CALLED();
314d323bbb2SMarcus Overhagen 	mouse_device *device;
315d323bbb2SMarcus Overhagen 	for (int i = 0; (device = (mouse_device *)fDevices.ItemAt(i)) != NULL; i++) {
316c2fbfb71SJérôme Duval 		if (!strcmp(device->path, path)) {
317c2fbfb71SJérôme Duval 			fDevices.RemoveItem(device);
318d323bbb2SMarcus Overhagen 
319d323bbb2SMarcus Overhagen 			input_device_ref *devices[2];
320d323bbb2SMarcus Overhagen 			devices[0] = &device->device_ref;
321d323bbb2SMarcus Overhagen 			devices[1] = NULL;
322d323bbb2SMarcus Overhagen 			UnregisterDevices(devices);
323d323bbb2SMarcus Overhagen 
32433efb919SStefano Ceccherini 			delete device;
32561d7deeeSJérôme Duval 			return B_OK;
32661d7deeeSJérôme Duval 		}
32733efb919SStefano Ceccherini 	}
32833efb919SStefano Ceccherini 
32933efb919SStefano Ceccherini 	return B_ENTRY_NOT_FOUND;
33033efb919SStefano Ceccherini }
33161d7deeeSJérôme Duval 
33261d7deeeSJérôme Duval 
33361d7deeeSJérôme Duval int32
3344c0af4a8SStefano Ceccherini MouseInputDevice::ThreadFunction(void  *arg)
33561d7deeeSJérôme Duval {
3364c0af4a8SStefano Ceccherini 	watcher_params *params = (watcher_params *)arg;
3374c0af4a8SStefano Ceccherini 	return params->object->DeviceWatcher(params->device);
3384c0af4a8SStefano Ceccherini }
33933efb919SStefano Ceccherini 
3404c0af4a8SStefano Ceccherini 
3414c0af4a8SStefano Ceccherini int32
3424c0af4a8SStefano Ceccherini MouseInputDevice::DeviceWatcher(mouse_device *dev)
3434c0af4a8SStefano Ceccherini {
34461d7deeeSJérôme Duval 	mouse_movement movements;
3452895720cSJérôme Duval 	uint32 buttons_state = 0;
346e7b980aeSStefano Ceccherini 	BMessage *message = NULL;
34733efb919SStefano Ceccherini 	while (dev->active) {
3487d5d344bSJérôme Duval 		memset(&movements, 0, sizeof(movements));
349106d748cSMarcus Overhagen 		if (ioctl(dev->fd, MS_READ, &movements) != B_OK) {
350d323bbb2SMarcus Overhagen 			return 0;
351106d748cSMarcus Overhagen 		}
35261d7deeeSJérôme Duval 
353c2fbfb71SJérôme Duval 		uint32 buttons = buttons_state ^ movements.buttons;
35461d7deeeSJérôme Duval 
3555a23ac26SJérôme Duval 		LOG("%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld, wheel_x:%ld, wheel_y:%ld\n", dev->device_ref.name, movements.buttons,
3565a23ac26SJérôme Duval 			movements.xdelta, movements.ydelta, movements.clicks, movements.wheel_xdelta, movements.wheel_ydelta);
3573aa69c78SStefano Ceccherini 
358fc2045eeSJérôme Duval 		// TODO: add acceleration computing
359fc2045eeSJérôme Duval 		int32 xdelta = movements.xdelta * dev->settings.accel.speed >> 15;
3606be0f7efSJérôme Duval 		int32 ydelta = movements.ydelta * dev->settings.accel.speed >> 15;
3616ed407d8SJérôme Duval 
362c2fbfb71SJérôme Duval 		LOG("%s: x: %ld, y: %ld, \n", dev->device_ref.name, xdelta, ydelta);
3636ed407d8SJérôme Duval 
364e7b980aeSStefano Ceccherini 		if (movements.xdelta != 0 || movements.ydelta != 0) {
365e7b980aeSStefano Ceccherini 			message = new BMessage(B_MOUSE_MOVED);
366e7b980aeSStefano Ceccherini 			if (message) {
367e7b980aeSStefano Ceccherini 				message->AddInt64("when", movements.timestamp);
368*23b47e0bSJérôme Duval 				message->AddInt32("buttons", Remap(dev, movements.buttons));
369e7b980aeSStefano Ceccherini 				message->AddInt32("x", xdelta);
370e7b980aeSStefano Ceccherini 				message->AddInt32("y", ydelta);
371e7b980aeSStefano Ceccherini 
3724c0af4a8SStefano Ceccherini 				EnqueueMessage(message);
373e7b980aeSStefano Ceccherini 			}
374e7b980aeSStefano Ceccherini 		}
375e7b980aeSStefano Ceccherini 
3763aa69c78SStefano Ceccherini 		if (buttons != 0) {
377fc2045eeSJérôme Duval 			message = new BMessage(B_MOUSE_UP);
3783f8c0d7eSJérôme Duval 			if ((buttons & movements.buttons) > 0) {
3793aa69c78SStefano Ceccherini 				message->what = B_MOUSE_DOWN;
380fc2045eeSJérôme Duval 				message->AddInt32("clicks", movements.clicks);
3813aa69c78SStefano Ceccherini 				LOG("B_MOUSE_DOWN\n");
382e361bf69SJérôme Duval 			} else {
3833aa69c78SStefano Ceccherini 				LOG("B_MOUSE_UP\n");
3843aa69c78SStefano Ceccherini 			}
3853aa69c78SStefano Ceccherini 
386fc2045eeSJérôme Duval 			message->AddInt64("when", movements.timestamp);
387*23b47e0bSJérôme Duval 			message->AddInt32("buttons", Remap(dev, movements.buttons));
388fc2045eeSJérôme Duval 			message->AddInt32("x", xdelta);
389fc2045eeSJérôme Duval 			message->AddInt32("y", ydelta);
3904c0af4a8SStefano Ceccherini 			EnqueueMessage(message);
391c2fbfb71SJérôme Duval 			buttons_state = movements.buttons;
3923aa69c78SStefano Ceccherini 		}
3933aa69c78SStefano Ceccherini 
3947d5d344bSJérôme Duval 		if ((movements.wheel_ydelta != 0) || (movements.wheel_xdelta != 0)) {
395fc2045eeSJérôme Duval 			message = new BMessage(B_MOUSE_WHEEL_CHANGED);
396fc2045eeSJérôme Duval 			if (message) {
397fc2045eeSJérôme Duval 				message->AddInt64("when", movements.timestamp);
3987d5d344bSJérôme Duval 				message->AddFloat("be:wheel_delta_x", movements.wheel_xdelta);
3997d5d344bSJérôme Duval 				message->AddFloat("be:wheel_delta_y", movements.wheel_ydelta);
400fc2045eeSJérôme Duval 
4014c0af4a8SStefano Ceccherini 				EnqueueMessage(message);
402fc2045eeSJérôme Duval 			}
403fc2045eeSJérôme Duval 		}
404fc2045eeSJérôme Duval 
40561d7deeeSJérôme Duval 	}
40661d7deeeSJérôme Duval 
40761d7deeeSJérôme Duval 	return 0;
40861d7deeeSJérôme Duval }
40961d7deeeSJérôme Duval 
41061d7deeeSJérôme Duval 
411c2fbfb71SJérôme Duval void
412c2fbfb71SJérôme Duval MouseInputDevice::RecursiveScan(const char *directory)
41333efb919SStefano Ceccherini {
414c2fbfb71SJérôme Duval 	CALLED();
415497d01f0SAxel Dörfler 
41633efb919SStefano Ceccherini 	BEntry entry;
41733efb919SStefano Ceccherini 	BDirectory dir(directory);
41833efb919SStefano Ceccherini 	while (dir.GetNextEntry(&entry) == B_OK) {
419c2fbfb71SJérôme Duval 		BPath path;
420c2fbfb71SJérôme Duval 		entry.GetPath(&path);
421c2fbfb71SJérôme Duval 
422d323bbb2SMarcus Overhagen 		if (0 == strcmp(path.Leaf(), "serial"))
423d323bbb2SMarcus Overhagen 			continue; // skip serial
42433efb919SStefano Ceccherini 
42533efb919SStefano Ceccherini 		if (entry.IsDirectory())
426c2fbfb71SJérôme Duval 			RecursiveScan(path.Path());
427c2fbfb71SJérôme Duval 		else
428c2fbfb71SJérôme Duval 			AddDevice(path.Path());
42933efb919SStefano Ceccherini 	}
43033efb919SStefano Ceccherini }
43133efb919SStefano Ceccherini 
43233efb919SStefano Ceccherini 
433*23b47e0bSJérôme Duval uint32
434*23b47e0bSJérôme Duval MouseInputDevice::Remap(mouse_device* device, uint32 buttons)
435*23b47e0bSJérôme Duval {
436*23b47e0bSJérôme Duval 	if (device->remap)
437*23b47e0bSJérôme Duval 		return buttons;
438*23b47e0bSJérôme Duval 
439*23b47e0bSJérôme Duval 	uint32 newbuttons = 0;
440*23b47e0bSJérôme Duval 	for (int32 i=0; buttons; i++) {
441*23b47e0bSJérôme Duval 		if (buttons & 0x1) {
442*23b47e0bSJérôme Duval #ifdef HAIKU_TARGET_PLATFORM_HAIKU
443*23b47e0bSJérôme Duval 			newbuttons |= device->settings.map.button[i];
444*23b47e0bSJérôme Duval #else
445*23b47e0bSJérôme Duval 			if (i==0)
446*23b47e0bSJérôme Duval 				newbuttons |= device->settings.map.left;
447*23b47e0bSJérôme Duval 			if (i==1)
448*23b47e0bSJérôme Duval 				newbuttons |= device->settings.map.right;
449*23b47e0bSJérôme Duval 			if (i==2)
450*23b47e0bSJérôme Duval 				newbuttons |= device->settings.map.middle;
451*23b47e0bSJérôme Duval #endif
452*23b47e0bSJérôme Duval 		}
453*23b47e0bSJérôme Duval 		buttons >>= 1;
454*23b47e0bSJérôme Duval 	}
455*23b47e0bSJérôme Duval 
456*23b47e0bSJérôme Duval 	return newbuttons;
457*23b47e0bSJérôme Duval }
458*23b47e0bSJérôme Duval 
459*23b47e0bSJérôme Duval 
4604c0af4a8SStefano Ceccherini // mouse_device
4614c0af4a8SStefano Ceccherini mouse_device::mouse_device(const char *driver_path)
4624c0af4a8SStefano Ceccherini 	:
4634c0af4a8SStefano Ceccherini 	fd(-1),
4644c0af4a8SStefano Ceccherini 	device_watcher(-1),
4654c0af4a8SStefano Ceccherini 	active(false)
4664c0af4a8SStefano Ceccherini {
4674c0af4a8SStefano Ceccherini 	strcpy(path, driver_path);
4684c0af4a8SStefano Ceccherini 	device_ref.name = get_short_name(path);
4694c0af4a8SStefano Ceccherini 	device_ref.type = B_POINTING_DEVICE;
4704c0af4a8SStefano Ceccherini 	device_ref.cookie = this;
471*23b47e0bSJérôme Duval #ifdef HAIKU_TARGET_PLATFORM_HAIKU
472*23b47e0bSJérôme Duval 	settings.map.button[0] = B_PRIMARY_MOUSE_BUTTON;
473*23b47e0bSJérôme Duval 	settings.map.button[1] = B_SECONDARY_MOUSE_BUTTON;
474*23b47e0bSJérôme Duval 	settings.map.button[2] = B_TERTIARY_MOUSE_BUTTON;
475*23b47e0bSJérôme Duval #endif
476*23b47e0bSJérôme Duval 	remap = false;
4774c0af4a8SStefano Ceccherini };
4784c0af4a8SStefano Ceccherini 
4794c0af4a8SStefano Ceccherini 
4804c0af4a8SStefano Ceccherini mouse_device::~mouse_device()
4814c0af4a8SStefano Ceccherini {
4824c0af4a8SStefano Ceccherini 	free(device_ref.name);
4834c0af4a8SStefano Ceccherini }
4844c0af4a8SStefano Ceccherini 
4854c0af4a8SStefano Ceccherini 
48633efb919SStefano Ceccherini static char *
48733efb919SStefano Ceccherini get_short_name(const char *longName)
48833efb919SStefano Ceccherini {
48933efb919SStefano Ceccherini 	BString string(longName);
49033efb919SStefano Ceccherini 	BString name;
49133efb919SStefano Ceccherini 
49233efb919SStefano Ceccherini 	int32 slash = string.FindLast("/");
4937dcdcad2SJérôme Duval 	string.CopyInto(name, slash + 1, string.Length() - slash);
4947dcdcad2SJérôme Duval 	int32 index = atoi(name.String()) + 1;
49533efb919SStefano Ceccherini 
4967dcdcad2SJérôme Duval 	int32 previousSlash = string.FindLast("/", slash);
4977dcdcad2SJérôme Duval 	string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1);
498497d01f0SAxel Dörfler 
499497d01f0SAxel Dörfler 	if (name == "ps2")
500497d01f0SAxel Dörfler 		name = "PS/2";
501497d01f0SAxel Dörfler 	else
502497d01f0SAxel Dörfler 		name.Capitalize();
503497d01f0SAxel Dörfler 
5047dcdcad2SJérôme Duval 	name << " Mouse " << index;
50533efb919SStefano Ceccherini 
50633efb919SStefano Ceccherini 	return strdup(name.String());
50733efb919SStefano Ceccherini }
508