void JoystickProtocolHandler::AddHandlers(HIDDevice &device, HIDCollection &collection, ProtocolHandler *&handlerList) { if (collection.UsagePage() != B_HID_USAGE_PAGE_GENERIC_DESKTOP || (collection.UsageID() != B_HID_UID_GD_JOYSTICK && collection.UsageID() != B_HID_UID_GD_GAMEPAD && collection.UsageID() != B_HID_UID_GD_MULTIAXIS)) { TRACE("collection not a joystick or gamepad\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 one axis bool foundAxis = false; for (uint32 j = 0; j < inputReport->CountItems(); j++) { HIDReportItem *item = inputReport->ItemAt(j); if (item == NULL || !item->HasData()) continue; if (item->UsagePage() != B_HID_USAGE_PAGE_GENERIC_DESKTOP) continue; if (item->UsageID() >= B_HID_UID_GD_X && item->UsageID() <= B_HID_UID_GD_RZ) { foundAxis = true; break; } } if (!foundAxis) continue; ProtocolHandler *newHandler = new(std::nothrow) JoystickProtocolHandler(*inputReport); if (newHandler == NULL) { TRACE("failed to allocated joystick protocol handler\n"); continue; } newHandler->SetNextHandler(handlerList); handlerList = newHandler; } }
status_t JoystickProtocolHandler::_Update() { 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_CANCELED) return B_CANCELED; 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_OK; } result = mutex_lock(&fUpdateLock); if (result != B_OK) { fReport.DoneProcessing(); return result; } memset(fCurrentValues.data, 0, fCurrentValues.data_size); for (uint32 i = 0; i < fAxisCount; i++) { if (fAxis[i] == NULL) continue; if (fAxis[i]->Extract() == B_OK && fAxis[i]->Valid()) fCurrentValues.axes[i] = (int16)fAxis[i]->ScaledData(16, true); } for (uint32 i = 0; i < fHatCount; i++) { HIDReportItem *hat = fHats[i]; if (hat == NULL) continue; if (hat->Extract() != B_OK || !hat->Valid()) continue; fCurrentValues.hats[i] = hat->ScaledRangeData(1, 8); } for (uint32 i = 0; i < fButtonCount; i++) { HIDReportItem *button = fButtons[i]; if (button == NULL) break; uint16 index = button->UsageID() - 1; if (index >= fMaxButton) continue; if (button->Extract() == B_OK && button->Valid()) { fCurrentValues.buttons[index / 32] |= (button->Data() & 1) << (index % 32); } } fReport.DoneProcessing(); TRACE("got joystick report\n"); *fCurrentValues.timestamp = system_time(); mutex_unlock(&fUpdateLock); return B_OK; }
JoystickProtocolHandler::JoystickProtocolHandler(HIDReport &report) : ProtocolHandler(report.Device(), "joystick/usb/", 0), fReport(report), fAxisCount(0), fAxis(NULL), fHatCount(0), fHats(NULL), fButtonCount(0), fMaxButton(0), fButtons(NULL), fOpenCount(0), fUpdateThread(-1) { mutex_init(&fUpdateLock, "joystick update lock"); memset(&fJoystickModuleInfo, 0, sizeof(joystick_module_info)); memset(&fCurrentValues, 0, sizeof(variable_joystick)); for (uint32 i = 0; i < report.CountItems(); i++) { HIDReportItem *item = report.ItemAt(i); if (!item->HasData()) continue; switch (item->UsagePage()) { case B_HID_USAGE_PAGE_BUTTON: { if (item->UsageID() > INT16_MAX) break; HIDReportItem **newButtons = (HIDReportItem **)realloc(fButtons, ++fButtonCount * sizeof(HIDReportItem *)); if (newButtons == NULL) { fButtonCount--; break; } fButtons = newButtons; fButtons[fButtonCount - 1] = item; if (fMaxButton < item->UsageID()) fMaxButton = item->UsageID(); break; } case B_HID_USAGE_PAGE_GENERIC_DESKTOP: { if (item->UsageID() == B_HID_UID_GD_HAT_SWITCH) { HIDReportItem **newHats = (HIDReportItem **)realloc(fHats, ++fHatCount * sizeof(HIDReportItem *)); if (newHats == NULL) { fHatCount--; break; } fHats = newHats; fHats[fHatCount - 1] = item; break; } // TODO: "axis" is set but not used! // uint16 axis = 0; if (item->UsageID() >= B_HID_UID_GD_X && item->UsageID() <= B_HID_UID_GD_WHEEL) { // axis = item->UsageID() - B_HID_UID_GD_X; } else if (item->UsageID() >= B_HID_UID_GD_VX && item->UsageID() <= B_HID_UID_GD_VNO) { // axis = item->UsageID() - B_HID_UID_GD_VX; } else break; HIDReportItem **newAxis = (HIDReportItem **)realloc(fAxis, ++fAxisCount * sizeof(HIDReportItem *)); if (newAxis == NULL) { fAxisCount--; break; } fAxis = newAxis; fAxis[fAxisCount - 1] = item; break; } } } fCurrentValues.initialize(fAxisCount, fHatCount, fMaxButton); TRACE("joystick device with %lu buttons, %lu axes and %lu hats\n", fButtonCount, fAxisCount, fHatCount); TRACE("report id: %u\n", report.ID()); }
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()); }
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; }