123b47e0bSJérôme Duval /*
2fdad31e6SMichael Lotz * Copyright 2004-2011, Haiku.
323b47e0bSJérôme Duval * Distributed under the terms of the MIT License.
423b47e0bSJérôme Duval *
523b47e0bSJérôme Duval * Authors:
6d246d9beSStefano Ceccherini * Stefano Ceccherini (stefano.ceccherini@gmail.com)
7d246d9beSStefano Ceccherini * Jérôme Duval
8d246d9beSStefano Ceccherini * Axel Dörfler, axeld@pinc-software.de
9167f43a2SStephan Aßmus * Clemens Zeidler, haiku@clemens-zeidler.de
10239fd643SStephan Aßmus * Stephan Aßmus, superstippi@gmx.de
1123b47e0bSJérôme Duval */
1233efb919SStefano Ceccherini
1333efb919SStefano Ceccherini
1461d7deeeSJérôme Duval #include "MouseInputDevice.h"
15b6a7b204SAxel Dörfler
16b6a7b204SAxel Dörfler #include <errno.h>
17b6a7b204SAxel Dörfler #include <new>
18b6a7b204SAxel Dörfler #include <stdio.h>
19b6a7b204SAxel Dörfler #include <stdlib.h>
20b6a7b204SAxel Dörfler #include <unistd.h>
2161d7deeeSJérôme Duval
225125eae2SStephan Aßmus #include <Autolock.h>
23c2fbfb71SJérôme Duval #include <Debug.h>
2433efb919SStefano Ceccherini #include <Directory.h>
2533efb919SStefano Ceccherini #include <Entry.h>
26167f43a2SStephan Aßmus #include <File.h>
27167f43a2SStephan Aßmus #include <FindDirectory.h>
2833efb919SStefano Ceccherini #include <NodeMonitor.h>
2933efb919SStefano Ceccherini #include <Path.h>
3033efb919SStefano Ceccherini #include <String.h>
3161604e48SAxel Dörfler #include <View.h>
3261604e48SAxel Dörfler
332c494653SAxel Dörfler #include <kb_mouse_settings.h>
342c494653SAxel Dörfler #include <keyboard_mouse_driver.h>
352c494653SAxel Dörfler #include <touchpad_settings.h>
3633efb919SStefano Ceccherini
375e596efeSAugustin Cavalier #include "movement_maker.h"
385e596efeSAugustin Cavalier
39b6a7b204SAxel Dörfler
40e01a0431SStephan Aßmus #undef TRACE
41b6a7b204SAxel Dörfler //#define TRACE_MOUSE_DEVICE
42b6a7b204SAxel Dörfler #ifdef TRACE_MOUSE_DEVICE
43e01a0431SStephan Aßmus
44e01a0431SStephan Aßmus class FunctionTracer {
45e01a0431SStephan Aßmus public:
FunctionTracer(const void * pointer,const char * className,const char * functionName,int32 & depth)46e01a0431SStephan Aßmus FunctionTracer(const void* pointer, const char* className,
47e01a0431SStephan Aßmus const char* functionName,
48e01a0431SStephan Aßmus int32& depth)
49e01a0431SStephan Aßmus : fFunctionName(),
50e01a0431SStephan Aßmus fPrepend(),
51e01a0431SStephan Aßmus fFunctionDepth(depth),
52e01a0431SStephan Aßmus fPointer(pointer)
53e01a0431SStephan Aßmus {
54e01a0431SStephan Aßmus fFunctionDepth++;
55e01a0431SStephan Aßmus fPrepend.Append(' ', fFunctionDepth * 2);
56e01a0431SStephan Aßmus fFunctionName << className << "::" << functionName << "()";
57e01a0431SStephan Aßmus
58e01a0431SStephan Aßmus debug_printf("%p -> %s%s {\n", fPointer, fPrepend.String(),
59e01a0431SStephan Aßmus fFunctionName.String());
60e01a0431SStephan Aßmus }
61e01a0431SStephan Aßmus
~FunctionTracer()62e01a0431SStephan Aßmus ~FunctionTracer()
63e01a0431SStephan Aßmus {
64e01a0431SStephan Aßmus debug_printf("%p -> %s}\n", fPointer, fPrepend.String());
65e01a0431SStephan Aßmus fFunctionDepth--;
66e01a0431SStephan Aßmus }
67e01a0431SStephan Aßmus
68e01a0431SStephan Aßmus private:
69e01a0431SStephan Aßmus BString fFunctionName;
70e01a0431SStephan Aßmus BString fPrepend;
71e01a0431SStephan Aßmus int32& fFunctionDepth;
72e01a0431SStephan Aßmus const void* fPointer;
73e01a0431SStephan Aßmus };
74e01a0431SStephan Aßmus
75e01a0431SStephan Aßmus
76e01a0431SStephan Aßmus static int32 sFunctionDepth = -1;
77e01a0431SStephan Aßmus # define MD_CALLED(x...) FunctionTracer _ft(this, "MouseDevice", \
78e01a0431SStephan Aßmus __FUNCTION__, sFunctionDepth)
79e01a0431SStephan Aßmus # define MID_CALLED(x...) FunctionTracer _ft(this, "MouseInputDevice", \
80e01a0431SStephan Aßmus __FUNCTION__, sFunctionDepth)
81e02ed691SRene Gollent # define TRACE(x...) do { BString _to; \
82e01a0431SStephan Aßmus _to.Append(' ', (sFunctionDepth + 1) * 2); \
83e01a0431SStephan Aßmus debug_printf("%p -> %s", this, _to.String()); \
84e02ed691SRene Gollent debug_printf(x); } while (0)
85e01a0431SStephan Aßmus # define LOG_EVENT(text...) do {} while (0)
865125eae2SStephan Aßmus # define LOG_ERR(text...) TRACE(text)
873aa69c78SStefano Ceccherini #else
88e01a0431SStephan Aßmus # define TRACE(x...) do {} while (0)
89e01a0431SStephan Aßmus # define MD_CALLED(x...) TRACE(x)
90e01a0431SStephan Aßmus # define MID_CALLED(x...) TRACE(x)
916e094221SStephan Aßmus # define LOG_ERR(x...) debug_printf(x)
926e094221SStephan Aßmus # define LOG_EVENT(x...) TRACE(x)
933aa69c78SStefano Ceccherini #endif
943aa69c78SStefano Ceccherini
95e01a0431SStephan Aßmus
9633efb919SStefano Ceccherini const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4;
9733efb919SStefano Ceccherini const static char* kMouseDevicesDirectory = "/dev/input/mouse";
98167f43a2SStephan Aßmus const static char* kTouchpadDevicesDirectory = "/dev/input/touchpad";
9933efb919SStefano Ceccherini
10033efb919SStefano Ceccherini
10161604e48SAxel Dörfler class MouseDevice {
10261604e48SAxel Dörfler public:
1035125eae2SStephan Aßmus MouseDevice(MouseInputDevice& target,
1045125eae2SStephan Aßmus const char* path);
10561604e48SAxel Dörfler ~MouseDevice();
10633efb919SStefano Ceccherini
10761604e48SAxel Dörfler status_t Start();
10861604e48SAxel Dörfler void Stop();
10961604e48SAxel Dörfler
11061604e48SAxel Dörfler status_t UpdateSettings();
111167f43a2SStephan Aßmus status_t UpdateTouchpadSettings(const BMessage* message);
11261604e48SAxel Dörfler
Path() const11361604e48SAxel Dörfler const char* Path() const { return fPath.String(); }
DeviceRef()11461604e48SAxel Dörfler input_device_ref* DeviceRef() { return &fDeviceRef; }
11561604e48SAxel Dörfler
11661604e48SAxel Dörfler private:
1175125eae2SStephan Aßmus char* _BuildShortName() const;
11861604e48SAxel Dörfler
1195125eae2SStephan Aßmus static status_t _ControlThreadEntry(void* arg);
1205125eae2SStephan Aßmus void _ControlThread();
1215125eae2SStephan Aßmus void _ControlThreadCleanup();
1225125eae2SStephan Aßmus void _UpdateSettings();
1235125eae2SStephan Aßmus
124167f43a2SStephan Aßmus status_t _GetTouchpadSettingsPath(BPath& path);
1255e596efeSAugustin Cavalier status_t _UpdateTouchpadSettings(BMessage* message);
126167f43a2SStephan Aßmus
1275125eae2SStephan Aßmus BMessage* _BuildMouseMessage(uint32 what,
1285125eae2SStephan Aßmus uint64 when, uint32 buttons,
12961604e48SAxel Dörfler int32 deltaX, int32 deltaY) const;
1305125eae2SStephan Aßmus void _ComputeAcceleration(
1315125eae2SStephan Aßmus const mouse_movement& movements,
1326e094221SStephan Aßmus int32& deltaX, int32& deltaY,
1336e094221SStephan Aßmus float& historyDeltaX,
1346e094221SStephan Aßmus float& historyDeltaY) const;
13561604e48SAxel Dörfler uint32 _RemapButtons(uint32 buttons) const;
13661604e48SAxel Dörfler
13761604e48SAxel Dörfler private:
138c5555ad3SStephan Aßmus MouseInputDevice& fTarget;
13961604e48SAxel Dörfler BString fPath;
14061604e48SAxel Dörfler int fDevice;
14161604e48SAxel Dörfler
14261604e48SAxel Dörfler input_device_ref fDeviceRef;
14361604e48SAxel Dörfler mouse_settings fSettings;
14461604e48SAxel Dörfler bool fDeviceRemapsButtons;
14561604e48SAxel Dörfler
14661604e48SAxel Dörfler thread_id fThread;
14761604e48SAxel Dörfler volatile bool fActive;
1485125eae2SStephan Aßmus volatile bool fUpdateSettings;
149167f43a2SStephan Aßmus
150167f43a2SStephan Aßmus bool fIsTouchpad;
1515e596efeSAugustin Cavalier TouchpadMovement fTouchpadMovementMaker;
152167f43a2SStephan Aßmus BMessage* fTouchpadSettingsMessage;
153167f43a2SStephan Aßmus BLocker fTouchpadSettingsLock;
1540dbc4befSStefano Ceccherini };
1550dbc4befSStefano Ceccherini
1560dbc4befSStefano Ceccherini
15761604e48SAxel Dörfler extern "C" BInputServerDevice*
instantiate_input_device()15861d7deeeSJérôme Duval instantiate_input_device()
15961d7deeeSJérôme Duval {
160d246d9beSStefano Ceccherini return new(std::nothrow) MouseInputDevice();
16161d7deeeSJérôme Duval }
16261d7deeeSJérôme Duval
16361d7deeeSJérôme Duval
16461604e48SAxel Dörfler // #pragma mark -
16561604e48SAxel Dörfler
16661604e48SAxel Dörfler
MouseDevice(MouseInputDevice & target,const char * driverPath)167c5555ad3SStephan Aßmus MouseDevice::MouseDevice(MouseInputDevice& target, const char* driverPath)
16861604e48SAxel Dörfler :
16961604e48SAxel Dörfler fTarget(target),
170c5555ad3SStephan Aßmus fPath(driverPath),
17161604e48SAxel Dörfler fDevice(-1),
172e01a0431SStephan Aßmus fDeviceRemapsButtons(false),
17361604e48SAxel Dörfler fThread(-1),
1745125eae2SStephan Aßmus fActive(false),
175167f43a2SStephan Aßmus fUpdateSettings(false),
176167f43a2SStephan Aßmus fIsTouchpad(false),
177167f43a2SStephan Aßmus fTouchpadSettingsMessage(NULL),
178167f43a2SStephan Aßmus fTouchpadSettingsLock("Touchpad settings lock")
17961d7deeeSJérôme Duval {
180e01a0431SStephan Aßmus MD_CALLED();
181e01a0431SStephan Aßmus
18261604e48SAxel Dörfler fDeviceRef.name = _BuildShortName();
18361604e48SAxel Dörfler fDeviceRef.type = B_POINTING_DEVICE;
18461604e48SAxel Dörfler fDeviceRef.cookie = this;
18561604e48SAxel Dörfler
18661604e48SAxel Dörfler #ifdef HAIKU_TARGET_PLATFORM_HAIKU
1875bbf7f1bSAdrien Destugues for (int i = 0; i < B_MAX_MOUSE_BUTTONS; i++)
1885bbf7f1bSAdrien Destugues fSettings.map.button[i] = B_MOUSE_BUTTON(i + 1);
1893aa69c78SStefano Ceccherini #endif
19061604e48SAxel Dörfler };
19161d7deeeSJérôme Duval
19261d7deeeSJérôme Duval
~MouseDevice()19361604e48SAxel Dörfler MouseDevice::~MouseDevice()
19461d7deeeSJérôme Duval {
195e01a0431SStephan Aßmus MD_CALLED();
196e01a0431SStephan Aßmus TRACE("delete\n");
197e01a0431SStephan Aßmus
19861604e48SAxel Dörfler if (fActive)
19961604e48SAxel Dörfler Stop();
20061d7deeeSJérôme Duval
20161604e48SAxel Dörfler free(fDeviceRef.name);
202167f43a2SStephan Aßmus delete fTouchpadSettingsMessage;
20361d7deeeSJérôme Duval }
20461d7deeeSJérôme Duval
20561d7deeeSJérôme Duval
20661d7deeeSJérôme Duval status_t
Start()20761604e48SAxel Dörfler MouseDevice::Start()
20853d77642SJérôme Duval {
209e01a0431SStephan Aßmus MD_CALLED();
210e01a0431SStephan Aßmus
21161604e48SAxel Dörfler fDevice = open(fPath.String(), O_RDWR);
2125125eae2SStephan Aßmus // let the control thread handle any error on opening the device
21333efb919SStefano Ceccherini
21433efb919SStefano Ceccherini char threadName[B_OS_NAME_LENGTH];
21561604e48SAxel Dörfler snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", fDeviceRef.name);
21633efb919SStefano Ceccherini
2175125eae2SStephan Aßmus fThread = spawn_thread(_ControlThreadEntry, threadName,
21861604e48SAxel Dörfler kMouseThreadPriority, (void*)this);
2194c0af4a8SStefano Ceccherini
22033efb919SStefano Ceccherini status_t status;
221fdad31e6SMichael Lotz if (fThread < 0)
22261604e48SAxel Dörfler status = fThread;
22361604e48SAxel Dörfler else {
22461604e48SAxel Dörfler fActive = true;
22561604e48SAxel Dörfler status = resume_thread(fThread);
22661604e48SAxel Dörfler }
22733efb919SStefano Ceccherini
22861604e48SAxel Dörfler if (status < B_OK) {
22961604e48SAxel Dörfler LOG_ERR("%s: can't spawn/resume watching thread: %s\n",
23061604e48SAxel Dörfler fDeviceRef.name, strerror(status));
231fdad31e6SMichael Lotz if (fDevice >= 0)
232167f43a2SStephan Aßmus close(fDevice);
23314a12accSFredrik Holmqvist
23461604e48SAxel Dörfler return status;
23561604e48SAxel Dörfler }
23661604e48SAxel Dörfler
2379195fe6eSStephan Aßmus return fDevice >= 0 ? B_OK : B_ERROR;
23861d7deeeSJérôme Duval }
23961d7deeeSJérôme Duval
24061d7deeeSJérôme Duval
241c2fbfb71SJérôme Duval void
Stop()24261604e48SAxel Dörfler MouseDevice::Stop()
24361604e48SAxel Dörfler {
244e01a0431SStephan Aßmus MD_CALLED();
2451ccc2f2dSJérôme Duval
24661604e48SAxel Dörfler fActive = false;
24761604e48SAxel Dörfler // this will stop the thread as soon as it reads the next packet
24861604e48SAxel Dörfler
249e01a0431SStephan Aßmus close(fDevice);
250e01a0431SStephan Aßmus fDevice = -1;
251e01a0431SStephan Aßmus
252fdad31e6SMichael Lotz if (fThread >= 0) {
25361604e48SAxel Dörfler // unblock the thread, which might wait on a semaphore.
25461604e48SAxel Dörfler suspend_thread(fThread);
25561604e48SAxel Dörfler resume_thread(fThread);
25661604e48SAxel Dörfler
25761604e48SAxel Dörfler status_t dummy;
25861604e48SAxel Dörfler wait_for_thread(fThread, &dummy);
25961604e48SAxel Dörfler }
26061604e48SAxel Dörfler }
26161604e48SAxel Dörfler
26261604e48SAxel Dörfler
26342b505fbSAxel Dörfler status_t
UpdateSettings()26442b505fbSAxel Dörfler MouseDevice::UpdateSettings()
26542b505fbSAxel Dörfler {
266e01a0431SStephan Aßmus MD_CALLED();
26742b505fbSAxel Dörfler
2685125eae2SStephan Aßmus if (fThread < 0)
2695125eae2SStephan Aßmus return B_ERROR;
27042b505fbSAxel Dörfler
271167f43a2SStephan Aßmus // trigger updating the settings in the control thread
2725125eae2SStephan Aßmus fUpdateSettings = true;
273167f43a2SStephan Aßmus
274167f43a2SStephan Aßmus return B_OK;
275167f43a2SStephan Aßmus }
276167f43a2SStephan Aßmus
277167f43a2SStephan Aßmus
278167f43a2SStephan Aßmus status_t
UpdateTouchpadSettings(const BMessage * message)279167f43a2SStephan Aßmus MouseDevice::UpdateTouchpadSettings(const BMessage* message)
280167f43a2SStephan Aßmus {
281167f43a2SStephan Aßmus if (!fIsTouchpad)
282167f43a2SStephan Aßmus return B_BAD_TYPE;
283167f43a2SStephan Aßmus if (fThread < 0)
284167f43a2SStephan Aßmus return B_ERROR;
285167f43a2SStephan Aßmus
286167f43a2SStephan Aßmus BAutolock _(fTouchpadSettingsLock);
287167f43a2SStephan Aßmus
288167f43a2SStephan Aßmus // trigger updating the settings in the control thread
289167f43a2SStephan Aßmus fUpdateSettings = true;
290167f43a2SStephan Aßmus
291167f43a2SStephan Aßmus delete fTouchpadSettingsMessage;
292167f43a2SStephan Aßmus fTouchpadSettingsMessage = new BMessage(*message);
293fdad31e6SMichael Lotz if (fTouchpadSettingsMessage == NULL)
294fdad31e6SMichael Lotz return B_NO_MEMORY;
29542b505fbSAxel Dörfler
29642b505fbSAxel Dörfler return B_OK;
2975125eae2SStephan Aßmus }
29842b505fbSAxel Dörfler
2995125eae2SStephan Aßmus
3005125eae2SStephan Aßmus char*
_BuildShortName() const3015125eae2SStephan Aßmus MouseDevice::_BuildShortName() const
3025125eae2SStephan Aßmus {
303ffd6c2f4SAdrien Destugues // TODO It would be simpler and better to use B_GET_DEVICE_NAME, but...
304ffd6c2f4SAdrien Destugues // - This is currently called before the device is open
305ffd6c2f4SAdrien Destugues // - We need to implement that in our input drivers first
3065125eae2SStephan Aßmus BString string(fPath);
307ffd6c2f4SAdrien Destugues BString deviceName;
3085125eae2SStephan Aßmus BString name;
3095125eae2SStephan Aßmus
3105125eae2SStephan Aßmus int32 slash = string.FindLast("/");
311ffd6c2f4SAdrien Destugues string.CopyInto(deviceName, slash + 1, string.Length() - slash);
312ffd6c2f4SAdrien Destugues // FIXME the device name may be more than just a number (for example
313ffd6c2f4SAdrien Destugues // ibm_trackpoint_0)
314ffd6c2f4SAdrien Destugues int32 index = atoi(deviceName.String()) + 1;
3155125eae2SStephan Aßmus
3165125eae2SStephan Aßmus int32 previousSlash = string.FindLast("/", slash);
3175125eae2SStephan Aßmus string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1);
3185125eae2SStephan Aßmus
3195125eae2SStephan Aßmus if (name == "ps2")
3205125eae2SStephan Aßmus name = "PS/2";
321155b8260SPhilippe Houdoin
322ffd6c2f4SAdrien Destugues if (name.Length() <= 4)
323155b8260SPhilippe Houdoin name.ToUpper();
3245125eae2SStephan Aßmus else
3255125eae2SStephan Aßmus name.Capitalize();
3265125eae2SStephan Aßmus
327f32bcfd5SAdrien Destugues // Check the whole string for "touchpad" because it's a different directory
328f32bcfd5SAdrien Destugues // FIXME use MS_IS_TOUCHPAD ioctl instead (or fIsTouchpad which caches its
329f32bcfd5SAdrien Destugues // result) but this can only be done after the control thread is running
330f32bcfd5SAdrien Destugues if (string.FindFirst("touchpad") >= 0) {
331167f43a2SStephan Aßmus name << " Touchpad ";
332ffd6c2f4SAdrien Destugues } else if (deviceName.FindFirst("trackpoint") >= 0) {
333ffd6c2f4SAdrien Destugues // That's always PS/2, so don't keep the bus name
334ffd6c2f4SAdrien Destugues name = "Trackpoint ";
335167f43a2SStephan Aßmus } else {
336ffd6c2f4SAdrien Destugues if (deviceName.FindFirst("intelli") >= 0)
337cc442411SStephan Aßmus name.Prepend("Extended ");
338cc442411SStephan Aßmus
339167f43a2SStephan Aßmus name << " Mouse ";
340167f43a2SStephan Aßmus }
341167f43a2SStephan Aßmus name << index;
3425125eae2SStephan Aßmus
3435125eae2SStephan Aßmus return strdup(name.String());
3445125eae2SStephan Aßmus }
3455125eae2SStephan Aßmus
3465125eae2SStephan Aßmus
3475125eae2SStephan Aßmus // #pragma mark - control thread
3485125eae2SStephan Aßmus
3495125eae2SStephan Aßmus
3505125eae2SStephan Aßmus status_t
_ControlThreadEntry(void * arg)3515125eae2SStephan Aßmus MouseDevice::_ControlThreadEntry(void* arg)
3525125eae2SStephan Aßmus {
3535125eae2SStephan Aßmus MouseDevice* device = (MouseDevice*)arg;
3545125eae2SStephan Aßmus device->_ControlThread();
3555125eae2SStephan Aßmus return B_OK;
35642b505fbSAxel Dörfler }
35742b505fbSAxel Dörfler
35842b505fbSAxel Dörfler
35961604e48SAxel Dörfler void
_ControlThread()3605125eae2SStephan Aßmus MouseDevice::_ControlThread()
36161604e48SAxel Dörfler {
362167f43a2SStephan Aßmus MD_CALLED();
363167f43a2SStephan Aßmus
3645125eae2SStephan Aßmus if (fDevice < 0) {
3655125eae2SStephan Aßmus _ControlThreadCleanup();
3665125eae2SStephan Aßmus // TOAST!
3675125eae2SStephan Aßmus return;
3685125eae2SStephan Aßmus }
3695125eae2SStephan Aßmus
370167f43a2SStephan Aßmus // touchpad settings
3715e596efeSAugustin Cavalier touchpad_specs touchpadSpecs;
3725e596efeSAugustin Cavalier if (ioctl(fDevice, MS_IS_TOUCHPAD, &touchpadSpecs, sizeof(touchpadSpecs)) == B_OK) {
373167f43a2SStephan Aßmus TRACE("is touchpad %s\n", fPath.String());
374167f43a2SStephan Aßmus fIsTouchpad = true;
375167f43a2SStephan Aßmus
3765e596efeSAugustin Cavalier touchpad_settings settings;
3775e596efeSAugustin Cavalier settings = kDefaultTouchpadSettings;
378167f43a2SStephan Aßmus
379167f43a2SStephan Aßmus BPath path;
380167f43a2SStephan Aßmus status_t status = _GetTouchpadSettingsPath(path);
381167f43a2SStephan Aßmus BFile settingsFile(path.Path(), B_READ_ONLY);
382167f43a2SStephan Aßmus if (status == B_OK && settingsFile.InitCheck() == B_OK) {
3835e596efeSAugustin Cavalier if (settingsFile.Read(&settings, sizeof(touchpad_settings))
384167f43a2SStephan Aßmus != sizeof(touchpad_settings)) {
385167f43a2SStephan Aßmus TRACE("failed to load settings\n");
386167f43a2SStephan Aßmus }
387167f43a2SStephan Aßmus }
3885e596efeSAugustin Cavalier
3895e596efeSAugustin Cavalier fTouchpadMovementMaker.SetSpecs(touchpadSpecs);
3905e596efeSAugustin Cavalier fTouchpadMovementMaker.SetSettings(settings);
391167f43a2SStephan Aßmus }
392167f43a2SStephan Aßmus
3935125eae2SStephan Aßmus _UpdateSettings();
3945125eae2SStephan Aßmus
39561604e48SAxel Dörfler uint32 lastButtons = 0;
3966e094221SStephan Aßmus float historyDeltaX = 0.0;
3976e094221SStephan Aßmus float historyDeltaY = 0.0;
39861604e48SAxel Dörfler
3997d1d7033SStephan Aßmus static const bigtime_t kTransferDelay = 1000000 / 125;
4007d1d7033SStephan Aßmus // 125 transfers per second should be more than enough
4015994d47aSStephan Aßmus #define USE_REGULAR_INTERVAL 1
4027d1d7033SStephan Aßmus #if USE_REGULAR_INTERVAL
4037d1d7033SStephan Aßmus bigtime_t nextTransferTime = system_time() + kTransferDelay;
4047d1d7033SStephan Aßmus #endif
4057d1d7033SStephan Aßmus
4065e596efeSAugustin Cavalier // touchpads only
4075e596efeSAugustin Cavalier touchpad_movement lastTouchpadMovement;
4085e596efeSAugustin Cavalier bigtime_t touchpadEventTimeout = B_INFINITE_TIMEOUT;
4095e596efeSAugustin Cavalier
41061604e48SAxel Dörfler while (fActive) {
41161604e48SAxel Dörfler mouse_movement movements;
4127d1d7033SStephan Aßmus
4137d1d7033SStephan Aßmus #if USE_REGULAR_INTERVAL
4147d1d7033SStephan Aßmus snooze_until(nextTransferTime, B_SYSTEM_TIMEBASE);
4157d1d7033SStephan Aßmus nextTransferTime += kTransferDelay;
4167d1d7033SStephan Aßmus #endif
4177d1d7033SStephan Aßmus
4185e596efeSAugustin Cavalier if (!fIsTouchpad) {
419308e87fcSRene Gollent if (ioctl(fDevice, MS_READ, &movements, sizeof(movements)) != B_OK) {
420308e87fcSRene Gollent LOG_ERR("Mouse device exiting, %s\n", strerror(errno));
4215125eae2SStephan Aßmus _ControlThreadCleanup();
422c5555ad3SStephan Aßmus // TOAST!
42361604e48SAxel Dörfler return;
424c5555ad3SStephan Aßmus }
4255e596efeSAugustin Cavalier } else {
4265e596efeSAugustin Cavalier touchpad_read read;
4275e596efeSAugustin Cavalier read.timeout = touchpadEventTimeout;
4285e596efeSAugustin Cavalier
4295e596efeSAugustin Cavalier status_t status = ioctl(fDevice, MS_READ_TOUCHPAD, &read, sizeof(read));
430ba0a86caSAugustin Cavalier if (status < 0)
431ba0a86caSAugustin Cavalier status = errno;
4325e596efeSAugustin Cavalier if (status != B_OK && status != B_TIMED_OUT) {
433ba0a86caSAugustin Cavalier LOG_ERR("Mouse (touchpad) device exiting, %s\n", strerror(errno));
4345e596efeSAugustin Cavalier _ControlThreadCleanup();
4355e596efeSAugustin Cavalier // TOAST!
4365e596efeSAugustin Cavalier return;
437ba0a86caSAugustin Cavalier } else if (status == B_TIMED_OUT) {
4385e596efeSAugustin Cavalier read.event = MS_READ_TOUCHPAD;
4395e596efeSAugustin Cavalier read.u.touchpad = lastTouchpadMovement;
4405e596efeSAugustin Cavalier }
4415e596efeSAugustin Cavalier
4425e596efeSAugustin Cavalier if (read.event == MS_READ_TOUCHPAD) {
4435e596efeSAugustin Cavalier lastTouchpadMovement = read.u.touchpad;
4445e596efeSAugustin Cavalier status = fTouchpadMovementMaker.EventToMovement(&read.u.touchpad,
4455e596efeSAugustin Cavalier &movements, touchpadEventTimeout);
4465e596efeSAugustin Cavalier } else if (read.event == MS_READ) {
4475e596efeSAugustin Cavalier movements = read.u.mouse;
4485e596efeSAugustin Cavalier touchpadEventTimeout = -1;
4495e596efeSAugustin Cavalier }
4505e596efeSAugustin Cavalier
4515e596efeSAugustin Cavalier if (status != B_OK)
4525e596efeSAugustin Cavalier continue;
4535e596efeSAugustin Cavalier }
45461604e48SAxel Dörfler
4555125eae2SStephan Aßmus // take care of updating the settings first, if necessary
4565125eae2SStephan Aßmus if (fUpdateSettings) {
4575125eae2SStephan Aßmus fUpdateSettings = false;
458167f43a2SStephan Aßmus if (fIsTouchpad) {
459167f43a2SStephan Aßmus BAutolock _(fTouchpadSettingsLock);
4603bf47305SAxel Dörfler if (fTouchpadSettingsMessage != NULL) {
4615e596efeSAugustin Cavalier _UpdateTouchpadSettings(fTouchpadSettingsMessage);
462167f43a2SStephan Aßmus delete fTouchpadSettingsMessage;
463167f43a2SStephan Aßmus fTouchpadSettingsMessage = NULL;
464167f43a2SStephan Aßmus } else
465167f43a2SStephan Aßmus _UpdateSettings();
466167f43a2SStephan Aßmus } else
467167f43a2SStephan Aßmus _UpdateSettings();
4685125eae2SStephan Aßmus }
4695125eae2SStephan Aßmus
47061604e48SAxel Dörfler uint32 buttons = lastButtons ^ movements.buttons;
47161604e48SAxel Dörfler
47261604e48SAxel Dörfler uint32 remappedButtons = _RemapButtons(movements.buttons);
47361604e48SAxel Dörfler int32 deltaX, deltaY;
4746e094221SStephan Aßmus _ComputeAcceleration(movements, deltaX, deltaY, historyDeltaX,
4756e094221SStephan Aßmus historyDeltaY);
47661604e48SAxel Dörfler
4776e094221SStephan Aßmus LOG_EVENT("%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld, "
4786e094221SStephan Aßmus "wheel_x:%ld, wheel_y:%ld\n",
4796e094221SStephan Aßmus fDeviceRef.name, movements.buttons,
4806e094221SStephan Aßmus movements.xdelta, movements.ydelta, movements.clicks,
4816e094221SStephan Aßmus movements.wheel_xdelta, movements.wheel_ydelta);
4826e094221SStephan Aßmus LOG_EVENT("%s: x: %ld, y: %ld (%.4f, %.4f)\n", fDeviceRef.name,
4836e094221SStephan Aßmus deltaX, deltaY, historyDeltaX, historyDeltaY);
48461604e48SAxel Dörfler
48561604e48SAxel Dörfler // Send single messages for each event
48661604e48SAxel Dörfler
48761604e48SAxel Dörfler if (buttons != 0) {
48861604e48SAxel Dörfler bool pressedButton = (buttons & movements.buttons) > 0;
48961604e48SAxel Dörfler BMessage* message = _BuildMouseMessage(
49061604e48SAxel Dörfler pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP,
49161604e48SAxel Dörfler movements.timestamp, remappedButtons, deltaX, deltaY);
49261604e48SAxel Dörfler if (message != NULL) {
49361604e48SAxel Dörfler if (pressedButton) {
49461604e48SAxel Dörfler message->AddInt32("clicks", movements.clicks);
495e01a0431SStephan Aßmus LOG_EVENT("B_MOUSE_DOWN\n");
49661604e48SAxel Dörfler } else
497e01a0431SStephan Aßmus LOG_EVENT("B_MOUSE_UP\n");
49861604e48SAxel Dörfler
49961604e48SAxel Dörfler fTarget.EnqueueMessage(message);
50061604e48SAxel Dörfler lastButtons = movements.buttons;
50161604e48SAxel Dörfler }
50261604e48SAxel Dörfler }
50361604e48SAxel Dörfler
50445f11ce8SStephan Aßmus if (movements.xdelta != 0 || movements.ydelta != 0) {
50545f11ce8SStephan Aßmus BMessage* message = _BuildMouseMessage(B_MOUSE_MOVED,
50645f11ce8SStephan Aßmus movements.timestamp, remappedButtons, deltaX, deltaY);
50745f11ce8SStephan Aßmus if (message != NULL)
50845f11ce8SStephan Aßmus fTarget.EnqueueMessage(message);
50945f11ce8SStephan Aßmus }
51045f11ce8SStephan Aßmus
511fdad31e6SMichael Lotz if (movements.wheel_ydelta != 0 || movements.wheel_xdelta != 0) {
512c5555ad3SStephan Aßmus BMessage* message = new BMessage(B_MOUSE_WHEEL_CHANGED);
51361604e48SAxel Dörfler if (message == NULL)
51461604e48SAxel Dörfler continue;
51561604e48SAxel Dörfler
51661604e48SAxel Dörfler if (message->AddInt64("when", movements.timestamp) == B_OK
5173bf47305SAxel Dörfler && message->AddFloat("be:wheel_delta_x",
5183bf47305SAxel Dörfler movements.wheel_xdelta) == B_OK
5193bf47305SAxel Dörfler && message->AddFloat("be:wheel_delta_y",
520*b08fdcdeSGustaf Alhäll movements.wheel_ydelta) == B_OK
521*b08fdcdeSGustaf Alhäll && message->AddInt32("be:device_subtype",
522*b08fdcdeSGustaf Alhäll fIsTouchpad
523*b08fdcdeSGustaf Alhäll ? B_TOUCHPAD_DEVICE_SUBTYPE
524*b08fdcdeSGustaf Alhäll : B_MOUSE_DEVICE_SUBTYPE) == B_OK)
52561604e48SAxel Dörfler fTarget.EnqueueMessage(message);
52661604e48SAxel Dörfler else
52761604e48SAxel Dörfler delete message;
52861604e48SAxel Dörfler }
5297d1d7033SStephan Aßmus
5307d1d7033SStephan Aßmus #if !USE_REGULAR_INTERVAL
5317d1d7033SStephan Aßmus snooze(kTransferDelay);
5327d1d7033SStephan Aßmus #endif
53361604e48SAxel Dörfler }
53461604e48SAxel Dörfler }
53561604e48SAxel Dörfler
53661604e48SAxel Dörfler
5375125eae2SStephan Aßmus void
_ControlThreadCleanup()5385125eae2SStephan Aßmus MouseDevice::_ControlThreadCleanup()
53961604e48SAxel Dörfler {
5405125eae2SStephan Aßmus // NOTE: Only executed when the control thread detected an error
5415125eae2SStephan Aßmus // and from within the control thread!
5425125eae2SStephan Aßmus
5435125eae2SStephan Aßmus if (fActive) {
5445125eae2SStephan Aßmus fThread = -1;
5455125eae2SStephan Aßmus fTarget._RemoveDevice(fPath.String());
5465125eae2SStephan Aßmus } else {
5475125eae2SStephan Aßmus // In case active is already false, another thread
5485125eae2SStephan Aßmus // waits for this thread to quit, and may already hold
549fdad31e6SMichael Lotz // locks that _RemoveDevice() wants to acquire. In other
5505125eae2SStephan Aßmus // words, the device is already being removed, so we simply
5515125eae2SStephan Aßmus // quit here.
5525125eae2SStephan Aßmus }
5535125eae2SStephan Aßmus }
5545125eae2SStephan Aßmus
5555125eae2SStephan Aßmus
5565125eae2SStephan Aßmus void
_UpdateSettings()5575125eae2SStephan Aßmus MouseDevice::_UpdateSettings()
5585125eae2SStephan Aßmus {
5595125eae2SStephan Aßmus MD_CALLED();
5605125eae2SStephan Aßmus // retrieve current values
5615125eae2SStephan Aßmus
562caed67a8SMáximo Castañeda if (get_mouse_map(fDeviceRef.name, &fSettings.map) != B_OK)
5635125eae2SStephan Aßmus LOG_ERR("error when get_mouse_map\n");
564caed67a8SMáximo Castañeda else
565caed67a8SMáximo Castañeda fDeviceRemapsButtons = ioctl(fDevice, MS_SET_MAP, &fSettings.map) == B_OK;
5665125eae2SStephan Aßmus
567caed67a8SMáximo Castañeda if (get_click_speed(fDeviceRef.name, &fSettings.click_speed) == B_OK) {
5685e596efeSAugustin Cavalier if (fIsTouchpad)
5695e596efeSAugustin Cavalier fTouchpadMovementMaker.click_speed = fSettings.click_speed;
5705125eae2SStephan Aßmus ioctl(fDevice, MS_SET_CLICKSPEED, &fSettings.click_speed);
5715e596efeSAugustin Cavalier } else
5725e596efeSAugustin Cavalier LOG_ERR("error when get_click_speed\n");
5735125eae2SStephan Aßmus
57468d1b97eSAugustin Cavalier if (get_mouse_speed(fDeviceRef.name, &fSettings.accel.speed) != B_OK)
5755125eae2SStephan Aßmus LOG_ERR("error when get_mouse_speed\n");
5765125eae2SStephan Aßmus else {
57768d1b97eSAugustin Cavalier if (get_mouse_acceleration(fDeviceRef.name, &fSettings.accel.accel_factor) != B_OK)
5785125eae2SStephan Aßmus LOG_ERR("error when get_mouse_acceleration\n");
5795125eae2SStephan Aßmus else {
5805125eae2SStephan Aßmus mouse_accel accel;
5815125eae2SStephan Aßmus ioctl(fDevice, MS_GET_ACCEL, &accel);
5825125eae2SStephan Aßmus accel.speed = fSettings.accel.speed;
5835125eae2SStephan Aßmus accel.accel_factor = fSettings.accel.accel_factor;
5845125eae2SStephan Aßmus ioctl(fDevice, MS_SET_ACCEL, &fSettings.accel);
5855125eae2SStephan Aßmus }
5865125eae2SStephan Aßmus }
5875125eae2SStephan Aßmus
58868d1b97eSAugustin Cavalier if (get_mouse_type(fDeviceRef.name, &fSettings.type) != B_OK)
5895125eae2SStephan Aßmus LOG_ERR("error when get_mouse_type\n");
5905125eae2SStephan Aßmus else
5915125eae2SStephan Aßmus ioctl(fDevice, MS_SET_TYPE, &fSettings.type);
59261604e48SAxel Dörfler }
59361604e48SAxel Dörfler
59461604e48SAxel Dörfler
595167f43a2SStephan Aßmus status_t
_GetTouchpadSettingsPath(BPath & path)596167f43a2SStephan Aßmus MouseDevice::_GetTouchpadSettingsPath(BPath& path)
597167f43a2SStephan Aßmus {
598167f43a2SStephan Aßmus status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
599167f43a2SStephan Aßmus if (status < B_OK)
600167f43a2SStephan Aßmus return status;
601167f43a2SStephan Aßmus return path.Append(TOUCHPAD_SETTINGS_FILE);
602167f43a2SStephan Aßmus }
603167f43a2SStephan Aßmus
604167f43a2SStephan Aßmus
605167f43a2SStephan Aßmus status_t
_UpdateTouchpadSettings(BMessage * message)6065e596efeSAugustin Cavalier MouseDevice::_UpdateTouchpadSettings(BMessage* message)
607167f43a2SStephan Aßmus {
6085e596efeSAugustin Cavalier touchpad_settings settings;
6095e596efeSAugustin Cavalier message->FindBool("scroll_twofinger", &settings.scroll_twofinger);
610fc548b41SAxel Dörfler message->FindBool("scroll_twofinger_horizontal",
6115e596efeSAugustin Cavalier &settings.scroll_twofinger_horizontal);
612167f43a2SStephan Aßmus message->FindFloat("scroll_rightrange",
6135e596efeSAugustin Cavalier &settings.scroll_rightrange);
614167f43a2SStephan Aßmus message->FindFloat("scroll_bottomrange",
6155e596efeSAugustin Cavalier &settings.scroll_bottomrange);
6163bf47305SAxel Dörfler
617167f43a2SStephan Aßmus message->FindInt16("scroll_xstepsize",
6185e596efeSAugustin Cavalier (int16*)&settings.scroll_xstepsize);
619167f43a2SStephan Aßmus message->FindInt16("scroll_ystepsize",
6205e596efeSAugustin Cavalier (int16*)&settings.scroll_ystepsize);
621167f43a2SStephan Aßmus message->FindInt8("scroll_acceleration",
6225e596efeSAugustin Cavalier (int8*)&settings.scroll_acceleration);
623167f43a2SStephan Aßmus message->FindInt8("tapgesture_sensibility",
6245e596efeSAugustin Cavalier (int8*)&settings.tapgesture_sensibility);
6255e596efeSAugustin Cavalier
6265e596efeSAugustin Cavalier if (fIsTouchpad)
6275e596efeSAugustin Cavalier fTouchpadMovementMaker.SetSettings(settings);
628167f43a2SStephan Aßmus
629167f43a2SStephan Aßmus return B_OK;
630167f43a2SStephan Aßmus }
631167f43a2SStephan Aßmus
632167f43a2SStephan Aßmus
63361604e48SAxel Dörfler BMessage*
_BuildMouseMessage(uint32 what,uint64 when,uint32 buttons,int32 deltaX,int32 deltaY) const63461604e48SAxel Dörfler MouseDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons,
63561604e48SAxel Dörfler int32 deltaX, int32 deltaY) const
63661604e48SAxel Dörfler {
63761604e48SAxel Dörfler BMessage* message = new BMessage(what);
63861604e48SAxel Dörfler if (message == NULL)
63961604e48SAxel Dörfler return NULL;
64061604e48SAxel Dörfler
64161604e48SAxel Dörfler if (message->AddInt64("when", when) < B_OK
64261604e48SAxel Dörfler || message->AddInt32("buttons", buttons) < B_OK
64361604e48SAxel Dörfler || message->AddInt32("x", deltaX) < B_OK
644*b08fdcdeSGustaf Alhäll || message->AddInt32("y", deltaY) < B_OK
645*b08fdcdeSGustaf Alhäll || message->AddInt32("be:device_subtype",
646*b08fdcdeSGustaf Alhäll fIsTouchpad ? B_TOUCHPAD_DEVICE_SUBTYPE : B_MOUSE_DEVICE_SUBTYPE) < B_OK) {
64761604e48SAxel Dörfler delete message;
64861604e48SAxel Dörfler return NULL;
64961604e48SAxel Dörfler }
65061604e48SAxel Dörfler
65161604e48SAxel Dörfler return message;
65261604e48SAxel Dörfler }
65361604e48SAxel Dörfler
65461604e48SAxel Dörfler
65561604e48SAxel Dörfler void
_ComputeAcceleration(const mouse_movement & movements,int32 & _deltaX,int32 & _deltaY,float & historyDeltaX,float & historyDeltaY) const65661604e48SAxel Dörfler MouseDevice::_ComputeAcceleration(const mouse_movement& movements,
6576e094221SStephan Aßmus int32& _deltaX, int32& _deltaY, float& historyDeltaX,
6586e094221SStephan Aßmus float& historyDeltaY) const
65961604e48SAxel Dörfler {
66042b505fbSAxel Dörfler // basic mouse speed
6616e094221SStephan Aßmus float deltaX = (float)movements.xdelta * fSettings.accel.speed / 65536.0
6626e094221SStephan Aßmus + historyDeltaX;
6636e094221SStephan Aßmus float deltaY = (float)movements.ydelta * fSettings.accel.speed / 65536.0
6646e094221SStephan Aßmus + historyDeltaY;
66542b505fbSAxel Dörfler
66642b505fbSAxel Dörfler // acceleration
66742b505fbSAxel Dörfler double acceleration = 1;
66842b505fbSAxel Dörfler if (fSettings.accel.accel_factor) {
669fafab827SAxel Dörfler acceleration = 1 + sqrt(deltaX * deltaX + deltaY * deltaY)
67074ef1621SAxel Dörfler * fSettings.accel.accel_factor / 524288.0;
67142b505fbSAxel Dörfler }
67242b505fbSAxel Dörfler
6736e094221SStephan Aßmus deltaX *= acceleration;
6746e094221SStephan Aßmus deltaY *= acceleration;
67542b505fbSAxel Dörfler
6766e094221SStephan Aßmus if (deltaX >= 0)
6776e094221SStephan Aßmus _deltaX = (int32)floorf(deltaX);
678fafab827SAxel Dörfler else
6796e094221SStephan Aßmus _deltaX = (int32)ceilf(deltaX);
6806e094221SStephan Aßmus
6816e094221SStephan Aßmus if (deltaY >= 0)
6826e094221SStephan Aßmus _deltaY = (int32)floorf(deltaY);
6836e094221SStephan Aßmus else
6846e094221SStephan Aßmus _deltaY = (int32)ceilf(deltaY);
6856e094221SStephan Aßmus
6866e094221SStephan Aßmus historyDeltaX = deltaX - _deltaX;
6876e094221SStephan Aßmus historyDeltaY = deltaY - _deltaY;
68861604e48SAxel Dörfler }
68961604e48SAxel Dörfler
69033efb919SStefano Ceccherini
69123b47e0bSJérôme Duval uint32
_RemapButtons(uint32 buttons) const69261604e48SAxel Dörfler MouseDevice::_RemapButtons(uint32 buttons) const
69323b47e0bSJérôme Duval {
69461604e48SAxel Dörfler if (fDeviceRemapsButtons)
69523b47e0bSJérôme Duval return buttons;
69623b47e0bSJérôme Duval
69761604e48SAxel Dörfler uint32 newButtons = 0;
69823b47e0bSJérôme Duval for (int32 i = 0; buttons; i++) {
69923b47e0bSJérôme Duval if (buttons & 0x1) {
70021631085SStephan Aßmus #if defined(HAIKU_TARGET_PLATFORM_HAIKU) || defined(HAIKU_TARGET_PLATFORM_DANO)
70161604e48SAxel Dörfler newButtons |= fSettings.map.button[i];
70223b47e0bSJérôme Duval #else
70323b47e0bSJérôme Duval if (i == 0)
70461604e48SAxel Dörfler newButtons |= fSettings.map.left;
70523b47e0bSJérôme Duval if (i == 1)
70661604e48SAxel Dörfler newButtons |= fSettings.map.right;
70723b47e0bSJérôme Duval if (i == 2)
70861604e48SAxel Dörfler newButtons |= fSettings.map.middle;
70923b47e0bSJérôme Duval #endif
71023b47e0bSJérôme Duval }
71123b47e0bSJérôme Duval buttons >>= 1;
71223b47e0bSJérôme Duval }
71323b47e0bSJérôme Duval
71461604e48SAxel Dörfler return newButtons;
71523b47e0bSJérôme Duval }
71623b47e0bSJérôme Duval
71723b47e0bSJérôme Duval
71861604e48SAxel Dörfler // #pragma mark -
71961604e48SAxel Dörfler
72061604e48SAxel Dörfler
MouseInputDevice()72161604e48SAxel Dörfler MouseInputDevice::MouseInputDevice()
722b6a7b204SAxel Dörfler :
7235125eae2SStephan Aßmus fDevices(2, true),
7245125eae2SStephan Aßmus fDeviceListLock("MouseInputDevice list")
72561604e48SAxel Dörfler {
726e01a0431SStephan Aßmus MID_CALLED();
72761604e48SAxel Dörfler
728c5555ad3SStephan Aßmus StartMonitoringDevice(kMouseDevicesDirectory);
729167f43a2SStephan Aßmus StartMonitoringDevice(kTouchpadDevicesDirectory);
7309dd2d40eSStephan Aßmus _RecursiveScan(kMouseDevicesDirectory);
731167f43a2SStephan Aßmus _RecursiveScan(kTouchpadDevicesDirectory);
73261604e48SAxel Dörfler }
73361604e48SAxel Dörfler
73461604e48SAxel Dörfler
~MouseInputDevice()73561604e48SAxel Dörfler MouseInputDevice::~MouseInputDevice()
73661604e48SAxel Dörfler {
737e01a0431SStephan Aßmus MID_CALLED();
738e01a0431SStephan Aßmus
739167f43a2SStephan Aßmus StopMonitoringDevice(kTouchpadDevicesDirectory);
740b6a7b204SAxel Dörfler StopMonitoringDevice(kMouseDevicesDirectory);
741e01a0431SStephan Aßmus fDevices.MakeEmpty();
74261604e48SAxel Dörfler }
74361604e48SAxel Dörfler
74461604e48SAxel Dörfler
74561604e48SAxel Dörfler status_t
InitCheck()74661604e48SAxel Dörfler MouseInputDevice::InitCheck()
74761604e48SAxel Dörfler {
748e01a0431SStephan Aßmus MID_CALLED();
749e01a0431SStephan Aßmus
750d246d9beSStefano Ceccherini return BInputServerDevice::InitCheck();
75161604e48SAxel Dörfler }
75261604e48SAxel Dörfler
75361604e48SAxel Dörfler
75461604e48SAxel Dörfler status_t
Start(const char * name,void * cookie)75561604e48SAxel Dörfler MouseInputDevice::Start(const char* name, void* cookie)
75661604e48SAxel Dörfler {
757e01a0431SStephan Aßmus MID_CALLED();
758e01a0431SStephan Aßmus
75961604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie;
76061604e48SAxel Dörfler
76161604e48SAxel Dörfler return device->Start();
76261604e48SAxel Dörfler }
76361604e48SAxel Dörfler
76461604e48SAxel Dörfler
76561604e48SAxel Dörfler status_t
Stop(const char * name,void * cookie)76661604e48SAxel Dörfler MouseInputDevice::Stop(const char* name, void* cookie)
76761604e48SAxel Dörfler {
768e01a0431SStephan Aßmus TRACE("%s(%s)\n", __PRETTY_FUNCTION__, name);
76961604e48SAxel Dörfler
770e01a0431SStephan Aßmus MouseDevice* device = (MouseDevice*)cookie;
77161604e48SAxel Dörfler device->Stop();
772e01a0431SStephan Aßmus
77361604e48SAxel Dörfler return B_OK;
77461604e48SAxel Dörfler }
77561604e48SAxel Dörfler
77661604e48SAxel Dörfler
77761604e48SAxel Dörfler status_t
Control(const char * name,void * cookie,uint32 command,BMessage * message)77861604e48SAxel Dörfler MouseInputDevice::Control(const char* name, void* cookie,
77961604e48SAxel Dörfler uint32 command, BMessage* message)
78061604e48SAxel Dörfler {
781e01a0431SStephan Aßmus TRACE("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command);
782e01a0431SStephan Aßmus
78361604e48SAxel Dörfler MouseDevice* device = (MouseDevice*)cookie;
78461604e48SAxel Dörfler
78561604e48SAxel Dörfler if (command == B_NODE_MONITOR)
78661604e48SAxel Dörfler return _HandleMonitor(message);
78761604e48SAxel Dörfler
7885e596efeSAugustin Cavalier if (command == B_SET_TOUCHPAD_SETTINGS)
789167f43a2SStephan Aßmus return device->UpdateTouchpadSettings(message);
790167f43a2SStephan Aßmus
79161604e48SAxel Dörfler if (command >= B_MOUSE_TYPE_CHANGED
79261604e48SAxel Dörfler && command <= B_MOUSE_ACCELERATION_CHANGED)
79361604e48SAxel Dörfler return device->UpdateSettings();
79461604e48SAxel Dörfler
79561604e48SAxel Dörfler return B_BAD_VALUE;
79661604e48SAxel Dörfler }
79761604e48SAxel Dörfler
79861604e48SAxel Dörfler
79961604e48SAxel Dörfler status_t
_HandleMonitor(BMessage * message)80061604e48SAxel Dörfler MouseInputDevice::_HandleMonitor(BMessage* message)
80161604e48SAxel Dörfler {
802e01a0431SStephan Aßmus MID_CALLED();
80361604e48SAxel Dörfler
804b6a7b204SAxel Dörfler const char* path;
80561604e48SAxel Dörfler int32 opcode;
806b6a7b204SAxel Dörfler if (message->FindInt32("opcode", &opcode) != B_OK
807c5555ad3SStephan Aßmus || (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED)
808b6a7b204SAxel Dörfler || message->FindString("path", &path) != B_OK)
80961604e48SAxel Dörfler return B_BAD_VALUE;
81061604e48SAxel Dörfler
81161604e48SAxel Dörfler if (opcode == B_ENTRY_CREATED)
812b6a7b204SAxel Dörfler return _AddDevice(path);
81361604e48SAxel Dörfler
814c5555ad3SStephan Aßmus #if 0
815b6a7b204SAxel Dörfler return _RemoveDevice(path);
816c5555ad3SStephan Aßmus #else
817c5555ad3SStephan Aßmus // Don't handle B_ENTRY_REMOVED, let the control thread take care of it.
818c5555ad3SStephan Aßmus return B_OK;
819c5555ad3SStephan Aßmus #endif
82061604e48SAxel Dörfler }
82161604e48SAxel Dörfler
82261604e48SAxel Dörfler
82361604e48SAxel Dörfler void
_RecursiveScan(const char * directory)82461604e48SAxel Dörfler MouseInputDevice::_RecursiveScan(const char* directory)
82561604e48SAxel Dörfler {
826e01a0431SStephan Aßmus MID_CALLED();
82761604e48SAxel Dörfler
82861604e48SAxel Dörfler BEntry entry;
82961604e48SAxel Dörfler BDirectory dir(directory);
83061604e48SAxel Dörfler while (dir.GetNextEntry(&entry) == B_OK) {
83161604e48SAxel Dörfler BPath path;
83261604e48SAxel Dörfler entry.GetPath(&path);
83361604e48SAxel Dörfler
83461604e48SAxel Dörfler if (!strcmp(path.Leaf(), "serial")) {
83561604e48SAxel Dörfler // skip serial
83661604e48SAxel Dörfler continue;
83761604e48SAxel Dörfler }
83861604e48SAxel Dörfler
83961604e48SAxel Dörfler if (entry.IsDirectory())
84061604e48SAxel Dörfler _RecursiveScan(path.Path());
84161604e48SAxel Dörfler else
84261604e48SAxel Dörfler _AddDevice(path.Path());
84361604e48SAxel Dörfler }
84461604e48SAxel Dörfler }
84561604e48SAxel Dörfler
846e01a0431SStephan Aßmus
847e01a0431SStephan Aßmus MouseDevice*
_FindDevice(const char * path) const8485125eae2SStephan Aßmus MouseInputDevice::_FindDevice(const char* path) const
849e01a0431SStephan Aßmus {
850e01a0431SStephan Aßmus MID_CALLED();
851e01a0431SStephan Aßmus
852e01a0431SStephan Aßmus for (int32 i = fDevices.CountItems() - 1; i >= 0; i--) {
853e01a0431SStephan Aßmus MouseDevice* device = fDevices.ItemAt(i);
854e01a0431SStephan Aßmus if (strcmp(device->Path(), path) == 0)
855e01a0431SStephan Aßmus return device;
856e01a0431SStephan Aßmus }
857e01a0431SStephan Aßmus
858e01a0431SStephan Aßmus return NULL;
859e01a0431SStephan Aßmus }
860e01a0431SStephan Aßmus
861e01a0431SStephan Aßmus
862e01a0431SStephan Aßmus status_t
_AddDevice(const char * path)863e01a0431SStephan Aßmus MouseInputDevice::_AddDevice(const char* path)
864e01a0431SStephan Aßmus {
865e01a0431SStephan Aßmus MID_CALLED();
866e01a0431SStephan Aßmus
8675125eae2SStephan Aßmus BAutolock _(fDeviceListLock);
8685125eae2SStephan Aßmus
869e01a0431SStephan Aßmus _RemoveDevice(path);
870e01a0431SStephan Aßmus
871e01a0431SStephan Aßmus MouseDevice* device = new(std::nothrow) MouseDevice(*this, path);
872fdad31e6SMichael Lotz if (device == NULL) {
873e01a0431SStephan Aßmus TRACE("No memory\n");
874e01a0431SStephan Aßmus return B_NO_MEMORY;
875e01a0431SStephan Aßmus }
876e01a0431SStephan Aßmus
877e01a0431SStephan Aßmus if (!fDevices.AddItem(device)) {
878e01a0431SStephan Aßmus TRACE("No memory in list\n");
879e01a0431SStephan Aßmus delete device;
880e01a0431SStephan Aßmus return B_NO_MEMORY;
881e01a0431SStephan Aßmus }
882e01a0431SStephan Aßmus
883e01a0431SStephan Aßmus input_device_ref* devices[2];
884e01a0431SStephan Aßmus devices[0] = device->DeviceRef();
885e01a0431SStephan Aßmus devices[1] = NULL;
886e01a0431SStephan Aßmus
887e01a0431SStephan Aßmus TRACE("adding path: %s, name: %s\n", path, devices[0]->name);
888e01a0431SStephan Aßmus
889e01a0431SStephan Aßmus return RegisterDevices(devices);
890e01a0431SStephan Aßmus }
891e01a0431SStephan Aßmus
892e01a0431SStephan Aßmus
893e01a0431SStephan Aßmus status_t
_RemoveDevice(const char * path)894e01a0431SStephan Aßmus MouseInputDevice::_RemoveDevice(const char* path)
895e01a0431SStephan Aßmus {
896e01a0431SStephan Aßmus MID_CALLED();
897e01a0431SStephan Aßmus
8985125eae2SStephan Aßmus BAutolock _(fDeviceListLock);
8995125eae2SStephan Aßmus
900e01a0431SStephan Aßmus MouseDevice* device = _FindDevice(path);
901e01a0431SStephan Aßmus if (device == NULL) {
902e01a0431SStephan Aßmus TRACE("%s not found\n", path);
903e01a0431SStephan Aßmus return B_ENTRY_NOT_FOUND;
904e01a0431SStephan Aßmus }
905e01a0431SStephan Aßmus
906e01a0431SStephan Aßmus input_device_ref* devices[2];
907e01a0431SStephan Aßmus devices[0] = device->DeviceRef();
908e01a0431SStephan Aßmus devices[1] = NULL;
909e01a0431SStephan Aßmus
910e01a0431SStephan Aßmus TRACE("removing path: %s, name: %s\n", path, devices[0]->name);
911e01a0431SStephan Aßmus
912e01a0431SStephan Aßmus UnregisterDevices(devices);
913e01a0431SStephan Aßmus
914e01a0431SStephan Aßmus fDevices.RemoveItem(device);
915e01a0431SStephan Aßmus
916e01a0431SStephan Aßmus return B_OK;
917e01a0431SStephan Aßmus }
918