2 * Copyright 2008-2011 Michael Lotz <mmlr@mlotz.ch>
3 * Distributed under the terms of the MIT license.
7 //! Driver for USB Human Interface Devices.
11 #include "MouseProtocolHandler.h"
13 #include "HIDCollection.h"
14 #include "HIDDevice.h"
15 #include "HIDReport.h"
16 #include "HIDReportItem.h"
20 #include <usb/USB_hid.h>
22 #include <keyboard_mouse_driver.h>
25 MouseProtocolHandler::MouseProtocolHandler(HIDReport
&report
,
26 HIDReportItem
&xAxis
, HIDReportItem
&yAxis
)
28 ProtocolHandler(report
.Device(), "input/mouse/usb/", 0),
40 uint32 buttonCount
= 0;
41 for (uint32 i
= 0; i
< report
.CountItems(); i
++) {
42 HIDReportItem
*item
= report
.ItemAt(i
);
46 if (item
->UsagePage() == B_HID_USAGE_PAGE_BUTTON
47 && item
->UsageID() - 1 < B_MAX_MOUSE_BUTTONS
) {
48 fButtons
[buttonCount
++] = item
;
52 fButtons
[buttonCount
] = NULL
;
54 fWheel
= report
.FindItem(B_HID_USAGE_PAGE_GENERIC_DESKTOP
,
57 TRACE("mouse device with %lu buttons and %swheel\n", buttonCount
,
58 fWheel
== NULL
? "no " : "");
59 TRACE("report id: %u\n", report
.ID());
64 MouseProtocolHandler::AddHandlers(HIDDevice
&device
, HIDCollection
&collection
,
65 ProtocolHandler
*&handlerList
)
67 bool supported
= false;
68 switch (collection
.UsagePage()) {
69 case B_HID_USAGE_PAGE_GENERIC_DESKTOP
:
71 switch (collection
.UsageID()) {
72 case B_HID_UID_GD_MOUSE
:
73 case B_HID_UID_GD_POINTER
:
83 TRACE("collection not a mouse\n");
87 HIDParser
&parser
= device
.Parser();
88 uint32 maxReportCount
= parser
.CountReports(HID_REPORT_TYPE_INPUT
);
89 if (maxReportCount
== 0)
92 uint32 inputReportCount
= 0;
93 HIDReport
*inputReports
[maxReportCount
];
94 collection
.BuildReportList(HID_REPORT_TYPE_INPUT
, inputReports
,
97 for (uint32 i
= 0; i
< inputReportCount
; i
++) {
98 HIDReport
*inputReport
= inputReports
[i
];
100 // try to find at least an absolute x and y axis
101 HIDReportItem
*xAxis
= inputReport
->FindItem(
102 B_HID_USAGE_PAGE_GENERIC_DESKTOP
, B_HID_UID_GD_X
);
103 if (xAxis
== NULL
|| !xAxis
->Relative())
106 HIDReportItem
*yAxis
= inputReport
->FindItem(
107 B_HID_USAGE_PAGE_GENERIC_DESKTOP
, B_HID_UID_GD_Y
);
108 if (yAxis
== NULL
|| !yAxis
->Relative())
111 ProtocolHandler
*newHandler
= new(std::nothrow
) MouseProtocolHandler(
112 *inputReport
, *xAxis
, *yAxis
);
113 if (newHandler
== NULL
) {
114 TRACE("failed to allocated mouse protocol handler\n");
118 newHandler
->SetNextHandler(handlerList
);
119 handlerList
= newHandler
;
125 MouseProtocolHandler::Control(uint32
*cookie
, uint32 op
, void *buffer
,
131 if (length
< sizeof(mouse_movement
))
132 return B_BUFFER_OVERFLOW
;
135 status_t result
= _ReadReport(buffer
, cookie
);
136 if (result
!= B_INTERRUPTED
)
143 if (fReport
.Device()->IsRemoved())
144 return B_DEV_NOT_READY
;
146 // we are always on demand, so 0 queued events
150 case MS_SET_CLICKSPEED
:
152 return user_memcpy(&fClickSpeed
, buffer
, sizeof(bigtime_t
));
154 fClickSpeed
= *(bigtime_t
*)buffer
;
164 MouseProtocolHandler::_ReadReport(void *buffer
, uint32
*cookie
)
166 status_t result
= fReport
.WaitForReport(B_INFINITE_TIMEOUT
);
167 if (result
!= B_OK
) {
168 if (fReport
.Device()->IsRemoved()) {
169 TRACE("device has been removed\n");
170 return B_DEV_NOT_READY
;
173 if ((*cookie
& PROTOCOL_HANDLER_COOKIE_FLAG_CLOSED
) != 0)
176 if (result
!= B_INTERRUPTED
) {
177 // interrupts happen when other reports come in on the same
179 TRACE_ALWAYS("error waiting for report: %s\n", strerror(result
));
182 // signal that we simply want to try again
183 return B_INTERRUPTED
;
186 uint32 axisRelativeData
[2];
187 axisRelativeData
[0] = 0;
188 axisRelativeData
[1] = 0;
190 if (fXAxis
.Extract() == B_OK
&& fXAxis
.Valid())
191 axisRelativeData
[0] = fXAxis
.Data();
193 if (fYAxis
.Extract() == B_OK
&& fYAxis
.Valid())
194 axisRelativeData
[1] = fYAxis
.Data();
196 uint32 wheelData
= 0;
197 if (fWheel
!= NULL
&& fWheel
->Extract() == B_OK
&& fWheel
->Valid())
198 wheelData
= fWheel
->Data();
201 for (uint32 i
= 0; i
< B_MAX_MOUSE_BUTTONS
; i
++) {
202 HIDReportItem
*button
= fButtons
[i
];
206 if (button
->Extract() == B_OK
&& button
->Valid())
207 buttons
|= (button
->Data() & 1) << (button
->UsageID() - 1);
210 fReport
.DoneProcessing();
211 TRACE("got mouse report\n");
214 bigtime_t timestamp
= system_time();
216 if (fLastButtons
== 0) {
217 if (fLastClickTime
+ fClickSpeed
> timestamp
)
223 fLastClickTime
= timestamp
;
224 clicks
= fClickCount
;
227 fLastButtons
= buttons
;
229 mouse_movement
*info
= (mouse_movement
*)buffer
;
230 memset(info
, 0, sizeof(mouse_movement
));
232 info
->buttons
= buttons
;
233 info
->xdelta
= axisRelativeData
[0];
234 info
->ydelta
= -axisRelativeData
[1];
235 info
->clicks
= clicks
;
236 info
->timestamp
= timestamp
;
237 info
->wheel_ydelta
= -wheelData
;