USB HID: Split out tablet support into TabletProtocolHandler
* The previous approach of combining tablet and mouse support in MouseProtocolHandler was unintuitive and had the potential problem that if a device has multiple HID descriptors, one simulating a simple mouse, that one may be found first and there is no mechanism of choosing the best handler for a device. Now we can look for tablets before looking for mice. * Implement pressure, eraser and tilt support. Untested. This mostly comes from the patch in #7354, but eraser support should work more like intended by the Be API. * It appears that my Wacom Intuos 2 cannot be accessed via the HID framework, except as regular mouse. So I couldn't actually test these changes. I believe what worked before, i.e. QEMU absolute mouse position support, should work as good as before. Please shout if not! * If more recent Wacom tablets /could/ work with these changes, they will not, because the HID driver still explicitely ignores Wacom devices and the dedicated Wacom driver will not pick up newer devices, with its hard-coded and un-generic device support.
This commit is contained in:
@@ -24,4 +24,5 @@ KernelAddon usb_hid :
|
|||||||
JoystickProtocolHandler.cpp
|
JoystickProtocolHandler.cpp
|
||||||
KeyboardProtocolHandler.cpp
|
KeyboardProtocolHandler.cpp
|
||||||
MouseProtocolHandler.cpp
|
MouseProtocolHandler.cpp
|
||||||
|
TabletProtocolHandler.cpp
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -22,16 +22,16 @@
|
|||||||
#include <keyboard_mouse_driver.h>
|
#include <keyboard_mouse_driver.h>
|
||||||
|
|
||||||
|
|
||||||
MouseProtocolHandler::MouseProtocolHandler(HIDReport &report, bool tablet,
|
MouseProtocolHandler::MouseProtocolHandler(HIDReport &report,
|
||||||
HIDReportItem &xAxis, HIDReportItem &yAxis)
|
HIDReportItem &xAxis, HIDReportItem &yAxis)
|
||||||
:
|
:
|
||||||
ProtocolHandler(report.Device(),
|
ProtocolHandler(report.Device(), "input/mouse/usb/", 0),
|
||||||
tablet ? "input/tablet/usb" : "input/mouse/usb/", 0),
|
|
||||||
fReport(report),
|
fReport(report),
|
||||||
fTablet(tablet),
|
|
||||||
fXAxis(xAxis),
|
fXAxis(xAxis),
|
||||||
fYAxis(yAxis),
|
fYAxis(yAxis),
|
||||||
fWheel(NULL),
|
fWheel(NULL),
|
||||||
|
|
||||||
fLastButtons(0),
|
fLastButtons(0),
|
||||||
fClickCount(0),
|
fClickCount(0),
|
||||||
fLastClickTime(0),
|
fLastClickTime(0),
|
||||||
@@ -64,7 +64,6 @@ void
|
|||||||
MouseProtocolHandler::AddHandlers(HIDDevice &device, HIDCollection &collection,
|
MouseProtocolHandler::AddHandlers(HIDDevice &device, HIDCollection &collection,
|
||||||
ProtocolHandler *&handlerList)
|
ProtocolHandler *&handlerList)
|
||||||
{
|
{
|
||||||
bool tablet = false;
|
|
||||||
bool supported = false;
|
bool supported = false;
|
||||||
switch (collection.UsagePage()) {
|
switch (collection.UsagePage()) {
|
||||||
case B_HID_USAGE_PAGE_GENERIC_DESKTOP:
|
case B_HID_USAGE_PAGE_GENERIC_DESKTOP:
|
||||||
@@ -78,26 +77,10 @@ MouseProtocolHandler::AddHandlers(HIDDevice &device, HIDCollection &collection,
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case B_HID_USAGE_PAGE_DIGITIZER:
|
|
||||||
{
|
|
||||||
switch (collection.UsageID()) {
|
|
||||||
case B_HID_UID_DIG_DIGITIZER:
|
|
||||||
case B_HID_UID_DIG_PEN:
|
|
||||||
case B_HID_UID_DIG_LIGHT_PEN:
|
|
||||||
case B_HID_UID_DIG_TOUCH_SCREEN:
|
|
||||||
case B_HID_UID_DIG_TOUCH_PAD:
|
|
||||||
case B_HID_UID_DIG_WHITE_BOARD:
|
|
||||||
supported = true;
|
|
||||||
tablet = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!supported) {
|
if (!supported) {
|
||||||
TRACE("collection not a mouse/tablet/digitizer\n");
|
TRACE("collection not a mouse\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,22 +97,19 @@ MouseProtocolHandler::AddHandlers(HIDDevice &device, HIDCollection &collection,
|
|||||||
for (uint32 i = 0; i < inputReportCount; i++) {
|
for (uint32 i = 0; i < inputReportCount; i++) {
|
||||||
HIDReport *inputReport = inputReports[i];
|
HIDReport *inputReport = inputReports[i];
|
||||||
|
|
||||||
// try to find at least an x and y axis
|
// try to find at least an absolute x and y axis
|
||||||
HIDReportItem *xAxis = inputReport->FindItem(
|
HIDReportItem *xAxis = inputReport->FindItem(
|
||||||
B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X);
|
B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X);
|
||||||
if (xAxis == NULL)
|
if (xAxis == NULL || !xAxis->Relative())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
HIDReportItem *yAxis = inputReport->FindItem(
|
HIDReportItem *yAxis = inputReport->FindItem(
|
||||||
B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_Y);
|
B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_Y);
|
||||||
if (yAxis == NULL)
|
if (yAxis == NULL || !yAxis->Relative())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!xAxis->Relative() && !yAxis->Relative())
|
|
||||||
tablet = true;
|
|
||||||
|
|
||||||
ProtocolHandler *newHandler = new(std::nothrow) MouseProtocolHandler(
|
ProtocolHandler *newHandler = new(std::nothrow) MouseProtocolHandler(
|
||||||
*inputReport, tablet, *xAxis, *yAxis);
|
*inputReport, *xAxis, *yAxis);
|
||||||
if (newHandler == NULL) {
|
if (newHandler == NULL) {
|
||||||
TRACE("failed to allocated mouse protocol handler\n");
|
TRACE("failed to allocated mouse protocol handler\n");
|
||||||
continue;
|
continue;
|
||||||
@@ -148,10 +128,8 @@ MouseProtocolHandler::Control(uint32 *cookie, uint32 op, void *buffer,
|
|||||||
switch (op) {
|
switch (op) {
|
||||||
case MS_READ:
|
case MS_READ:
|
||||||
{
|
{
|
||||||
if ((!fTablet && length < sizeof(mouse_movement))
|
if (length < sizeof(mouse_movement))
|
||||||
|| (fTablet && length < sizeof(tablet_movement))) {
|
|
||||||
return B_BUFFER_OVERFLOW;
|
return B_BUFFER_OVERFLOW;
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
status_t result = _ReadReport(buffer);
|
status_t result = _ReadReport(buffer);
|
||||||
@@ -202,21 +180,15 @@ MouseProtocolHandler::_ReadReport(void *buffer)
|
|||||||
return B_INTERRUPTED;
|
return B_INTERRUPTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
float axisAbsoluteData[2];
|
|
||||||
uint32 axisRelativeData[2];
|
uint32 axisRelativeData[2];
|
||||||
if (fXAxis.Extract() == B_OK && fXAxis.Valid()) {
|
axisRelativeData[0] = 0;
|
||||||
if (fXAxis.Relative())
|
axisRelativeData[1] = 0;
|
||||||
axisRelativeData[0] = fXAxis.Data();
|
|
||||||
else
|
|
||||||
axisAbsoluteData[0] = fXAxis.ScaledFloatData();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fYAxis.Extract() == B_OK && fYAxis.Valid()) {
|
if (fXAxis.Extract() == B_OK && fXAxis.Valid())
|
||||||
if (fYAxis.Relative())
|
axisRelativeData[0] = fXAxis.Data();
|
||||||
axisRelativeData[1] = fYAxis.Data();
|
|
||||||
else
|
if (fYAxis.Extract() == B_OK && fYAxis.Valid())
|
||||||
axisAbsoluteData[1] = fYAxis.ScaledFloatData();
|
axisRelativeData[1] = fYAxis.Data();
|
||||||
}
|
|
||||||
|
|
||||||
uint32 wheelData = 0;
|
uint32 wheelData = 0;
|
||||||
if (fWheel != NULL && fWheel->Extract() == B_OK && fWheel->Valid())
|
if (fWheel != NULL && fWheel->Extract() == B_OK && fWheel->Valid())
|
||||||
@@ -251,33 +223,15 @@ MouseProtocolHandler::_ReadReport(void *buffer)
|
|||||||
|
|
||||||
fLastButtons = buttons;
|
fLastButtons = buttons;
|
||||||
|
|
||||||
if (fTablet) {
|
mouse_movement *info = (mouse_movement *)buffer;
|
||||||
tablet_movement *info = (tablet_movement *)buffer;
|
memset(info, 0, sizeof(mouse_movement));
|
||||||
memset(info, 0, sizeof(tablet_movement));
|
|
||||||
|
|
||||||
info->xpos = axisAbsoluteData[0];
|
info->buttons = buttons;
|
||||||
info->ypos = axisAbsoluteData[1];
|
info->xdelta = axisRelativeData[0];
|
||||||
info->has_contact = true;
|
info->ydelta = -axisRelativeData[1];
|
||||||
info->pressure = 1.0;
|
info->clicks = clicks;
|
||||||
info->eraser = false;
|
info->timestamp = timestamp;
|
||||||
info->tilt_x = 0.0;
|
info->wheel_ydelta = -wheelData;
|
||||||
info->tilt_y = 0.0;
|
|
||||||
|
|
||||||
info->buttons = buttons;
|
|
||||||
info->clicks = clicks;
|
|
||||||
info->timestamp = timestamp;
|
|
||||||
info->wheel_ydelta = -wheelData;
|
|
||||||
} else {
|
|
||||||
mouse_movement *info = (mouse_movement *)buffer;
|
|
||||||
memset(info, 0, sizeof(mouse_movement));
|
|
||||||
|
|
||||||
info->buttons = buttons;
|
|
||||||
info->xdelta = axisRelativeData[0];
|
|
||||||
info->ydelta = -axisRelativeData[1];
|
|
||||||
info->clicks = clicks;
|
|
||||||
info->timestamp = timestamp;
|
|
||||||
info->wheel_ydelta = -wheelData;
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class HIDReportItem;
|
|||||||
class MouseProtocolHandler : public ProtocolHandler {
|
class MouseProtocolHandler : public ProtocolHandler {
|
||||||
public:
|
public:
|
||||||
MouseProtocolHandler(HIDReport &report,
|
MouseProtocolHandler(HIDReport &report,
|
||||||
bool tablet, HIDReportItem &xAxis,
|
HIDReportItem &xAxis,
|
||||||
HIDReportItem &yAxis);
|
HIDReportItem &yAxis);
|
||||||
|
|
||||||
static void AddHandlers(HIDDevice &device,
|
static void AddHandlers(HIDDevice &device,
|
||||||
@@ -37,7 +37,6 @@ private:
|
|||||||
status_t _ReadReport(void *buffer);
|
status_t _ReadReport(void *buffer);
|
||||||
|
|
||||||
HIDReport & fReport;
|
HIDReport & fReport;
|
||||||
bool fTablet;
|
|
||||||
|
|
||||||
HIDReportItem & fXAxis;
|
HIDReportItem & fXAxis;
|
||||||
HIDReportItem & fYAxis;
|
HIDReportItem & fYAxis;
|
||||||
|
|||||||
@@ -14,9 +14,10 @@
|
|||||||
#include "ProtocolHandler.h"
|
#include "ProtocolHandler.h"
|
||||||
|
|
||||||
// includes for the different protocol handlers
|
// includes for the different protocol handlers
|
||||||
|
#include "JoystickProtocolHandler.h"
|
||||||
#include "KeyboardProtocolHandler.h"
|
#include "KeyboardProtocolHandler.h"
|
||||||
#include "MouseProtocolHandler.h"
|
#include "MouseProtocolHandler.h"
|
||||||
#include "JoystickProtocolHandler.h"
|
#include "TabletProtocolHandler.h"
|
||||||
|
|
||||||
|
|
||||||
ProtocolHandler::ProtocolHandler(HIDDevice *device, const char *basePath,
|
ProtocolHandler::ProtocolHandler(HIDDevice *device, const char *basePath,
|
||||||
@@ -86,9 +87,19 @@ ProtocolHandler::AddHandlers(HIDDevice &device, ProtocolHandler *&handlerList,
|
|||||||
TRACE("collection usage page %u usage id %u\n",
|
TRACE("collection usage page %u usage id %u\n",
|
||||||
collection->UsagePage(), collection->UsageID());
|
collection->UsagePage(), collection->UsageID());
|
||||||
|
|
||||||
|
// NOTE: There isn't currently a mechanism in place that figures out the
|
||||||
|
// "best" handler for a device. Consider the case of a tablet input
|
||||||
|
// device: It might advertise itself as regular mouse in one descriptor.
|
||||||
|
// If the MouseProtocolHandler is given a chance to look at the device
|
||||||
|
// first, it might be happy with that descriptor and provide the
|
||||||
|
// protocol handler. That is why the TabletProtocolHandler and
|
||||||
|
// JostickProtocolHandlers are given a chance first, so they might look
|
||||||
|
// for more interesting descriptors that unlock the specific device
|
||||||
|
// functions best.
|
||||||
KeyboardProtocolHandler::AddHandlers(device, *collection, handlerList);
|
KeyboardProtocolHandler::AddHandlers(device, *collection, handlerList);
|
||||||
MouseProtocolHandler::AddHandlers(device, *collection, handlerList);
|
|
||||||
JoystickProtocolHandler::AddHandlers(device, *collection, handlerList);
|
JoystickProtocolHandler::AddHandlers(device, *collection, handlerList);
|
||||||
|
TabletProtocolHandler::AddHandlers(device, *collection, handlerList);
|
||||||
|
MouseProtocolHandler::AddHandlers(device, *collection, handlerList);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtocolHandler *handler = handlerList;
|
ProtocolHandler *handler = handlerList;
|
||||||
|
|||||||
@@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 Stephan Aßmus <[email protected]>
|
||||||
|
* Copyright 2010-2011 Enrique Medina Gremaldos <[email protected]>
|
||||||
|
* Copyright 2008-2011 Michael Lotz <[email protected]>
|
||||||
|
* Distributed under the terms of the MIT license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
//! Driver for USB Human Interface Devices.
|
||||||
|
|
||||||
|
|
||||||
|
#include "Driver.h"
|
||||||
|
#include "TabletProtocolHandler.h"
|
||||||
|
|
||||||
|
#include "HIDCollection.h"
|
||||||
|
#include "HIDDevice.h"
|
||||||
|
#include "HIDReport.h"
|
||||||
|
#include "HIDReportItem.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <string.h>
|
||||||
|
#include <usb/USB_hid.h>
|
||||||
|
|
||||||
|
#include <keyboard_mouse_driver.h>
|
||||||
|
|
||||||
|
|
||||||
|
TabletProtocolHandler::TabletProtocolHandler(HIDReport &report,
|
||||||
|
HIDReportItem &xAxis, HIDReportItem &yAxis)
|
||||||
|
:
|
||||||
|
ProtocolHandler(report.Device(), "input/tablet/usb", 0),
|
||||||
|
fReport(report),
|
||||||
|
|
||||||
|
fXAxis(xAxis),
|
||||||
|
fYAxis(yAxis),
|
||||||
|
fWheel(NULL),
|
||||||
|
|
||||||
|
fPressure(NULL),
|
||||||
|
fRange(NULL),
|
||||||
|
fTip(NULL),
|
||||||
|
fBarrelSwitch(NULL),
|
||||||
|
fEraser(NULL),
|
||||||
|
fXTilt(NULL),
|
||||||
|
fYTilt(NULL),
|
||||||
|
|
||||||
|
fLastButtons(0),
|
||||||
|
fClickCount(0),
|
||||||
|
fLastClickTime(0),
|
||||||
|
fClickSpeed(250000)
|
||||||
|
{
|
||||||
|
uint32 buttonCount = 0;
|
||||||
|
for (uint32 i = 0; i < report.CountItems(); i++) {
|
||||||
|
HIDReportItem *item = report.ItemAt(i);
|
||||||
|
if (!item->HasData())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (item->UsagePage() == B_HID_USAGE_PAGE_BUTTON
|
||||||
|
&& item->UsageID() - 1 < B_MAX_MOUSE_BUTTONS) {
|
||||||
|
fButtons[buttonCount++] = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fButtons[buttonCount] = NULL;
|
||||||
|
|
||||||
|
fWheel = report.FindItem(B_HID_USAGE_PAGE_GENERIC_DESKTOP,
|
||||||
|
B_HID_UID_GD_WHEEL);
|
||||||
|
|
||||||
|
fPressure = report.FindItem(B_HID_USAGE_PAGE_DIGITIZER,
|
||||||
|
B_HID_UID_DIG_TIP_PRESSURE);
|
||||||
|
|
||||||
|
fRange = report.FindItem(B_HID_USAGE_PAGE_DIGITIZER,
|
||||||
|
B_HID_UID_DIG_IN_RANGE);
|
||||||
|
|
||||||
|
fTip = report.FindItem(B_HID_USAGE_PAGE_DIGITIZER,
|
||||||
|
B_HID_UID_DIG_TIP_SWITCH);
|
||||||
|
|
||||||
|
fBarrelSwitch = report.FindItem(B_HID_USAGE_PAGE_DIGITIZER,
|
||||||
|
B_HID_UID_DIG_BARREL_SWITCH);
|
||||||
|
|
||||||
|
fEraser = report.FindItem(B_HID_USAGE_PAGE_DIGITIZER,
|
||||||
|
B_HID_UID_DIG_ERASER);
|
||||||
|
|
||||||
|
fXTilt = report.FindItem(B_HID_USAGE_PAGE_DIGITIZER,
|
||||||
|
B_HID_UID_DIG_X_TILT);
|
||||||
|
|
||||||
|
fYTilt = report.FindItem(B_HID_USAGE_PAGE_DIGITIZER,
|
||||||
|
B_HID_UID_DIG_Y_TILT);
|
||||||
|
|
||||||
|
TRACE("tablet device with %lu buttons, %stip, %seraser, "
|
||||||
|
"%spressure, and %stilt\n",
|
||||||
|
buttonCount,
|
||||||
|
fTip == NULL ? "no " : "",
|
||||||
|
fEraser == NULL ? "no " : "",
|
||||||
|
fPressure == NULL ? "no " : "",
|
||||||
|
fXTilt == NULL && fYTilt == NULL ? "no " : "");
|
||||||
|
|
||||||
|
TRACE("report id: %u\n", report.ID());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabletProtocolHandler::AddHandlers(HIDDevice &device, HIDCollection &collection,
|
||||||
|
ProtocolHandler *&handlerList)
|
||||||
|
{
|
||||||
|
bool supported = false;
|
||||||
|
switch (collection.UsagePage()) {
|
||||||
|
case B_HID_USAGE_PAGE_GENERIC_DESKTOP:
|
||||||
|
{
|
||||||
|
switch (collection.UsageID()) {
|
||||||
|
case B_HID_UID_GD_MOUSE:
|
||||||
|
case B_HID_UID_GD_POINTER:
|
||||||
|
// NOTE: Maybe it is supported if X-axis and Y-axis are
|
||||||
|
// absolute. This is determined below by scanning the
|
||||||
|
// report items for absolute X and Y axis.
|
||||||
|
supported = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_HID_USAGE_PAGE_DIGITIZER:
|
||||||
|
{
|
||||||
|
switch (collection.UsageID()) {
|
||||||
|
case B_HID_UID_DIG_DIGITIZER:
|
||||||
|
case B_HID_UID_DIG_PEN:
|
||||||
|
case B_HID_UID_DIG_LIGHT_PEN:
|
||||||
|
case B_HID_UID_DIG_TOUCH_SCREEN:
|
||||||
|
case B_HID_UID_DIG_TOUCH_PAD:
|
||||||
|
case B_HID_UID_DIG_WHITE_BOARD:
|
||||||
|
TRACE("found tablet/digitizer\n");
|
||||||
|
supported = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!supported) {
|
||||||
|
TRACE("collection not a tablet/digitizer\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HIDParser &parser = device.Parser();
|
||||||
|
uint32 maxReportCount = parser.CountReports(HID_REPORT_TYPE_INPUT);
|
||||||
|
if (maxReportCount == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint32 inputReportCount = 0;
|
||||||
|
HIDReport *inputReports[maxReportCount];
|
||||||
|
collection.BuildReportList(HID_REPORT_TYPE_INPUT, inputReports,
|
||||||
|
inputReportCount);
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < inputReportCount; i++) {
|
||||||
|
HIDReport *inputReport = inputReports[i];
|
||||||
|
|
||||||
|
// try to find at least an absolute x and y axis
|
||||||
|
HIDReportItem *xAxis = inputReport->FindItem(
|
||||||
|
B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X);
|
||||||
|
if (xAxis == NULL || xAxis->Relative())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
HIDReportItem *yAxis = inputReport->FindItem(
|
||||||
|
B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_Y);
|
||||||
|
if (yAxis == NULL || yAxis->Relative())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ProtocolHandler *newHandler = new(std::nothrow) TabletProtocolHandler(
|
||||||
|
*inputReport, *xAxis, *yAxis);
|
||||||
|
if (newHandler == NULL) {
|
||||||
|
TRACE("failed to allocated tablet protocol handler\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
newHandler->SetNextHandler(handlerList);
|
||||||
|
handlerList = newHandler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
TabletProtocolHandler::Control(uint32 *cookie, uint32 op, void *buffer,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
case MS_READ:
|
||||||
|
{
|
||||||
|
if (length < sizeof(tablet_movement))
|
||||||
|
return B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
status_t result = _ReadReport(buffer);
|
||||||
|
if (result != B_INTERRUPTED)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case MS_NUM_EVENTS:
|
||||||
|
{
|
||||||
|
if (fReport.Device()->IsRemoved())
|
||||||
|
return B_DEV_NOT_READY;
|
||||||
|
|
||||||
|
// we are always on demand, so 0 queued events
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MS_SET_CLICKSPEED:
|
||||||
|
#ifdef __HAIKU__
|
||||||
|
return user_memcpy(&fClickSpeed, buffer, sizeof(bigtime_t));
|
||||||
|
#else
|
||||||
|
fClickSpeed = *(bigtime_t *)buffer;
|
||||||
|
return B_OK;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
TabletProtocolHandler::_ReadReport(void *buffer)
|
||||||
|
{
|
||||||
|
status_t result = fReport.WaitForReport(B_INFINITE_TIMEOUT);
|
||||||
|
if (result != B_OK) {
|
||||||
|
if (fReport.Device()->IsRemoved()) {
|
||||||
|
TRACE("device has been removed\n");
|
||||||
|
return B_DEV_NOT_READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != B_INTERRUPTED) {
|
||||||
|
// interrupts happen when other reports come in on the same
|
||||||
|
// input as ours
|
||||||
|
TRACE_ALWAYS("error waiting for report: %s\n", strerror(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
// signal that we simply want to try again
|
||||||
|
return B_INTERRUPTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
float axisAbsoluteData[2];
|
||||||
|
axisAbsoluteData[0] = 0.0f;
|
||||||
|
axisAbsoluteData[1] = 0.0f;
|
||||||
|
|
||||||
|
if (fXAxis.Extract() == B_OK && fXAxis.Valid())
|
||||||
|
axisAbsoluteData[0] = fXAxis.ScaledFloatData();
|
||||||
|
|
||||||
|
if (fYAxis.Extract() == B_OK && fYAxis.Valid())
|
||||||
|
axisAbsoluteData[1] = fYAxis.ScaledFloatData();
|
||||||
|
|
||||||
|
uint32 wheelData = 0;
|
||||||
|
if (fWheel != NULL && fWheel->Extract() == B_OK && fWheel->Valid())
|
||||||
|
wheelData = fWheel->Data();
|
||||||
|
|
||||||
|
uint32 buttons = 0;
|
||||||
|
for (uint32 i = 0; i < B_MAX_MOUSE_BUTTONS; i++) {
|
||||||
|
HIDReportItem *button = fButtons[i];
|
||||||
|
if (button == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (button->Extract() == B_OK && button->Valid())
|
||||||
|
buttons |= (button->Data() & 1) << (button->UsageID() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
float pressure = 1.0f;
|
||||||
|
if (fPressure != NULL && fPressure->Extract() == B_OK
|
||||||
|
&& fPressure->Valid()) {
|
||||||
|
pressure = fPressure->ScaledFloatData();
|
||||||
|
}
|
||||||
|
|
||||||
|
float xTilt = 0.0f;
|
||||||
|
if (fXTilt != NULL && fXTilt->Extract() == B_OK && fXTilt->Valid())
|
||||||
|
xTilt = fXTilt->ScaledFloatData();
|
||||||
|
|
||||||
|
float yTilt = 0.0f;
|
||||||
|
if (fXTilt != NULL && fYTilt->Extract() == B_OK && fYTilt->Valid())
|
||||||
|
yTilt = fYTilt->ScaledFloatData();
|
||||||
|
|
||||||
|
bool inRange = true;
|
||||||
|
if (fRange != NULL)
|
||||||
|
inRange = fRange->Extract() == B_OK && fRange->Valid();
|
||||||
|
|
||||||
|
bool eraser = false;
|
||||||
|
if (fEraser != NULL && fEraser->Extract() == B_OK && fEraser->Valid())
|
||||||
|
eraser = (fEraser->Data() & 1) != 0;
|
||||||
|
|
||||||
|
fReport.DoneProcessing();
|
||||||
|
TRACE("got tablet report\n");
|
||||||
|
|
||||||
|
int32 clicks = 0;
|
||||||
|
bigtime_t timestamp = system_time();
|
||||||
|
if (buttons != 0) {
|
||||||
|
if (fLastButtons == 0) {
|
||||||
|
if (fLastClickTime + fClickSpeed > timestamp)
|
||||||
|
fClickCount++;
|
||||||
|
else
|
||||||
|
fClickCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fLastClickTime = timestamp;
|
||||||
|
clicks = fClickCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
fLastButtons = buttons;
|
||||||
|
|
||||||
|
tablet_movement *info = (tablet_movement *)buffer;
|
||||||
|
memset(info, 0, sizeof(tablet_movement));
|
||||||
|
|
||||||
|
info->xpos = axisAbsoluteData[0];
|
||||||
|
info->ypos = axisAbsoluteData[1];
|
||||||
|
info->has_contact = inRange;
|
||||||
|
info->pressure = pressure;
|
||||||
|
info->eraser = eraser;
|
||||||
|
info->tilt_x = xTilt;
|
||||||
|
info->tilt_y = yTilt;
|
||||||
|
|
||||||
|
info->buttons = buttons;
|
||||||
|
info->clicks = clicks;
|
||||||
|
info->timestamp = timestamp;
|
||||||
|
info->wheel_ydelta = -wheelData;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 Stephan Aßmus <[email protected]>
|
||||||
|
* Copyright 2010-2011 Enrique Medina Gremaldos <[email protected]>
|
||||||
|
* Copyright 2008-2011 Michael Lotz <[email protected]>
|
||||||
|
* Distributed under the terms of the MIT license.
|
||||||
|
*/
|
||||||
|
#ifndef USB_TABLET_PROTOCOL_HANDLER_H
|
||||||
|
#define USB_TABLET_PROTOCOL_HANDLER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <InterfaceDefs.h>
|
||||||
|
|
||||||
|
#include "ProtocolHandler.h"
|
||||||
|
|
||||||
|
|
||||||
|
class HIDCollection;
|
||||||
|
class HIDReportItem;
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef B_MAX_MOUSE_BUTTONS
|
||||||
|
# define B_MAX_MOUSE_BUTTONS 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
class TabletProtocolHandler : public ProtocolHandler {
|
||||||
|
public:
|
||||||
|
TabletProtocolHandler(HIDReport &report,
|
||||||
|
HIDReportItem &xAxis,
|
||||||
|
HIDReportItem &yAxis);
|
||||||
|
|
||||||
|
static void AddHandlers(HIDDevice &device,
|
||||||
|
HIDCollection &collection,
|
||||||
|
ProtocolHandler *&handlerList);
|
||||||
|
|
||||||
|
virtual status_t Control(uint32 *cookie, uint32 op, void *buffer,
|
||||||
|
size_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
status_t _ReadReport(void *buffer);
|
||||||
|
|
||||||
|
HIDReport & fReport;
|
||||||
|
|
||||||
|
HIDReportItem & fXAxis;
|
||||||
|
HIDReportItem & fYAxis;
|
||||||
|
HIDReportItem * fWheel;
|
||||||
|
HIDReportItem * fButtons[B_MAX_MOUSE_BUTTONS];
|
||||||
|
|
||||||
|
HIDReportItem * fPressure;
|
||||||
|
HIDReportItem * fRange;
|
||||||
|
HIDReportItem * fTip;
|
||||||
|
HIDReportItem * fBarrelSwitch;
|
||||||
|
HIDReportItem * fEraser;
|
||||||
|
HIDReportItem * fXTilt;
|
||||||
|
HIDReportItem * fYTilt;
|
||||||
|
|
||||||
|
uint32 fLastButtons;
|
||||||
|
uint32 fClickCount;
|
||||||
|
bigtime_t fLastClickTime;
|
||||||
|
bigtime_t fClickSpeed;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // USB_TABLET_PROTOCOL_HANDLER_H
|
||||||
Reference in New Issue
Block a user