xref: /haiku/src/add-ons/input_server/devices/mouse/MouseInputDevice.cpp (revision 6af8fc09735b8cd7efc713db08f3fee0ded2aa6f)
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 //
7*6af8fc09SStefano Ceccherini // Copyright (c) 2004-2005 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 
37c2fbfb71SJérôme Duval #include <Debug.h>
3833efb919SStefano Ceccherini #include <Directory.h>
3933efb919SStefano Ceccherini #include <Entry.h>
4033efb919SStefano Ceccherini #include <NodeMonitor.h>
4133efb919SStefano Ceccherini #include <Path.h>
4233efb919SStefano Ceccherini #include <String.h>
4333efb919SStefano Ceccherini 
443aa69c78SStefano Ceccherini #if DEBUG
45c2fbfb71SJé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); \
46c2fbfb71SJérôme Duval                 fputs(buf, MouseInputDevice::sLogFile); fflush(MouseInputDevice::sLogFile); }
47c2fbfb71SJérôme Duval         #define LOG_ERR(text...) LOG(text)
48c2fbfb71SJérôme Duval FILE *MouseInputDevice::sLogFile = NULL;
493aa69c78SStefano Ceccherini #else
50c2fbfb71SJérôme Duval         #define LOG(text...)
51c2fbfb71SJérôme Duval         #define LOG_ERR(text...) fprintf(stderr, text)
523aa69c78SStefano Ceccherini #endif
533aa69c78SStefano Ceccherini 
54c2fbfb71SJérôme Duval #define CALLED() LOG("%s\n", __PRETTY_FUNCTION__)
5533efb919SStefano Ceccherini 
5633efb919SStefano Ceccherini static MouseInputDevice *sSingletonMouseDevice = NULL;
573aa69c78SStefano Ceccherini 
5833efb919SStefano Ceccherini const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4;
5933efb919SStefano Ceccherini const static char *kMouseDevicesDirectory = "/dev/input/mouse";
6033efb919SStefano Ceccherini 
6133efb919SStefano Ceccherini // "/dev/" is automatically prepended by StartMonitoringDevice()
6233efb919SStefano Ceccherini const static char *kMouseDevicesDirectoryUSB = "input/mouse/usb";
6333efb919SStefano Ceccherini 
640dbc4befSStefano Ceccherini struct mouse_device {
6533efb919SStefano Ceccherini 	mouse_device(const char *path);
6633efb919SStefano Ceccherini 	~mouse_device();
6733efb919SStefano Ceccherini 
6833efb919SStefano Ceccherini 	input_device_ref device_ref;
69c2fbfb71SJérôme Duval 	char path[B_PATH_NAME_LENGTH];
70c2fbfb71SJérôme Duval 	int fd;
710dbc4befSStefano Ceccherini 	thread_id device_watcher;
7233efb919SStefano Ceccherini 	mouse_settings settings;
7333efb919SStefano Ceccherini 	bool active;
740dbc4befSStefano Ceccherini };
750dbc4befSStefano Ceccherini 
760dbc4befSStefano Ceccherini 
7733efb919SStefano Ceccherini // forward declarations
7833efb919SStefano Ceccherini static char *get_short_name(const char *longName);
7933efb919SStefano Ceccherini 
8033efb919SStefano Ceccherini 
8161d7deeeSJérôme Duval extern "C"
8261d7deeeSJérôme Duval BInputServerDevice *
8361d7deeeSJérôme Duval instantiate_input_device()
8461d7deeeSJérôme Duval {
8561d7deeeSJérôme Duval 	return new MouseInputDevice();
8661d7deeeSJérôme Duval }
8761d7deeeSJérôme Duval 
8861d7deeeSJérôme Duval 
8961d7deeeSJérôme Duval MouseInputDevice::MouseInputDevice()
9061d7deeeSJérôme Duval {
9133efb919SStefano Ceccherini 	ASSERT(sSingletonMouseDevice == NULL);
9233efb919SStefano Ceccherini 	sSingletonMouseDevice = this;
9361d7deeeSJérôme Duval 
943aa69c78SStefano Ceccherini #if DEBUG
955c506d7fSJérôme Duval 	sLogFile = fopen("/var/log/mouse_device_log.log", "a");
963aa69c78SStefano Ceccherini #endif
97c2fbfb71SJérôme Duval 	CALLED();
9833efb919SStefano Ceccherini 
9933efb919SStefano Ceccherini 	StartMonitoringDevice(kMouseDevicesDirectoryUSB);
10061d7deeeSJérôme Duval }
10161d7deeeSJérôme Duval 
10261d7deeeSJérôme Duval 
10361d7deeeSJérôme Duval MouseInputDevice::~MouseInputDevice()
10461d7deeeSJérôme Duval {
105c2fbfb71SJérôme Duval 	CALLED();
10633efb919SStefano Ceccherini 	StopMonitoringDevice(kMouseDevicesDirectoryUSB);
10761d7deeeSJérôme Duval 
108c2fbfb71SJérôme Duval 	for (int32 i = 0; i < fDevices.CountItems(); i++)
109c2fbfb71SJérôme Duval 		delete (mouse_device *)fDevices.ItemAt(i);
11061d7deeeSJérôme Duval 
1113aa69c78SStefano Ceccherini #if DEBUG
1123aa69c78SStefano Ceccherini 	fclose(sLogFile);
1133aa69c78SStefano Ceccherini #endif
11461d7deeeSJérôme Duval }
11561d7deeeSJérôme Duval 
11661d7deeeSJérôme Duval 
11761d7deeeSJérôme Duval status_t
11833efb919SStefano Ceccherini MouseInputDevice::InitFromSettings(void *cookie, uint32 opcode)
11953d77642SJérôme Duval {
1207dcdcad2SJérôme Duval 	CALLED();
12133efb919SStefano Ceccherini 	mouse_device *device = (mouse_device *)cookie;
12233efb919SStefano Ceccherini 
12353d77642SJérôme Duval 	// retrieve current values
12453d77642SJérôme Duval 
12533efb919SStefano Ceccherini 	if (get_mouse_map(&device->settings.map) != B_OK)
126c2fbfb71SJérôme Duval 		LOG_ERR("error when get_mouse_map\n");
12753d77642SJérôme Duval 	else
128c2fbfb71SJérôme Duval 		ioctl(device->fd, MS_SET_MAP, &device->settings.map);
12953d77642SJérôme Duval 
13033efb919SStefano Ceccherini 	if (get_click_speed(&device->settings.click_speed) != B_OK)
131c2fbfb71SJérôme Duval 		LOG_ERR("error when get_click_speed\n");
13253d77642SJérôme Duval 	else
133c2fbfb71SJérôme Duval 		ioctl(device->fd, MS_SET_CLICKSPEED, &device->settings.click_speed);
13453d77642SJérôme Duval 
13533efb919SStefano Ceccherini 	if (get_mouse_speed(&device->settings.accel.speed) != B_OK)
136c2fbfb71SJérôme Duval 		LOG_ERR("error when get_mouse_speed\n");
13753d77642SJérôme Duval 	else {
13833efb919SStefano Ceccherini 		if (get_mouse_acceleration(&device->settings.accel.accel_factor) != B_OK)
139c2fbfb71SJérôme Duval 			LOG_ERR("error when get_mouse_acceleration\n");
14053d77642SJérôme Duval 		else {
14153d77642SJérôme Duval 			mouse_accel accel;
142c2fbfb71SJérôme Duval 			ioctl(device->fd, MS_GET_ACCEL, &accel);
14333efb919SStefano Ceccherini 			accel.speed = device->settings.accel.speed;
14433efb919SStefano Ceccherini 			accel.accel_factor = device->settings.accel.accel_factor;
145c2fbfb71SJérôme Duval 			ioctl(device->fd, MS_SET_ACCEL, &device->settings.accel);
14653d77642SJérôme Duval 		}
14753d77642SJérôme Duval 	}
14853d77642SJérôme Duval 
14933efb919SStefano Ceccherini 	if (get_mouse_type(&device->settings.type) != B_OK)
150c2fbfb71SJérôme Duval 		LOG_ERR("error when get_mouse_type\n");
15153d77642SJérôme Duval 	else
152c2fbfb71SJérôme Duval 		ioctl(device->fd, MS_SET_TYPE, &device->settings.type);
15353d77642SJérôme Duval 
15453d77642SJérôme Duval 	return B_OK;
15533efb919SStefano Ceccherini 
15653d77642SJérôme Duval }
15753d77642SJérôme Duval 
15853d77642SJérôme Duval 
15953d77642SJérôme Duval status_t
16061d7deeeSJérôme Duval MouseInputDevice::InitCheck()
16161d7deeeSJérôme Duval {
162c2fbfb71SJérôme Duval 	CALLED();
163c2fbfb71SJérôme Duval 	RecursiveScan(kMouseDevicesDirectory);
16453d77642SJérôme Duval 
165c2fbfb71SJérôme Duval 	return B_OK;
16661d7deeeSJérôme Duval }
16761d7deeeSJérôme Duval 
16861d7deeeSJérôme Duval 
16961d7deeeSJérôme Duval status_t
17061d7deeeSJérôme Duval MouseInputDevice::Start(const char *name, void *cookie)
17161d7deeeSJérôme Duval {
17233efb919SStefano Ceccherini 	mouse_device *device = (mouse_device *)cookie;
17333efb919SStefano Ceccherini 
174c2fbfb71SJérôme Duval 	LOG("%s(%s)\n", __PRETTY_FUNCTION__, name);
1753aa69c78SStefano Ceccherini 
176c2fbfb71SJérôme Duval 	device->fd = open(device->path, O_RDWR);
177c2fbfb71SJérôme Duval 	if (device->fd < 0)
178*6af8fc09SStefano Ceccherini 		return device->fd;
179c2fbfb71SJérôme Duval 
180*6af8fc09SStefano Ceccherini 	status_t status = InitFromSettings(device);
181*6af8fc09SStefano Ceccherini 	if (status < B_OK) {
182*6af8fc09SStefano Ceccherini 		LOG_ERR("%s: can't initialize from settings: %s\n",
183*6af8fc09SStefano Ceccherini 			name, strerror(status));
184*6af8fc09SStefano Ceccherini 		return status;
185*6af8fc09SStefano Ceccherini 	}
18633efb919SStefano Ceccherini 
18733efb919SStefano Ceccherini 	char threadName[B_OS_NAME_LENGTH];
18833efb919SStefano Ceccherini 	snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", name);
18933efb919SStefano Ceccherini 
19033efb919SStefano Ceccherini 	device->active = true;
19133efb919SStefano Ceccherini 	device->device_watcher = spawn_thread(DeviceWatcher, threadName,
19233efb919SStefano Ceccherini 		kMouseThreadPriority, device);
19333efb919SStefano Ceccherini 
194*6af8fc09SStefano Ceccherini 	if (device->device_watcher < B_OK) {
195*6af8fc09SStefano Ceccherini 		LOG_ERR("%s: can't spawn watching thread: %s\n",
196*6af8fc09SStefano Ceccherini 			name, strerror(device->device_watcher));
197*6af8fc09SStefano Ceccherini 		return device->device_watcher;
198*6af8fc09SStefano Ceccherini 	}
199*6af8fc09SStefano Ceccherini 
200*6af8fc09SStefano Ceccherini 	status = resume_thread(device->device_watcher);
201*6af8fc09SStefano Ceccherini 	if (status < B_OK) {
202*6af8fc09SStefano Ceccherini 		LOG_ERR("%s: can't resume watching thread: %s\n",
203*6af8fc09SStefano Ceccherini 			name, strerror(status));
204*6af8fc09SStefano Ceccherini 		return status;
205*6af8fc09SStefano Ceccherini 	}
20633efb919SStefano Ceccherini 
20761d7deeeSJérôme Duval 	return B_OK;
20861d7deeeSJérôme Duval }
20961d7deeeSJérôme Duval 
21061d7deeeSJérôme Duval 
21161d7deeeSJérôme Duval status_t
2123aa69c78SStefano Ceccherini MouseInputDevice::Stop(const char *name, void *cookie)
21361d7deeeSJérôme Duval {
21433efb919SStefano Ceccherini 	mouse_device *device = (mouse_device *)cookie;
21533efb919SStefano Ceccherini 
216c2fbfb71SJérôme Duval 	LOG("%s(%s)\n", __PRETTY_FUNCTION__, name);
2173aa69c78SStefano Ceccherini 
218c2fbfb71SJérôme Duval 	close(device->fd);
21961d7deeeSJérôme Duval 
22033efb919SStefano Ceccherini 	device->active = false;
22133efb919SStefano Ceccherini 	if (device->device_watcher >= 0) {
222*6af8fc09SStefano Ceccherini 		// TODO: This is done to unblock the thread,
223*6af8fc09SStefano Ceccherini 		// which is waiting on a semaphore.
224c2fbfb71SJérôme Duval 		suspend_thread(device->device_watcher);
225c2fbfb71SJérôme Duval 		resume_thread(device->device_watcher);
22633efb919SStefano Ceccherini 		status_t dummy;
22733efb919SStefano Ceccherini 		wait_for_thread(device->device_watcher, &dummy);
22833efb919SStefano Ceccherini 	}
22961d7deeeSJérôme Duval 
23061d7deeeSJérôme Duval 	return B_OK;
23161d7deeeSJérôme Duval }
23261d7deeeSJérôme Duval 
23361d7deeeSJérôme Duval 
23461d7deeeSJérôme Duval status_t
23561d7deeeSJérôme Duval MouseInputDevice::Control(const char *name, void *cookie,
23661d7deeeSJérôme Duval 						  uint32 command, BMessage *message)
23761d7deeeSJérôme Duval {
238c2fbfb71SJérôme Duval 	LOG("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command);
239*6af8fc09SStefano Ceccherini 	status_t status = B_BAD_VALUE;
24053d77642SJérôme Duval 
24153d77642SJérôme Duval 	if (command == B_NODE_MONITOR)
242*6af8fc09SStefano Ceccherini 		status = HandleMonitor(message);
24353d77642SJérôme Duval 	else if (command >= B_MOUSE_TYPE_CHANGED
24453d77642SJérôme Duval 		&& command <= B_MOUSE_ACCELERATION_CHANGED) {
245*6af8fc09SStefano Ceccherini 		status = InitFromSettings(cookie, command);
24653d77642SJérôme Duval 	}
247*6af8fc09SStefano Ceccherini 	return status;
24853d77642SJérôme Duval }
24953d77642SJérôme Duval 
25053d77642SJérôme Duval 
25133efb919SStefano Ceccherini // TODO: Test this. USB doesn't work on my machine
25233efb919SStefano Ceccherini status_t
25333efb919SStefano Ceccherini MouseInputDevice::HandleMonitor(BMessage *message)
25433efb919SStefano Ceccherini {
255c2fbfb71SJérôme Duval 	CALLED();
25633efb919SStefano Ceccherini 	int32 opcode = 0;
25733efb919SStefano Ceccherini 	status_t status;
258c2fbfb71SJérôme Duval 	if ((status = message->FindInt32("opcode", &opcode)) < B_OK)
25933efb919SStefano Ceccherini 	        return status;
26033efb919SStefano Ceccherini 
261c2fbfb71SJérôme Duval 	if ((opcode != B_ENTRY_CREATED)
262c2fbfb71SJérôme Duval 	        && (opcode != B_ENTRY_REMOVED))
263c2fbfb71SJérôme Duval 	        return B_OK;
264c2fbfb71SJérôme Duval 
26533efb919SStefano Ceccherini 	BEntry entry;
26633efb919SStefano Ceccherini 	BPath path;
26733efb919SStefano Ceccherini 	dev_t device;
26833efb919SStefano Ceccherini 	ino_t directory;
26933efb919SStefano Ceccherini 	const char *name = NULL;
27033efb919SStefano Ceccherini 
27133efb919SStefano Ceccherini 	message->FindInt32("device", &device);
27233efb919SStefano Ceccherini 	message->FindInt64("directory", &directory);
27333efb919SStefano Ceccherini 	message->FindString("name", &name);
27433efb919SStefano Ceccherini 
27533efb919SStefano Ceccherini 	entry_ref ref(device, directory, name);
27633efb919SStefano Ceccherini 
277c2fbfb71SJérôme Duval 	if ((status = entry.SetTo(&ref)) != B_OK)
278c2fbfb71SJérôme Duval 	        return status;
279c2fbfb71SJérôme Duval 	if ((status = entry.GetPath(&path)) != B_OK)
280c2fbfb71SJérôme Duval 	        return status;
281c2fbfb71SJérôme Duval 	if ((status = path.InitCheck()) != B_OK)
282c2fbfb71SJérôme Duval 	        return status;
28333efb919SStefano Ceccherini 
284c2fbfb71SJérôme Duval 	if (opcode == B_ENTRY_CREATED)
285*6af8fc09SStefano Ceccherini 		status = AddDevice(path.Path());
286c2fbfb71SJérôme Duval 	else
287*6af8fc09SStefano Ceccherini 		status = RemoveDevice(path.Path());
28833efb919SStefano Ceccherini 
28933efb919SStefano Ceccherini 	return status;
29033efb919SStefano Ceccherini }
29133efb919SStefano Ceccherini 
29233efb919SStefano Ceccherini 
29353d77642SJérôme Duval status_t
29433efb919SStefano Ceccherini MouseInputDevice::AddDevice(const char *path)
29553d77642SJérôme Duval {
296c2fbfb71SJérôme Duval 	CALLED();
297c2fbfb71SJérôme Duval 
29833efb919SStefano Ceccherini 	mouse_device *device = new mouse_device(path);
29933efb919SStefano Ceccherini 	if (!device) {
30033efb919SStefano Ceccherini 		LOG("No memory\n");
30133efb919SStefano Ceccherini 		return B_NO_MEMORY;
30233efb919SStefano Ceccherini 	}
30333efb919SStefano Ceccherini 
30433efb919SStefano Ceccherini 	input_device_ref *devices[2];
30533efb919SStefano Ceccherini 	devices[0] = &device->device_ref;
30633efb919SStefano Ceccherini 	devices[1] = NULL;
30733efb919SStefano Ceccherini 
308c2fbfb71SJérôme Duval 	fDevices.AddItem(device);
30933efb919SStefano Ceccherini 
31033efb919SStefano Ceccherini 	return RegisterDevices(devices);
31133efb919SStefano Ceccherini }
31233efb919SStefano Ceccherini 
31333efb919SStefano Ceccherini 
31433efb919SStefano Ceccherini status_t
31533efb919SStefano Ceccherini MouseInputDevice::RemoveDevice(const char *path)
31633efb919SStefano Ceccherini {
317c2fbfb71SJérôme Duval 	CALLED();
31833efb919SStefano Ceccherini 	int32 i = 0;
31933efb919SStefano Ceccherini 	mouse_device *device = NULL;
320c2fbfb71SJérôme Duval 	while ((device = (mouse_device *)fDevices.ItemAt(i)) != NULL) {
321c2fbfb71SJérôme Duval 		if (!strcmp(device->path, path)) {
322c2fbfb71SJérôme Duval 			fDevices.RemoveItem(device);
32333efb919SStefano Ceccherini 			delete device;
32461d7deeeSJérôme Duval 			return B_OK;
32561d7deeeSJérôme Duval 		}
32633efb919SStefano Ceccherini 	}
32733efb919SStefano Ceccherini 
32833efb919SStefano Ceccherini 	return B_ENTRY_NOT_FOUND;
32933efb919SStefano Ceccherini }
33061d7deeeSJérôme Duval 
33161d7deeeSJérôme Duval 
33261d7deeeSJérôme Duval int32
33361d7deeeSJérôme Duval MouseInputDevice::DeviceWatcher(void *arg)
33461d7deeeSJérôme Duval {
33533efb919SStefano Ceccherini 	mouse_device *dev = (mouse_device *)arg;
33633efb919SStefano Ceccherini 
33761d7deeeSJérôme Duval 	mouse_movement movements;
3382895720cSJérôme Duval 	uint32 buttons_state = 0;
33961d7deeeSJérôme Duval 	BMessage *message;
34033efb919SStefano Ceccherini 	while (dev->active) {
3417d5d344bSJérôme Duval 		memset(&movements, 0, sizeof(movements));
342c2fbfb71SJérôme Duval 		if (ioctl(dev->fd, MS_READ, &movements) < B_OK)
343145a357dSStefano Ceccherini 			continue;
34461d7deeeSJérôme Duval 
345c2fbfb71SJérôme Duval 		uint32 buttons = buttons_state ^ movements.buttons;
34661d7deeeSJérôme Duval 
3475a23ac26SJé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,
3485a23ac26SJérôme Duval 			movements.xdelta, movements.ydelta, movements.clicks, movements.wheel_xdelta, movements.wheel_ydelta);
3493aa69c78SStefano Ceccherini 
350fc2045eeSJérôme Duval 		// TODO: add acceleration computing
351fc2045eeSJérôme Duval 		int32 xdelta = movements.xdelta * dev->settings.accel.speed >> 15;
3526be0f7efSJérôme Duval 		int32 ydelta = movements.ydelta * dev->settings.accel.speed >> 15;
3536ed407d8SJérôme Duval 
354c2fbfb71SJérôme Duval 		LOG("%s: x: %ld, y: %ld, \n", dev->device_ref.name, xdelta, ydelta);
3556ed407d8SJérôme Duval 
356*6af8fc09SStefano Ceccherini 		// TODO: Here we send B_MOUSE_UP/DOWN before B_MOUSE_MOVED.
357*6af8fc09SStefano Ceccherini 		// This could be the cause of the bug in RootLayer.cpp:
358*6af8fc09SStefano Ceccherini 		// "mouse position changed in B_MOUSE_DOWN from last B_MOUSE_MOVED".
359*6af8fc09SStefano Ceccherini 		// Might be wiser to switch the order.
3603aa69c78SStefano Ceccherini 		if (buttons != 0) {
361fc2045eeSJérôme Duval 			message = new BMessage(B_MOUSE_UP);
3623f8c0d7eSJérôme Duval 			if ((buttons & movements.buttons) > 0) {
3633aa69c78SStefano Ceccherini 				message->what = B_MOUSE_DOWN;
364fc2045eeSJérôme Duval 				message->AddInt32("clicks", movements.clicks);
3653aa69c78SStefano Ceccherini 				LOG("B_MOUSE_DOWN\n");
366e361bf69SJérôme Duval 			} else {
3673aa69c78SStefano Ceccherini 				LOG("B_MOUSE_UP\n");
3683aa69c78SStefano Ceccherini 			}
3693aa69c78SStefano Ceccherini 
370fc2045eeSJérôme Duval 			message->AddInt64("when", movements.timestamp);
371e361bf69SJérôme Duval 			message->AddInt32("buttons", movements.buttons);
372fc2045eeSJérôme Duval 			message->AddInt32("x", xdelta);
373fc2045eeSJérôme Duval 			message->AddInt32("y", ydelta);
37433efb919SStefano Ceccherini 			sSingletonMouseDevice->EnqueueMessage(message);
375c2fbfb71SJérôme Duval 			buttons_state = movements.buttons;
3763aa69c78SStefano Ceccherini 		}
3773aa69c78SStefano Ceccherini 
3783aa69c78SStefano Ceccherini 		if (movements.xdelta != 0 || movements.ydelta != 0) {
3793aa69c78SStefano Ceccherini 			message = new BMessage(B_MOUSE_MOVED);
3803aa69c78SStefano Ceccherini 			if (message) {
381fc2045eeSJérôme Duval 				message->AddInt64("when", movements.timestamp);
3823aa69c78SStefano Ceccherini 				message->AddInt32("buttons", movements.buttons);
383fc2045eeSJérôme Duval 				message->AddInt32("x", xdelta);
384fc2045eeSJérôme Duval 				message->AddInt32("y", ydelta);
3853aa69c78SStefano Ceccherini 
38633efb919SStefano Ceccherini 				sSingletonMouseDevice->EnqueueMessage(message);
3873aa69c78SStefano Ceccherini 			}
38861d7deeeSJérôme Duval 		}
389fc2045eeSJérôme Duval 
3907d5d344bSJérôme Duval 		if ((movements.wheel_ydelta != 0) || (movements.wheel_xdelta != 0)) {
391fc2045eeSJérôme Duval 			message = new BMessage(B_MOUSE_WHEEL_CHANGED);
392fc2045eeSJérôme Duval 			if (message) {
393fc2045eeSJérôme Duval 				message->AddInt64("when", movements.timestamp);
3947d5d344bSJérôme Duval 				message->AddFloat("be:wheel_delta_x", movements.wheel_xdelta);
3957d5d344bSJérôme Duval 				message->AddFloat("be:wheel_delta_y", movements.wheel_ydelta);
396fc2045eeSJérôme Duval 
397fc2045eeSJérôme Duval 				sSingletonMouseDevice->EnqueueMessage(message);
398fc2045eeSJérôme Duval 			}
399fc2045eeSJérôme Duval 		}
400fc2045eeSJérôme Duval 
40161d7deeeSJérôme Duval 	}
40261d7deeeSJérôme Duval 
40361d7deeeSJérôme Duval 	return 0;
40461d7deeeSJérôme Duval }
40561d7deeeSJérôme Duval 
40661d7deeeSJérôme Duval 
40733efb919SStefano Ceccherini // mouse_device
408c2fbfb71SJérôme Duval mouse_device::mouse_device(const char *driver_path)
40933efb919SStefano Ceccherini {
410c2fbfb71SJérôme Duval 	fd = -1;
41133efb919SStefano Ceccherini 	device_watcher = -1;
41233efb919SStefano Ceccherini 	active = false;
413c2fbfb71SJérôme Duval 	strcpy(path, driver_path);
41433efb919SStefano Ceccherini 	device_ref.name = get_short_name(path);
41533efb919SStefano Ceccherini 	device_ref.type = B_POINTING_DEVICE;
41633efb919SStefano Ceccherini 	device_ref.cookie = this;
41733efb919SStefano Ceccherini };
41833efb919SStefano Ceccherini 
41933efb919SStefano Ceccherini 
42033efb919SStefano Ceccherini mouse_device::~mouse_device()
42133efb919SStefano Ceccherini {
42233efb919SStefano Ceccherini 	free(device_ref.name);
42333efb919SStefano Ceccherini }
42433efb919SStefano Ceccherini 
42533efb919SStefano Ceccherini 
426c2fbfb71SJérôme Duval void
427c2fbfb71SJérôme Duval MouseInputDevice::RecursiveScan(const char *directory)
42833efb919SStefano Ceccherini {
429c2fbfb71SJérôme Duval 	CALLED();
430497d01f0SAxel Dörfler 
431c2fbfb71SJérôme Duval 	bool found_ps2 = false;
43233efb919SStefano Ceccherini 	BEntry entry;
43333efb919SStefano Ceccherini 	BDirectory dir(directory);
43433efb919SStefano Ceccherini 	while (dir.GetNextEntry(&entry) == B_OK) {
435c2fbfb71SJérôme Duval 		BPath path;
436c2fbfb71SJérôme Duval 		entry.GetPath(&path);
437c2fbfb71SJérôme Duval 
438c2fbfb71SJérôme Duval 		char name[B_FILE_NAME_LENGTH];
439c2fbfb71SJérôme Duval 		entry.GetName(name);
440c2fbfb71SJérôme Duval 		if (strcmp(name, "ps2") == 0)
441c2fbfb71SJérôme Duval 			found_ps2 = true;
442c2fbfb71SJérôme Duval 		if (strcmp(name,"serial") == 0 && found_ps2)
443c2fbfb71SJérôme Duval 			continue;
44433efb919SStefano Ceccherini 
44533efb919SStefano Ceccherini 		if (entry.IsDirectory())
446c2fbfb71SJérôme Duval 			RecursiveScan(path.Path());
447c2fbfb71SJérôme Duval 		else
448c2fbfb71SJérôme Duval 			AddDevice(path.Path());
44933efb919SStefano Ceccherini 	}
45033efb919SStefano Ceccherini }
45133efb919SStefano Ceccherini 
45233efb919SStefano Ceccherini 
45333efb919SStefano Ceccherini static char *
45433efb919SStefano Ceccherini get_short_name(const char *longName)
45533efb919SStefano Ceccherini {
45633efb919SStefano Ceccherini 	BString string(longName);
45733efb919SStefano Ceccherini 	BString name;
45833efb919SStefano Ceccherini 
45933efb919SStefano Ceccherini 	int32 slash = string.FindLast("/");
4607dcdcad2SJérôme Duval 	string.CopyInto(name, slash + 1, string.Length() - slash);
4617dcdcad2SJérôme Duval 	int32 index = atoi(name.String()) + 1;
46233efb919SStefano Ceccherini 
4637dcdcad2SJérôme Duval 	int32 previousSlash = string.FindLast("/", slash);
4647dcdcad2SJérôme Duval 	string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1);
465497d01f0SAxel Dörfler 
466497d01f0SAxel Dörfler 	if (name == "ps2")
467497d01f0SAxel Dörfler 		name = "PS/2";
468497d01f0SAxel Dörfler 	else
469497d01f0SAxel Dörfler 		name.Capitalize();
470497d01f0SAxel Dörfler 
4717dcdcad2SJérôme Duval 	name << " Mouse " << index;
47233efb919SStefano Ceccherini 
47333efb919SStefano Ceccherini 	return strdup(name.String());
47433efb919SStefano Ceccherini }
475