xref: /haiku/src/add-ons/input_server/devices/mouse/MouseInputDevice.cpp (revision 7d5d344bf1c545c8cca88b75e40c571f99b5c9d2)
161d7deeeSJérôme Duval /*****************************************************************************/
261d7deeeSJérôme Duval // Mouse input server device addon
361d7deeeSJérôme Duval // Written by Stefano Ceccherini
461d7deeeSJérôme Duval //
561d7deeeSJérôme Duval // MouseInputDevice.cpp
661d7deeeSJérôme Duval //
761d7deeeSJérôme Duval // Copyright (c) 2004 Haiku Project
861d7deeeSJérôme Duval //
961d7deeeSJérôme Duval // Permission is hereby granted, free of charge, to any person obtaining a
1061d7deeeSJérôme Duval // copy of this software and associated documentation files (the "Software"),
1161d7deeeSJérôme Duval // to deal in the Software without restriction, including without limitation
1261d7deeeSJérôme Duval // the rights to use, copy, modify, merge, publish, distribute, sublicense,
1361d7deeeSJérôme Duval // and/or sell copies of the Software, and to permit persons to whom the
1461d7deeeSJérôme Duval // Software is furnished to do so, subject to the following conditions:
1561d7deeeSJérôme Duval //
1661d7deeeSJérôme Duval // The above copyright notice and this permission notice shall be included
1761d7deeeSJérôme Duval // in all copies or substantial portions of the Software.
1861d7deeeSJérôme Duval //
1961d7deeeSJérôme Duval // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
2061d7deeeSJérôme Duval // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2161d7deeeSJérôme Duval // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2261d7deeeSJérôme Duval // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2361d7deeeSJérôme Duval // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2461d7deeeSJérôme Duval // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2561d7deeeSJérôme Duval // DEALINGS IN THE SOFTWARE.
2661d7deeeSJérôme Duval /*****************************************************************************/
2733efb919SStefano Ceccherini 
2833efb919SStefano Ceccherini // TODO: Use strlcpy instead of strcpy
2933efb919SStefano Ceccherini 
3061d7deeeSJérôme Duval #include "MouseInputDevice.h"
31fc2045eeSJérôme Duval #include "kb_mouse_settings.h"
32fc2045eeSJérôme Duval #include "kb_mouse_driver.h"
3361d7deeeSJérôme Duval 
3461d7deeeSJérôme Duval #include <stdlib.h>
3561d7deeeSJérôme Duval #include <unistd.h>
3661d7deeeSJérôme Duval 
3733efb919SStefano Ceccherini #include <Directory.h>
3833efb919SStefano Ceccherini #include <Entry.h>
3933efb919SStefano Ceccherini #include <List.h>
4033efb919SStefano Ceccherini #include <NodeMonitor.h>
4133efb919SStefano Ceccherini #include <Path.h>
4233efb919SStefano Ceccherini #include <String.h>
4333efb919SStefano Ceccherini 
445c506d7fSJérôme Duval #define DEBUG 1
453aa69c78SStefano Ceccherini #if DEBUG
465c506d7fSJérôme Duval 	#define LOG(text) fputs(text, sLogFile); fflush(sLogFile)
473aa69c78SStefano Ceccherini #else
483aa69c78SStefano Ceccherini 	#define LOG(text)
493aa69c78SStefano Ceccherini #endif
503aa69c78SStefano Ceccherini 
5133efb919SStefano Ceccherini #include <Debug.h>
5233efb919SStefano Ceccherini 
533aa69c78SStefano Ceccherini FILE *MouseInputDevice::sLogFile = NULL;
5433efb919SStefano Ceccherini 
5533efb919SStefano Ceccherini static MouseInputDevice *sSingletonMouseDevice = NULL;
563aa69c78SStefano Ceccherini 
573aa69c78SStefano Ceccherini // TODO: These are "stolen" from the kb_mouse driver on bebits, which uses
583aa69c78SStefano Ceccherini // the same protocol as BeOS one. They're just here to test this add-on with
593aa69c78SStefano Ceccherini // the BeOS mouse driver.
6061d7deeeSJérôme Duval const static uint32 kGetMouseMovements = 10099;
6153d77642SJérôme Duval const static uint32 kGetMouseAccel = 10101;
6253d77642SJérôme Duval const static uint32 kSetMouseAccel = 10102;
6353d77642SJérôme Duval const static uint32 kSetMouseType = 10104;
6453d77642SJérôme Duval const static uint32 kSetMouseMap = 10106;
6553d77642SJérôme Duval const static uint32 kSetClickSpeed = 10108;
6661d7deeeSJérôme Duval 
6733efb919SStefano Ceccherini const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4;
6833efb919SStefano Ceccherini const static char *kMouseDevicesDirectory = "/dev/input/mouse";
6933efb919SStefano Ceccherini 
7033efb919SStefano Ceccherini // "/dev/" is automatically prepended by StartMonitoringDevice()
7133efb919SStefano Ceccherini const static char *kMouseDevicesDirectoryUSB = "input/mouse/usb";
7233efb919SStefano Ceccherini 
730dbc4befSStefano Ceccherini struct mouse_device {
7433efb919SStefano Ceccherini 	mouse_device(const char *path);
7533efb919SStefano Ceccherini 	~mouse_device();
7633efb919SStefano Ceccherini 
7733efb919SStefano Ceccherini 	input_device_ref device_ref;
7833efb919SStefano Ceccherini 	char driver_path[B_PATH_NAME_LENGTH];
790dbc4befSStefano Ceccherini 	int driver_fd;
800dbc4befSStefano Ceccherini 	thread_id device_watcher;
810dbc4befSStefano Ceccherini 	uint32 buttons_state;
8233efb919SStefano Ceccherini 	mouse_settings settings;
8333efb919SStefano Ceccherini 	bool active;
840dbc4befSStefano Ceccherini };
850dbc4befSStefano Ceccherini 
860dbc4befSStefano Ceccherini 
8733efb919SStefano Ceccherini // forward declarations
8833efb919SStefano Ceccherini static void scan_recursively(const char *directory, BList *list);
8933efb919SStefano Ceccherini static char *get_short_name(const char *longName);
9033efb919SStefano Ceccherini 
9133efb919SStefano Ceccherini 
9261d7deeeSJérôme Duval extern "C"
9361d7deeeSJérôme Duval BInputServerDevice *
9461d7deeeSJérôme Duval instantiate_input_device()
9561d7deeeSJérôme Duval {
9661d7deeeSJérôme Duval 	return new MouseInputDevice();
9761d7deeeSJérôme Duval }
9861d7deeeSJérôme Duval 
9961d7deeeSJérôme Duval 
10061d7deeeSJérôme Duval MouseInputDevice::MouseInputDevice()
10133efb919SStefano Ceccherini 	:	fDevices(NULL)
10233efb919SStefano Ceccherini 
10361d7deeeSJérôme Duval {
10433efb919SStefano Ceccherini 	ASSERT(sSingletonMouseDevice == NULL);
10533efb919SStefano Ceccherini 	sSingletonMouseDevice = this;
10661d7deeeSJérôme Duval 
1073aa69c78SStefano Ceccherini #if DEBUG
1080dbc4befSStefano Ceccherini 	if (sLogFile == NULL)
1095c506d7fSJérôme Duval 		sLogFile = fopen("/var/log/mouse_device_log.log", "a");
1103aa69c78SStefano Ceccherini #endif
11133efb919SStefano Ceccherini 
11233efb919SStefano Ceccherini 	StartMonitoringDevice(kMouseDevicesDirectoryUSB);
11361d7deeeSJérôme Duval }
11461d7deeeSJérôme Duval 
11561d7deeeSJérôme Duval 
11661d7deeeSJérôme Duval MouseInputDevice::~MouseInputDevice()
11761d7deeeSJérôme Duval {
11833efb919SStefano Ceccherini 	StopMonitoringDevice(kMouseDevicesDirectoryUSB);
11961d7deeeSJérôme Duval 
12033efb919SStefano Ceccherini 	for (int32 i = 0; i < fDevices->CountItems(); i++)
12133efb919SStefano Ceccherini 		delete (mouse_device *)fDevices->ItemAt(i);
12233efb919SStefano Ceccherini 
12333efb919SStefano Ceccherini 	delete fDevices;
12461d7deeeSJérôme Duval 
1253aa69c78SStefano Ceccherini #if DEBUG
1263aa69c78SStefano Ceccherini 	fclose(sLogFile);
1273aa69c78SStefano Ceccherini #endif
12861d7deeeSJérôme Duval }
12961d7deeeSJérôme Duval 
13061d7deeeSJérôme Duval 
13161d7deeeSJérôme Duval status_t
13233efb919SStefano Ceccherini MouseInputDevice::InitFromSettings(void *cookie, uint32 opcode)
13353d77642SJérôme Duval {
13433efb919SStefano Ceccherini 	mouse_device *device = (mouse_device *)cookie;
13533efb919SStefano Ceccherini 
13653d77642SJérôme Duval 	// retrieve current values
13753d77642SJérôme Duval 
13833efb919SStefano Ceccherini 	if (get_mouse_map(&device->settings.map) != B_OK)
13953d77642SJérôme Duval 		fprintf(stderr, "error when get_mouse_map\n");
14053d77642SJérôme Duval 	else
14133efb919SStefano Ceccherini 		ioctl(device->driver_fd, kSetMouseMap, &device->settings.map);
14253d77642SJérôme Duval 
14333efb919SStefano Ceccherini 	if (get_click_speed(&device->settings.click_speed) != B_OK)
14453d77642SJérôme Duval 		fprintf(stderr, "error when get_click_speed\n");
14553d77642SJérôme Duval 	else
14633efb919SStefano Ceccherini 		ioctl(device->driver_fd, kSetClickSpeed, &device->settings.click_speed);
14753d77642SJérôme Duval 
14833efb919SStefano Ceccherini 	if (get_mouse_speed(&device->settings.accel.speed) != B_OK)
14953d77642SJérôme Duval 		fprintf(stderr, "error when get_mouse_speed\n");
15053d77642SJérôme Duval 	else {
15133efb919SStefano Ceccherini 		if (get_mouse_acceleration(&device->settings.accel.accel_factor) != B_OK)
15253d77642SJérôme Duval 			fprintf(stderr, "error when get_mouse_acceleration\n");
15353d77642SJérôme Duval 		else {
15453d77642SJérôme Duval 			mouse_accel accel;
15533efb919SStefano Ceccherini 			ioctl(device->driver_fd, kGetMouseAccel, &accel);
15633efb919SStefano Ceccherini 			accel.speed = device->settings.accel.speed;
15733efb919SStefano Ceccherini 			accel.accel_factor = device->settings.accel.accel_factor;
15833efb919SStefano Ceccherini 			ioctl(device->driver_fd, kSetMouseAccel, &device->settings.accel);
15953d77642SJérôme Duval 		}
16053d77642SJérôme Duval 	}
16153d77642SJérôme Duval 
16233efb919SStefano Ceccherini 	if (get_mouse_type(&device->settings.type) != B_OK)
16353d77642SJérôme Duval 		fprintf(stderr, "error when get_mouse_type\n");
16453d77642SJérôme Duval 	else
16533efb919SStefano Ceccherini 		ioctl(device->driver_fd, kSetMouseType, &device->settings.type);
16653d77642SJérôme Duval 
16753d77642SJérôme Duval 	return B_OK;
16833efb919SStefano Ceccherini 
16953d77642SJérôme Duval }
17053d77642SJérôme Duval 
17153d77642SJérôme Duval 
17253d77642SJérôme Duval status_t
17361d7deeeSJérôme Duval MouseInputDevice::InitCheck()
17461d7deeeSJérôme Duval {
17533efb919SStefano Ceccherini 	BList list;
17633efb919SStefano Ceccherini 	scan_recursively(kMouseDevicesDirectory, &list);
17753d77642SJérôme Duval 
17833efb919SStefano Ceccherini 	char path[B_PATH_NAME_LENGTH];
17933efb919SStefano Ceccherini 	if (list.CountItems() > 0) {
18033efb919SStefano Ceccherini 		fDevices = new BList;
18133efb919SStefano Ceccherini 		for (int32 i = 0; i < list.CountItems(); i++) {
18233efb919SStefano Ceccherini 			strcpy(path, kMouseDevicesDirectory);
18333efb919SStefano Ceccherini 			strcat(path, "/");
18433efb919SStefano Ceccherini 			strcat(path, (char *)list.ItemAt(i));
18533efb919SStefano Ceccherini 			AddDevice(path);
18633efb919SStefano Ceccherini 			free(list.ItemAt(i));
18761d7deeeSJérôme Duval 		}
18833efb919SStefano Ceccherini 	}
18933efb919SStefano Ceccherini 
19033efb919SStefano Ceccherini 	if (fDevices && fDevices->CountItems() > 0)
19133efb919SStefano Ceccherini 		return BInputServerDevice::InitCheck();
19233efb919SStefano Ceccherini 
19361d7deeeSJérôme Duval 	return B_ERROR;
19461d7deeeSJérôme Duval }
19561d7deeeSJérôme Duval 
19661d7deeeSJérôme Duval 
19761d7deeeSJérôme Duval status_t
19861d7deeeSJérôme Duval MouseInputDevice::Start(const char *name, void *cookie)
19961d7deeeSJérôme Duval {
20033efb919SStefano Ceccherini 	mouse_device *device = (mouse_device *)cookie;
20133efb919SStefano Ceccherini 
2023aa69c78SStefano Ceccherini 	char log[128];
2033aa69c78SStefano Ceccherini 	snprintf(log, 128, "Start(%s)\n", name);
2043aa69c78SStefano Ceccherini 
2053aa69c78SStefano Ceccherini 	LOG(log);
20633efb919SStefano Ceccherini 
20733efb919SStefano Ceccherini 	char threadName[B_OS_NAME_LENGTH];
20833efb919SStefano Ceccherini 	snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", name);
20933efb919SStefano Ceccherini 
21033efb919SStefano Ceccherini 	device->active = true;
21133efb919SStefano Ceccherini 	device->device_watcher = spawn_thread(DeviceWatcher, threadName,
21233efb919SStefano Ceccherini 									kMouseThreadPriority, device);
21333efb919SStefano Ceccherini 
21433efb919SStefano Ceccherini 	resume_thread(device->device_watcher);
21533efb919SStefano Ceccherini 
21661d7deeeSJérôme Duval 
21761d7deeeSJérôme Duval 	return B_OK;
21861d7deeeSJérôme Duval }
21961d7deeeSJérôme Duval 
22061d7deeeSJérôme Duval 
22161d7deeeSJérôme Duval status_t
2223aa69c78SStefano Ceccherini MouseInputDevice::Stop(const char *name, void *cookie)
22361d7deeeSJérôme Duval {
22433efb919SStefano Ceccherini 	mouse_device *device = (mouse_device *)cookie;
22533efb919SStefano Ceccherini 
2263aa69c78SStefano Ceccherini 	char log[128];
2273aa69c78SStefano Ceccherini 	snprintf(log, 128, "Stop(%s)\n", name);
2283aa69c78SStefano Ceccherini 
2293aa69c78SStefano Ceccherini 	LOG(log);
23061d7deeeSJérôme Duval 
23133efb919SStefano Ceccherini 	device->active = false;
23233efb919SStefano Ceccherini 	if (device->device_watcher >= 0) {
23333efb919SStefano Ceccherini 		status_t dummy;
23433efb919SStefano Ceccherini 		wait_for_thread(device->device_watcher, &dummy);
23533efb919SStefano Ceccherini 	}
23661d7deeeSJérôme Duval 
23761d7deeeSJérôme Duval 	return B_OK;
23861d7deeeSJérôme Duval }
23961d7deeeSJérôme Duval 
24061d7deeeSJérôme Duval 
24161d7deeeSJérôme Duval status_t
24261d7deeeSJérôme Duval MouseInputDevice::Control(const char *name, void *cookie,
24361d7deeeSJérôme Duval 						  uint32 command, BMessage *message)
24461d7deeeSJérôme Duval {
2453aa69c78SStefano Ceccherini 	char log[128];
2463aa69c78SStefano Ceccherini 	snprintf(log, 128, "Control(%s, code: %lu)\n", name, command);
2473aa69c78SStefano Ceccherini 
2483aa69c78SStefano Ceccherini 	LOG(log);
24953d77642SJérôme Duval 
25053d77642SJérôme Duval 	if (command == B_NODE_MONITOR)
25153d77642SJérôme Duval 		HandleMonitor(message);
25253d77642SJérôme Duval 	else if (command >= B_MOUSE_TYPE_CHANGED
25353d77642SJérôme Duval 		&& command <= B_MOUSE_ACCELERATION_CHANGED) {
25433efb919SStefano Ceccherini 		InitFromSettings(cookie, command);
25553d77642SJérôme Duval 	}
25653d77642SJérôme Duval 	return B_OK;
25753d77642SJérôme Duval }
25853d77642SJérôme Duval 
25953d77642SJérôme Duval 
26033efb919SStefano Ceccherini // TODO: Test this. USB doesn't work on my machine
26133efb919SStefano Ceccherini status_t
26233efb919SStefano Ceccherini MouseInputDevice::HandleMonitor(BMessage *message)
26333efb919SStefano Ceccherini {
26433efb919SStefano Ceccherini 	int32 opcode = 0;
26533efb919SStefano Ceccherini 	status_t status;
26633efb919SStefano Ceccherini 	status = message->FindInt32("opcode", &opcode);
26733efb919SStefano Ceccherini 	if (status < B_OK)
26833efb919SStefano Ceccherini 		return status;
26933efb919SStefano Ceccherini 
27033efb919SStefano Ceccherini 	BEntry entry;
27133efb919SStefano Ceccherini 	BPath path;
27233efb919SStefano Ceccherini 	dev_t device;
27333efb919SStefano Ceccherini 	ino_t directory;
27433efb919SStefano Ceccherini 	ino_t node;
27533efb919SStefano Ceccherini 	const char *name = NULL;
27633efb919SStefano Ceccherini 
27733efb919SStefano Ceccherini 	switch (opcode) {
27833efb919SStefano Ceccherini 		case B_ENTRY_CREATED:
27933efb919SStefano Ceccherini 		{
28033efb919SStefano Ceccherini 			message->FindInt32("device", &device);
28133efb919SStefano Ceccherini 			message->FindInt64("directory", &directory);
28233efb919SStefano Ceccherini 			message->FindInt64("node", &node);
28333efb919SStefano Ceccherini 			message->FindString("name", &name);
28433efb919SStefano Ceccherini 
28533efb919SStefano Ceccherini 			entry_ref ref(device, directory, name);
28633efb919SStefano Ceccherini 
28733efb919SStefano Ceccherini 			status = entry.SetTo(&ref);
28833efb919SStefano Ceccherini 			if (status == B_OK);
28933efb919SStefano Ceccherini 				status = entry.GetPath(&path);
29033efb919SStefano Ceccherini 			if (status == B_OK)
29133efb919SStefano Ceccherini 				status = path.InitCheck();
29233efb919SStefano Ceccherini 			if (status == B_OK)
29333efb919SStefano Ceccherini 				status = AddDevice(path.Path());
29433efb919SStefano Ceccherini 
29533efb919SStefano Ceccherini 			break;
29633efb919SStefano Ceccherini 		}
29733efb919SStefano Ceccherini 		case B_ENTRY_REMOVED:
29833efb919SStefano Ceccherini 		{
29933efb919SStefano Ceccherini 			message->FindInt32("device", &device);
30033efb919SStefano Ceccherini 			message->FindInt64("directory", &directory);
30133efb919SStefano Ceccherini 			message->FindInt64("node", &node);
30233efb919SStefano Ceccherini 			message->FindString("name", &name);
30333efb919SStefano Ceccherini 
30433efb919SStefano Ceccherini 			entry_ref ref(device, directory, name);
30533efb919SStefano Ceccherini 
30633efb919SStefano Ceccherini 			status = entry.SetTo(&ref);
30733efb919SStefano Ceccherini 			if (status == B_OK);
30833efb919SStefano Ceccherini 				status = entry.GetPath(&path);
30933efb919SStefano Ceccherini 			if (status == B_OK)
31033efb919SStefano Ceccherini 				status = path.InitCheck();
31133efb919SStefano Ceccherini 			if (status == B_OK)
31233efb919SStefano Ceccherini 				status = RemoveDevice(path.Path());
31333efb919SStefano Ceccherini 
31433efb919SStefano Ceccherini 			break;
31533efb919SStefano Ceccherini 		}
31633efb919SStefano Ceccherini 		default:
31733efb919SStefano Ceccherini 			status = B_BAD_VALUE;
31833efb919SStefano Ceccherini 			break;
31933efb919SStefano Ceccherini 	}
32033efb919SStefano Ceccherini 
32133efb919SStefano Ceccherini 	return status;
32233efb919SStefano Ceccherini }
32333efb919SStefano Ceccherini 
32433efb919SStefano Ceccherini 
32553d77642SJérôme Duval status_t
32633efb919SStefano Ceccherini MouseInputDevice::AddDevice(const char *path)
32753d77642SJérôme Duval {
32833efb919SStefano Ceccherini 	mouse_device *device = new mouse_device(path);
32933efb919SStefano Ceccherini 	if (!device) {
33033efb919SStefano Ceccherini 		LOG("No memory\n");
33133efb919SStefano Ceccherini 		return B_NO_MEMORY;
33233efb919SStefano Ceccherini 	}
33333efb919SStefano Ceccherini 
33433efb919SStefano Ceccherini 	input_device_ref *devices[2];
33533efb919SStefano Ceccherini 	devices[0] = &device->device_ref;
33633efb919SStefano Ceccherini 	devices[1] = NULL;
33733efb919SStefano Ceccherini 
33833efb919SStefano Ceccherini 	fDevices->AddItem(device);
33933efb919SStefano Ceccherini 
34033efb919SStefano Ceccherini 	InitFromSettings(device);
34133efb919SStefano Ceccherini 
34233efb919SStefano Ceccherini 	return RegisterDevices(devices);
34333efb919SStefano Ceccherini }
34433efb919SStefano Ceccherini 
34533efb919SStefano Ceccherini 
34633efb919SStefano Ceccherini status_t
34733efb919SStefano Ceccherini MouseInputDevice::RemoveDevice(const char *path)
34833efb919SStefano Ceccherini {
34933efb919SStefano Ceccherini 	if (fDevices) {
35033efb919SStefano Ceccherini 		int32 i = 0;
35133efb919SStefano Ceccherini 		mouse_device *device = NULL;
35233efb919SStefano Ceccherini 		while ((device = (mouse_device *)fDevices->ItemAt(i)) != NULL) {
35333efb919SStefano Ceccherini 			if (!strcmp(device->driver_path, path)) {
35433efb919SStefano Ceccherini 				fDevices->RemoveItem(device);
35533efb919SStefano Ceccherini 				delete device;
35661d7deeeSJérôme Duval 				return B_OK;
35761d7deeeSJérôme Duval 			}
35833efb919SStefano Ceccherini 		}
35933efb919SStefano Ceccherini 	}
36033efb919SStefano Ceccherini 
36133efb919SStefano Ceccherini 	return B_ENTRY_NOT_FOUND;
36233efb919SStefano Ceccherini }
36361d7deeeSJérôme Duval 
36461d7deeeSJérôme Duval 
36561d7deeeSJérôme Duval int32
36661d7deeeSJérôme Duval MouseInputDevice::DeviceWatcher(void *arg)
36761d7deeeSJérôme Duval {
36833efb919SStefano Ceccherini 	mouse_device *dev = (mouse_device *)arg;
36933efb919SStefano Ceccherini 
37061d7deeeSJérôme Duval 	mouse_movement movements;
37161d7deeeSJérôme Duval 	BMessage *message;
37261d7deeeSJérôme Duval 	char log[128];
37333efb919SStefano Ceccherini 	while (dev->active) {
374*7d5d344bSJérôme Duval 		memset(&movements, 0, sizeof(movements));
37533efb919SStefano Ceccherini 		if (ioctl(dev->driver_fd, kGetMouseMovements, &movements) < B_OK)
376145a357dSStefano Ceccherini 			continue;
37761d7deeeSJérôme Duval 
37833efb919SStefano Ceccherini 		uint32 buttons = dev->buttons_state ^ movements.buttons;
37961d7deeeSJérôme Duval 
38033efb919SStefano Ceccherini 		snprintf(log, 128, "%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld\n",
38133efb919SStefano Ceccherini 				dev->device_ref.name, movements.buttons, movements.xdelta,
382fc2045eeSJérôme Duval 				movements.ydelta, movements.clicks);
38361d7deeeSJérôme Duval 
3843aa69c78SStefano Ceccherini 		LOG(log);
3853aa69c78SStefano Ceccherini 
386fc2045eeSJérôme Duval 		// TODO: add acceleration computing
387fc2045eeSJérôme Duval 		int32 xdelta = movements.xdelta * dev->settings.accel.speed >> 15;
388fc2045eeSJérôme Duval 		int32 ydelta = movements.ydelta * dev->settings.accel.speed >> 15;
389fc2045eeSJérôme Duval 
3903aa69c78SStefano Ceccherini 		// TODO: B_MOUSE_DOWN and B_MOUSE_UP messages don't seem
39133efb919SStefano Ceccherini 		// to be generated correctly.
3923aa69c78SStefano Ceccherini 		if (buttons != 0) {
393fc2045eeSJérôme Duval 			message = new BMessage(B_MOUSE_UP);
3943f8c0d7eSJérôme Duval 			if ((buttons & movements.buttons) > 0) {
3953aa69c78SStefano Ceccherini 				message->what = B_MOUSE_DOWN;
396fc2045eeSJérôme Duval 				message->AddInt32("clicks", movements.clicks);
3973aa69c78SStefano Ceccherini 				LOG("B_MOUSE_DOWN\n");
398e361bf69SJérôme Duval 			} else {
3993aa69c78SStefano Ceccherini 				LOG("B_MOUSE_UP\n");
4003aa69c78SStefano Ceccherini 			}
4013aa69c78SStefano Ceccherini 
402fc2045eeSJérôme Duval 			message->AddInt64("when", movements.timestamp);
403e361bf69SJérôme Duval 			message->AddInt32("buttons", movements.buttons);
404fc2045eeSJérôme Duval 			message->AddInt32("x", xdelta);
405fc2045eeSJérôme Duval 			message->AddInt32("y", ydelta);
40633efb919SStefano Ceccherini 			sSingletonMouseDevice->EnqueueMessage(message);
407fc2045eeSJérôme Duval 			dev->buttons_state = movements.buttons;
4083aa69c78SStefano Ceccherini 		}
4093aa69c78SStefano Ceccherini 
4103aa69c78SStefano Ceccherini 		if (movements.xdelta != 0 || movements.ydelta != 0) {
4113aa69c78SStefano Ceccherini 			message = new BMessage(B_MOUSE_MOVED);
4123aa69c78SStefano Ceccherini 			if (message) {
413fc2045eeSJérôme Duval 				message->AddInt64("when", movements.timestamp);
4143aa69c78SStefano Ceccherini 				message->AddInt32("buttons", movements.buttons);
415fc2045eeSJérôme Duval 				message->AddInt32("x", xdelta);
416fc2045eeSJérôme Duval 				message->AddInt32("y", ydelta);
4173aa69c78SStefano Ceccherini 
41833efb919SStefano Ceccherini 				sSingletonMouseDevice->EnqueueMessage(message);
4193aa69c78SStefano Ceccherini 			}
42061d7deeeSJérôme Duval 		}
421fc2045eeSJérôme Duval 
422*7d5d344bSJérôme Duval 		if ((movements.wheel_ydelta != 0) || (movements.wheel_xdelta != 0)) {
423fc2045eeSJérôme Duval 			message = new BMessage(B_MOUSE_WHEEL_CHANGED);
424fc2045eeSJérôme Duval 			if (message) {
425fc2045eeSJérôme Duval 				message->AddInt64("when", movements.timestamp);
426*7d5d344bSJérôme Duval 				message->AddFloat("be:wheel_delta_x", movements.wheel_xdelta);
427*7d5d344bSJérôme Duval 				message->AddFloat("be:wheel_delta_y", movements.wheel_ydelta);
428fc2045eeSJérôme Duval 
429fc2045eeSJérôme Duval 				sSingletonMouseDevice->EnqueueMessage(message);
430fc2045eeSJérôme Duval 			}
431fc2045eeSJérôme Duval 		}
432fc2045eeSJérôme Duval 
43361d7deeeSJérôme Duval 	}
43461d7deeeSJérôme Duval 
43561d7deeeSJérôme Duval 	return 0;
43661d7deeeSJérôme Duval }
43761d7deeeSJérôme Duval 
43861d7deeeSJérôme Duval 
43933efb919SStefano Ceccherini // mouse_device
44033efb919SStefano Ceccherini mouse_device::mouse_device(const char *path)
44133efb919SStefano Ceccherini {
44233efb919SStefano Ceccherini 	driver_fd = -1;
44333efb919SStefano Ceccherini 	device_watcher = -1;
44433efb919SStefano Ceccherini 	buttons_state = 0;
44533efb919SStefano Ceccherini 	active = false;
44633efb919SStefano Ceccherini 	strcpy(driver_path, path);
44733efb919SStefano Ceccherini 	device_ref.name = get_short_name(path);
44833efb919SStefano Ceccherini 	device_ref.type = B_POINTING_DEVICE;
44933efb919SStefano Ceccherini 	device_ref.cookie = this;
45033efb919SStefano Ceccherini 
45133efb919SStefano Ceccherini 	// TODO: Add a function which checks if the object
45233efb919SStefano Ceccherini 	// has initialized correctly. Specifically, this is one
45333efb919SStefano Ceccherini 	// of the operations which could fail
45433efb919SStefano Ceccherini 	driver_fd = open(driver_path, O_RDWR);
45533efb919SStefano Ceccherini };
45633efb919SStefano Ceccherini 
45733efb919SStefano Ceccherini 
45833efb919SStefano Ceccherini mouse_device::~mouse_device()
45933efb919SStefano Ceccherini {
46033efb919SStefano Ceccherini 	free(device_ref.name);
46133efb919SStefano Ceccherini 	if (driver_fd >= 0)
46233efb919SStefano Ceccherini 		close(driver_fd);
46333efb919SStefano Ceccherini }
46433efb919SStefano Ceccherini 
46533efb919SStefano Ceccherini 
46633efb919SStefano Ceccherini // static functions
46733efb919SStefano Ceccherini 
46833efb919SStefano Ceccherini // On exit, "list" will contain a string for every file in
46933efb919SStefano Ceccherini // the tree, starting from the given "directory". Note that
47033efb919SStefano Ceccherini // the file names will also contain the name of the parent folder.
47133efb919SStefano Ceccherini static void
47233efb919SStefano Ceccherini scan_recursively(const char *directory, BList *list)
47333efb919SStefano Ceccherini {
47433efb919SStefano Ceccherini 	// TODO: See if it's simpler to use POSIX functions
47533efb919SStefano Ceccherini 	BEntry entry;
47633efb919SStefano Ceccherini 	BDirectory dir(directory);
47733efb919SStefano Ceccherini 	char buf[B_OS_NAME_LENGTH];
47833efb919SStefano Ceccherini 	while (dir.GetNextEntry(&entry) == B_OK) {
47933efb919SStefano Ceccherini 		entry.GetName(buf);
48033efb919SStefano Ceccherini 		BPath child(&dir, buf);
48133efb919SStefano Ceccherini 
48233efb919SStefano Ceccherini 		if (entry.IsDirectory())
48333efb919SStefano Ceccherini 			scan_recursively(child.Path(), list);
48433efb919SStefano Ceccherini 		else {
48533efb919SStefano Ceccherini 			BPath parent(directory);
48633efb919SStefano Ceccherini 			BString deviceName = parent.Leaf();
48733efb919SStefano Ceccherini 			deviceName << "/" << buf;
48833efb919SStefano Ceccherini 			list->AddItem(strdup(deviceName.String()));
48933efb919SStefano Ceccherini 		}
49033efb919SStefano Ceccherini 	}
49133efb919SStefano Ceccherini }
49233efb919SStefano Ceccherini 
49333efb919SStefano Ceccherini 
49433efb919SStefano Ceccherini static char *
49533efb919SStefano Ceccherini get_short_name(const char *longName)
49633efb919SStefano Ceccherini {
49733efb919SStefano Ceccherini 	BString string(longName);
49833efb919SStefano Ceccherini 	BString name;
49933efb919SStefano Ceccherini 
50033efb919SStefano Ceccherini 	int32 slash = string.FindLast("/");
50133efb919SStefano Ceccherini 	int32 previousSlash = string.FindLast("/", slash) + 1;
50233efb919SStefano Ceccherini 	string.CopyInto(name, slash, string.Length() - slash);
50333efb919SStefano Ceccherini 
50433efb919SStefano Ceccherini 	int32 deviceIndex = atoi(name.String()) + 1;
50533efb919SStefano Ceccherini 	string.CopyInto(name, previousSlash, slash - previousSlash);
50633efb919SStefano Ceccherini 	name << " mouse " << deviceIndex;
50733efb919SStefano Ceccherini 
50833efb919SStefano Ceccherini 	return strdup(name.String());
50933efb919SStefano Ceccherini }
510