xref: /haiku/src/add-ons/input_server/devices/mouse/MouseInputDevice.cpp (revision 0dbc4bef4976e237dfc3ff3e3116582020e3d129)
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 /*****************************************************************************/
2761d7deeeSJérôme Duval #include "MouseInputDevice.h"
2861d7deeeSJérôme Duval 
2961d7deeeSJérôme Duval #include <stdlib.h>
3061d7deeeSJérôme Duval #include <unistd.h>
3161d7deeeSJérôme Duval 
323aa69c78SStefano Ceccherini //#define DEBUG 1
333aa69c78SStefano Ceccherini #if DEBUG
343aa69c78SStefano Ceccherini 	#define LOG(text) fputs(text, sLogFile)
353aa69c78SStefano Ceccherini #else
363aa69c78SStefano Ceccherini 	#define LOG(text)
373aa69c78SStefano Ceccherini #endif
383aa69c78SStefano Ceccherini 
393aa69c78SStefano Ceccherini FILE *MouseInputDevice::sLogFile = NULL;
40*0dbc4befSStefano Ceccherini bool MouseInputDevice::sQuit = false;
413aa69c78SStefano Ceccherini 
423aa69c78SStefano Ceccherini // TODO: These are "stolen" from the kb_mouse driver on bebits, which uses
433aa69c78SStefano Ceccherini // the same protocol as BeOS one. They're just here to test this add-on with
443aa69c78SStefano Ceccherini // the BeOS mouse driver.
4561d7deeeSJérôme Duval const static uint32 kGetMouseMovements = 10099;
4653d77642SJérôme Duval const static uint32 kGetMouseAccel = 10101;
4753d77642SJérôme Duval const static uint32 kSetMouseAccel = 10102;
4853d77642SJérôme Duval const static uint32 kSetMouseType = 10104;
4953d77642SJérôme Duval const static uint32 kSetMouseMap = 10106;
5053d77642SJérôme Duval const static uint32 kSetClickSpeed = 10108;
5161d7deeeSJérôme Duval 
5261d7deeeSJérôme Duval struct mouse_movement {
5361d7deeeSJérôme Duval   int32 ser_fd_index;
5461d7deeeSJérôme Duval   int32 buttons;
5561d7deeeSJérôme Duval   int32 xdelta;
5661d7deeeSJérôme Duval   int32 ydelta;
5761d7deeeSJérôme Duval   int32 click_count;
5861d7deeeSJérôme Duval   int32 mouse_mods;
5961d7deeeSJérôme Duval   int64 mouse_time;
6061d7deeeSJérôme Duval };
6161d7deeeSJérôme Duval 
6261d7deeeSJérôme Duval 
63*0dbc4befSStefano Ceccherini struct mouse_device {
64*0dbc4befSStefano Ceccherini 	int driver_fd;
65*0dbc4befSStefano Ceccherini 	thread_id device_watcher;
66*0dbc4befSStefano Ceccherini 	uint32 buttons_state;
67*0dbc4befSStefano Ceccherini };
68*0dbc4befSStefano Ceccherini 
69*0dbc4befSStefano Ceccherini 
7061d7deeeSJérôme Duval extern "C"
7161d7deeeSJérôme Duval BInputServerDevice *
7261d7deeeSJérôme Duval instantiate_input_device()
7361d7deeeSJérôme Duval {
7461d7deeeSJérôme Duval 	return new MouseInputDevice();
7561d7deeeSJérôme Duval }
7661d7deeeSJérôme Duval 
7761d7deeeSJérôme Duval 
7861d7deeeSJérôme Duval MouseInputDevice::MouseInputDevice()
7953d77642SJérôme Duval 	: 	fThread(-1),
80*0dbc4befSStefano Ceccherini 		sQuit(false)
8161d7deeeSJérôme Duval {
823aa69c78SStefano Ceccherini 	// TODO: Open "/dev/input/mouse/serial/0" as well, and what about USB mouses ?
8361d7deeeSJérôme Duval 	fFd = open("dev/input/mouse/ps2/0", O_RDWR);
8461d7deeeSJérôme Duval 	if (fFd >= 0)
8561d7deeeSJérôme Duval 		fThread = spawn_thread(DeviceWatcher, "mouse watcher thread",
86e361bf69SJérôme Duval 			B_FIRST_REAL_TIME_PRIORITY+4, this);
8761d7deeeSJérôme Duval 
883aa69c78SStefano Ceccherini #if DEBUG
89*0dbc4befSStefano Ceccherini 	if (sLogFile == NULL)
903aa69c78SStefano Ceccherini 		sLogFile = fopen("/var/log/mouse_device_log.log", "w");
913aa69c78SStefano Ceccherini #endif
9261d7deeeSJérôme Duval }
9361d7deeeSJérôme Duval 
9461d7deeeSJérôme Duval 
9561d7deeeSJérôme Duval MouseInputDevice::~MouseInputDevice()
9661d7deeeSJérôme Duval {
9761d7deeeSJérôme Duval 	if (fThread >= 0) {
9861d7deeeSJérôme Duval 		status_t dummy;
9961d7deeeSJérôme Duval 		wait_for_thread(fThread, &dummy);
10061d7deeeSJérôme Duval 	}
10161d7deeeSJérôme Duval 
10261d7deeeSJérôme Duval 	if (fFd >= 0)
10361d7deeeSJérôme Duval 		close(fFd);
10461d7deeeSJérôme Duval 
1053aa69c78SStefano Ceccherini #if DEBUG
1063aa69c78SStefano Ceccherini 	fclose(sLogFile);
1073aa69c78SStefano Ceccherini #endif
10861d7deeeSJérôme Duval }
10961d7deeeSJérôme Duval 
11061d7deeeSJérôme Duval 
11161d7deeeSJérôme Duval status_t
11253d77642SJérôme Duval MouseInputDevice::InitFromSettings(uint32 opcode)
11353d77642SJérôme Duval {
11453d77642SJérôme Duval 	// retrieve current values
11553d77642SJérôme Duval 
11653d77642SJérôme Duval 	if (get_mouse_map(&fSettings.map)!=B_OK)
11753d77642SJérôme Duval 		fprintf(stderr, "error when get_mouse_map\n");
11853d77642SJérôme Duval 	else
11953d77642SJérôme Duval 		ioctl(fFd, kSetMouseMap, &fSettings.map);
12053d77642SJérôme Duval 
12153d77642SJérôme Duval 	if (get_click_speed(&fSettings.click_speed)!=B_OK)
12253d77642SJérôme Duval 		fprintf(stderr, "error when get_click_speed\n");
12353d77642SJérôme Duval 	else
12453d77642SJérôme Duval 		ioctl(fFd, kSetClickSpeed, &fSettings.click_speed);
12553d77642SJérôme Duval 
12653d77642SJérôme Duval 	if (get_mouse_speed(&fSettings.accel.speed)!=B_OK)
12753d77642SJérôme Duval 		fprintf(stderr, "error when get_mouse_speed\n");
12853d77642SJérôme Duval 	else {
12953d77642SJérôme Duval 		if (get_mouse_acceleration(&fSettings.accel.accel_factor)!=B_OK)
13053d77642SJérôme Duval 			fprintf(stderr, "error when get_mouse_acceleration\n");
13153d77642SJérôme Duval 		else {
13253d77642SJérôme Duval 			mouse_accel accel;
13353d77642SJérôme Duval 			ioctl(fFd, kGetMouseAccel, &accel);
13453d77642SJérôme Duval 			accel.speed = fSettings.accel.speed;
13553d77642SJérôme Duval 			accel.accel_factor = fSettings.accel.accel_factor;
13653d77642SJérôme Duval 			ioctl(fFd, kSetMouseAccel, &fSettings.accel);
13753d77642SJérôme Duval 		}
13853d77642SJérôme Duval 	}
13953d77642SJérôme Duval 
14053d77642SJérôme Duval 	if (get_mouse_type(&fSettings.type)!=B_OK)
14153d77642SJérôme Duval 		fprintf(stderr, "error when get_mouse_type\n");
14253d77642SJérôme Duval 	else
14353d77642SJérôme Duval 		ioctl(fFd, kSetMouseType, &fSettings.type);
14453d77642SJérôme Duval 
14553d77642SJérôme Duval 	return B_OK;
14653d77642SJérôme Duval }
14753d77642SJérôme Duval 
14853d77642SJérôme Duval 
14953d77642SJérôme Duval status_t
15061d7deeeSJérôme Duval MouseInputDevice::InitCheck()
15161d7deeeSJérôme Duval {
15253d77642SJérôme Duval 	InitFromSettings();
15353d77642SJérôme Duval 
154145a357dSStefano Ceccherini 	input_device_ref **devices = NULL;
155145a357dSStefano Ceccherini 	devices = (input_device_ref **)malloc(sizeof(input_device_ref *) * 2);
156145a357dSStefano Ceccherini 	if (!devices)
157145a357dSStefano Ceccherini 		return B_NO_MEMORY;
158145a357dSStefano Ceccherini 
15961d7deeeSJérôme Duval 	input_device_ref mouse1 = { "Mouse 1", B_POINTING_DEVICE, (void *)this };
16061d7deeeSJérôme Duval 
161145a357dSStefano Ceccherini 	devices[0] = &mouse1;
162145a357dSStefano Ceccherini 	devices[1] = NULL;
16361d7deeeSJérôme Duval 
16461d7deeeSJérôme Duval 	if (fFd >= 0 && fThread >= 0) {
16561d7deeeSJérôme Duval 		RegisterDevices(devices);
16661d7deeeSJérôme Duval 		return BInputServerDevice::InitCheck();
16761d7deeeSJérôme Duval 	}
16861d7deeeSJérôme Duval 	return B_ERROR;
16961d7deeeSJérôme Duval }
17061d7deeeSJérôme Duval 
17161d7deeeSJérôme Duval 
17261d7deeeSJérôme Duval status_t
17361d7deeeSJérôme Duval MouseInputDevice::Start(const char *name, void *cookie)
17461d7deeeSJérôme Duval {
1753aa69c78SStefano Ceccherini 	char log[128];
1763aa69c78SStefano Ceccherini 	snprintf(log, 128, "Start(%s)\n", name);
1773aa69c78SStefano Ceccherini 
1783aa69c78SStefano Ceccherini 	LOG(log);
17961d7deeeSJérôme Duval 	resume_thread(fThread);
18061d7deeeSJérôme Duval 
18161d7deeeSJérôme Duval 	return B_OK;
18261d7deeeSJérôme Duval }
18361d7deeeSJérôme Duval 
18461d7deeeSJérôme Duval 
18561d7deeeSJérôme Duval status_t
1863aa69c78SStefano Ceccherini MouseInputDevice::Stop(const char *name, void *cookie)
18761d7deeeSJérôme Duval {
1883aa69c78SStefano Ceccherini 	char log[128];
1893aa69c78SStefano Ceccherini 	snprintf(log, 128, "Stop(%s)\n", name);
1903aa69c78SStefano Ceccherini 
1913aa69c78SStefano Ceccherini 	LOG(log);
19261d7deeeSJérôme Duval 
19361d7deeeSJérôme Duval 	suspend_thread(fThread);
19461d7deeeSJérôme Duval 
19561d7deeeSJérôme Duval 	return B_OK;
19661d7deeeSJérôme Duval }
19761d7deeeSJérôme Duval 
19861d7deeeSJérôme Duval 
19961d7deeeSJérôme Duval status_t
20061d7deeeSJérôme Duval MouseInputDevice::Control(const char *name, void *cookie,
20161d7deeeSJérôme Duval 						  uint32 command, BMessage *message)
20261d7deeeSJérôme Duval {
2033aa69c78SStefano Ceccherini 	char log[128];
2043aa69c78SStefano Ceccherini 	snprintf(log, 128, "Control(%s, code: %lu)\n", name, command);
2053aa69c78SStefano Ceccherini 
2063aa69c78SStefano Ceccherini 	LOG(log);
20753d77642SJérôme Duval 
20853d77642SJérôme Duval 	if (command == B_NODE_MONITOR)
20953d77642SJérôme Duval 		HandleMonitor(message);
21053d77642SJérôme Duval 	else if (command >= B_MOUSE_TYPE_CHANGED
21153d77642SJérôme Duval 		&& command <= B_MOUSE_ACCELERATION_CHANGED) {
21253d77642SJérôme Duval 		InitFromSettings(command);
21353d77642SJérôme Duval 	}
21453d77642SJérôme Duval 	return B_OK;
21553d77642SJérôme Duval }
21653d77642SJérôme Duval 
21753d77642SJérôme Duval 
21853d77642SJérôme Duval status_t
21953d77642SJérôme Duval MouseInputDevice::HandleMonitor(BMessage *message)
22053d77642SJérôme Duval {
22161d7deeeSJérôme Duval 	return B_OK;
22261d7deeeSJérôme Duval }
22361d7deeeSJérôme Duval 
22461d7deeeSJérôme Duval 
22561d7deeeSJérôme Duval int32
22661d7deeeSJérôme Duval MouseInputDevice::DeviceWatcher(void *arg)
22761d7deeeSJérôme Duval {
22861d7deeeSJérôme Duval 	MouseInputDevice *dev = (MouseInputDevice *)arg;
22961d7deeeSJérôme Duval 	mouse_movement movements;
23061d7deeeSJérôme Duval 	BMessage *message;
23161d7deeeSJérôme Duval 	char log[128];
232*0dbc4befSStefano Ceccherini 	while (!sQuit) {
233145a357dSStefano Ceccherini 		if (ioctl(dev->fFd, kGetMouseMovements, &movements) < B_OK)
234145a357dSStefano Ceccherini 			continue;
23561d7deeeSJérôme Duval 
236e361bf69SJérôme Duval 		uint32 buttons = dev->fButtons ^ movements.buttons;
23761d7deeeSJérôme Duval 
23861d7deeeSJérôme Duval 		snprintf(log, 128, "buttons: %ld, x: %ld, y: %ld\n",
23961d7deeeSJérôme Duval 				movements.buttons, movements.xdelta, movements.ydelta);
24061d7deeeSJérôme Duval 
2413aa69c78SStefano Ceccherini 		LOG(log);
2423aa69c78SStefano Ceccherini 
2433aa69c78SStefano Ceccherini 		// TODO: B_MOUSE_DOWN and B_MOUSE_UP messages don't seem
2443aa69c78SStefano Ceccherini 		// to reach the application,
2453aa69c78SStefano Ceccherini 		// for some reason. Check if they reach the input server.
2463aa69c78SStefano Ceccherini 		if (buttons != 0) {
2473aa69c78SStefano Ceccherini 			message = new BMessage;
248e361bf69SJérôme Duval 			if (buttons & movements.buttons > 0) {
2493aa69c78SStefano Ceccherini 				message->what = B_MOUSE_DOWN;
2503aa69c78SStefano Ceccherini 				LOG("B_MOUSE_DOWN\n");
2513aa69c78SStefano Ceccherini 
252e361bf69SJérôme Duval 			} else {
2533aa69c78SStefano Ceccherini 				message->what = B_MOUSE_UP;
2543aa69c78SStefano Ceccherini 				LOG("B_MOUSE_UP\n");
2553aa69c78SStefano Ceccherini 			}
2563aa69c78SStefano Ceccherini 
2573aa69c78SStefano Ceccherini 			message->AddInt64("when", movements.mouse_time);
258e361bf69SJérôme Duval 			message->AddInt32("buttons", movements.buttons);
2593aa69c78SStefano Ceccherini 			message->AddInt32("clicks", movements.click_count);
260e361bf69SJérôme Duval 			message->AddInt32("x", movements.xdelta);
261e361bf69SJérôme Duval 			message->AddInt32("y", movements.ydelta);
26261d7deeeSJérôme Duval 
26361d7deeeSJérôme Duval 			dev->EnqueueMessage(message);
2643aa69c78SStefano Ceccherini 
2653aa69c78SStefano Ceccherini 			dev->fButtons = movements.buttons;
2663aa69c78SStefano Ceccherini 
2673aa69c78SStefano Ceccherini 		}
2683aa69c78SStefano Ceccherini 
2693aa69c78SStefano Ceccherini 		if (movements.xdelta != 0 || movements.ydelta != 0) {
2703aa69c78SStefano Ceccherini 			message = new BMessage(B_MOUSE_MOVED);
2713aa69c78SStefano Ceccherini 			if (message) {
2723aa69c78SStefano Ceccherini 				message->AddInt64("when", movements.mouse_time);
2733aa69c78SStefano Ceccherini 				message->AddInt32("buttons", movements.buttons);
2743aa69c78SStefano Ceccherini 				message->AddInt32("x", movements.xdelta);
2753aa69c78SStefano Ceccherini 				message->AddInt32("y", movements.ydelta);
2763aa69c78SStefano Ceccherini 
2773aa69c78SStefano Ceccherini 				dev->EnqueueMessage(message);
2783aa69c78SStefano Ceccherini 			}
27961d7deeeSJérôme Duval 		}
28061d7deeeSJérôme Duval 	}
28161d7deeeSJérôme Duval 
28261d7deeeSJérôme Duval 	return 0;
28361d7deeeSJérôme Duval }
28461d7deeeSJérôme Duval 
28561d7deeeSJérôme Duval 
286