diff --git a/src/device_init.cpp b/src/device_init.cpp index 61415ced..6087da3e 100644 --- a/src/device_init.cpp +++ b/src/device_init.cpp @@ -23,6 +23,7 @@ void RegisterDevice::Register() inst.Add(DEVTYPE_EYETOY, new DeviceProxy()); inst.Add(DEVTYPE_BEATMANIA_DADADA, new DeviceProxy()); inst.Add(DEVTYPE_SEGA_SEAMIC, new DeviceProxy()); + inst.Add(DEVTYPE_KEYBOARDMANIA, new DeviceProxy()); RegisterAPIs(); } diff --git a/src/deviceproxy.h b/src/deviceproxy.h index 5116a7b5..7300e078 100644 --- a/src/deviceproxy.h +++ b/src/deviceproxy.h @@ -31,6 +31,7 @@ enum DeviceType DEVTYPE_EYETOY, DEVTYPE_BEATMANIA_DADADA, DEVTYPE_SEGA_SEAMIC, + DEVTYPE_KEYBOARDMANIA, }; struct SelectDeviceName { diff --git a/src/usb-pad/dx/dinput-config.cpp b/src/usb-pad/dx/dinput-config.cpp index 60b66854..11e86134 100644 --- a/src/usb-pad/dx/dinput-config.cpp +++ b/src/usb-pad/dx/dinput-config.cpp @@ -84,6 +84,17 @@ DWORD LABELS[CID_COUNT] = { IDC_LABEL17, IDC_LABEL18, IDC_LABEL19, + IDC_LABEL20, + IDC_LABEL21, + IDC_LABEL22, + IDC_LABEL23, + IDC_LABEL24, + IDC_LABEL25, + IDC_LABEL26, + IDC_LABEL27, + IDC_LABEL28, + IDC_LABEL29, + IDC_LABEL30, }; struct DXDlgSettings @@ -944,6 +955,13 @@ INT_PTR CALLBACK DxDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam TestForce(s->port); } break; + case IDC_DELALL: + { + for (int i = 0; i < CID_COUNT; i++) { + DeleteControl(s->port, (ControlID)i); + } + } + break; case IDC_ASS0: { StartListen(CID_STEERING); break; } case IDC_ASS1: { StartListen(CID_STEERING_R); break; } @@ -965,6 +983,17 @@ INT_PTR CALLBACK DxDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam case IDC_ASS17: { StartListen(CID_R3); break; } case IDC_ASS18: { StartListen(CID_SELECT); break; } case IDC_ASS19: { StartListen(CID_START); break; } + case IDC_ASS20: { StartListen(CID_BUTTON20); break; } + case IDC_ASS21: { StartListen(CID_BUTTON21); break; } + case IDC_ASS22: { StartListen(CID_BUTTON22); break; } + case IDC_ASS23: { StartListen(CID_BUTTON23); break; } + case IDC_ASS24: { StartListen(CID_BUTTON24); break; } + case IDC_ASS25: { StartListen(CID_BUTTON25); break; } + case IDC_ASS26: { StartListen(CID_BUTTON26); break; } + case IDC_ASS27: { StartListen(CID_BUTTON27); break; } + case IDC_ASS28: { StartListen(CID_BUTTON28); break; } + case IDC_ASS29: { StartListen(CID_BUTTON29); break; } + case IDC_ASS30: { StartListen(CID_BUTTON30); break; } case IDC_DEL0: { DeleteControl(s->port, CID_STEERING); break; } case IDC_DEL1: { DeleteControl(s->port, CID_STEERING_R); break; } case IDC_DEL2: { DeleteControl(s->port, CID_THROTTLE); break; } @@ -1148,6 +1177,9 @@ int DInputPad::Configure(int port, const char* dev_type, void *data) if (strcmp(dev_type, "buzz_device") == 0) { return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DLG_BUZZ), h.hWnd, DxDialogProc, (LPARAM)&s); } + if(strcmp(dev_type, "keyboardmania") == 0) { + return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DLG_KEYBOARDMANIA), h.hWnd, DxDialogProc, (LPARAM)&s); + } return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DIALOG1), h.hWnd, DxDialogProc, (LPARAM)&s); } diff --git a/src/usb-pad/dx/dx.h b/src/usb-pad/dx/dx.h index 0e4e1ce3..ea2ba009 100644 --- a/src/usb-pad/dx/dx.h +++ b/src/usb-pad/dx/dx.h @@ -56,6 +56,17 @@ enum ControlID CID_R3, CID_SELECT, CID_START, + CID_BUTTON20, + CID_BUTTON21, + CID_BUTTON22, + CID_BUTTON23, + CID_BUTTON24, + CID_BUTTON25, + CID_BUTTON26, + CID_BUTTON27, + CID_BUTTON28, + CID_BUTTON29, + CID_BUTTON30, CID_COUNT, }; diff --git a/src/usb-pad/dx/usb-pad-dx.cpp b/src/usb-pad/dx/usb-pad-dx.cpp index 50fedfe9..90e05f88 100644 --- a/src/usb-pad/dx/usb-pad-dx.cpp +++ b/src/usb-pad/dx/usb-pad-dx.cpp @@ -35,6 +35,16 @@ int DInputPad::TokenIn(uint8_t *buf, int len) pad_copy_data(mType, buf, mWheelData); return 5; } + + if (mType == WT_KEYBOARDMANIA_CONTROLLER) { + for (int i = 0; i < 31; i++) { + if (GetControl(mPort, i)) { + mWheelData.buttons |= 1 << i; + } + } + pad_copy_data(mType, buf, mWheelData); + return len; + } //Allow in both ports but warn in configure dialog that only one DX wheel is supported for now //if(idx == 0){ diff --git a/src/usb-pad/dx/versionproxy.h b/src/usb-pad/dx/versionproxy.h index c76086e1..58b75289 100644 --- a/src/usb-pad/dx/versionproxy.h +++ b/src/usb-pad/dx/versionproxy.h @@ -8,6 +8,7 @@ #define IDB_BITMAP2 112 #define IDB_BITMAP3 113 #define IDD_DLG_BUZZ 114 +#define IDD_DLG_KEYBOARDMANIA 115 #define IDD_DIALOG1 202 #define IDC_DEL0 1001 #define IDC_ASS0 1002 @@ -169,6 +170,29 @@ #define IDC_BZ_CTL4_LBL3 1135 #define IDC_BZ_CTL4_LBL4 1136 #define IDC_BZ_CTL4_LBL5 1137 +#define IDC_LABEL20 1138 +#define IDC_ASS20 1139 +#define IDC_LABEL21 1140 +#define IDC_ASS21 1141 +#define IDC_LABEL22 1142 +#define IDC_ASS22 1143 +#define IDC_LABEL23 1144 +#define IDC_ASS23 1145 +#define IDC_LABEL24 1146 +#define IDC_ASS24 1147 +#define IDC_LABEL25 1148 +#define IDC_ASS25 1149 +#define IDC_LABEL26 1150 +#define IDC_ASS26 1151 +#define IDC_LABEL27 1152 +#define IDC_ASS27 1153 +#define IDC_LABEL28 1154 +#define IDC_ASS28 1155 +#define IDC_LABEL29 1156 +#define IDC_ASS29 1157 +#define IDC_LABEL30 1158 +#define IDC_ASS30 1159 +#define IDC_DELALL 1160 // Next default values for new objects // diff --git a/src/usb-pad/dx/versionproxy.rc b/src/usb-pad/dx/versionproxy.rc index 8803b19c..2c646479 100644 --- a/src/usb-pad/dx/versionproxy.rc +++ b/src/usb-pad/dx/versionproxy.rc @@ -297,6 +297,77 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,354,142,50,14 END +IDD_DLG_KEYBOARDMANIA DIALOGEX 0, 0, 580, 160 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Keyboardmania controller" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Buttons",IDC_STATIC,5,5,140,50 + PUSHBUTTON "Start",IDC_ASS22,90,15,50,15 + PUSHBUTTON "Select",IDC_ASS14,90,35,50,15 + LTEXT "1/1/1/1",IDC_LABEL22,10,17,50,8 + LTEXT "1/1/1/1",IDC_LABEL14,10,37,50,8 + GROUPBOX "Wheel",IDC_STATIC,150,5,140,50 + PUSHBUTTON "Up",IDC_ASS29,235,15,50,15 + PUSHBUTTON "Down",IDC_ASS30,235,35,50,15 + LTEXT "1/1/1/1",IDC_LABEL29,155,17,50,8 + LTEXT "1/1/1/1",IDC_LABEL30,155,37,50,8 + + GROUPBOX "Keys",IDC_STATIC,5,60,570,70 + PUSHBUTTON "C 1",IDC_ASS0,10,95,40,15 + PUSHBUTTON "C# 1",IDC_ASS1,30,80,40,15 + PUSHBUTTON "D 1",IDC_ASS2,50,95,40,15 + PUSHBUTTON "D# 1",IDC_ASS3,70,80,40,15 + PUSHBUTTON "E 1",IDC_ASS4,90,95,40,15 + PUSHBUTTON "F 1",IDC_ASS5,130,95,40,15 + PUSHBUTTON "F# 1",IDC_ASS6,150,80,40,15 + PUSHBUTTON "G 1",IDC_ASS8,170,95,40,15 + PUSHBUTTON "G# 1",IDC_ASS9,190,80,40,15 + PUSHBUTTON "A 1",IDC_ASS10,210,95,40,15 + PUSHBUTTON "A# 1",IDC_ASS11,230,80,40,15 + PUSHBUTTON "B 1",IDC_ASS12,250,95,40,15 + PUSHBUTTON "C 2",IDC_ASS13,290,95,40,15 + PUSHBUTTON "C# 2",IDC_ASS16,310,80,40,15 + PUSHBUTTON "D 2",IDC_ASS17,330,95,40,15 + PUSHBUTTON "D# 2",IDC_ASS18,350,80,40,15 + PUSHBUTTON "E 2",IDC_ASS19,370,95,40,15 + PUSHBUTTON "F 2",IDC_ASS20,410,95,40,15 + PUSHBUTTON "F# 2",IDC_ASS21,430,80,40,15 + PUSHBUTTON "G 2",IDC_ASS24,450,95,40,15 + PUSHBUTTON "G# 2",IDC_ASS25,470,80,40,15 + PUSHBUTTON "A 2",IDC_ASS26,490,95,40,15 + PUSHBUTTON "A# 2",IDC_ASS27,510,80,40,15 + PUSHBUTTON "B 2",IDC_ASS28,530,95,40,15 + LTEXT "1/1/1/1",IDC_LABEL0,10,110,38,8 + LTEXT "1/1/1/1",IDC_LABEL1,30,70,38,8 + LTEXT "1/1/1/1",IDC_LABEL2,50,110,38,8 + LTEXT "1/1/1/1",IDC_LABEL3,70,70,38,8 + LTEXT "1/1/1/1",IDC_LABEL4,90,110,38,8 + LTEXT "1/1/1/1",IDC_LABEL5,130,110,38,8 + LTEXT "1/1/1/1",IDC_LABEL6,150,70,38,8 + LTEXT "1/1/1/1",IDC_LABEL8,170,110,38,8 + LTEXT "1/1/1/1",IDC_LABEL9,190,70,38,8 + LTEXT "1/1/1/1",IDC_LABEL10,210,110,38,8 + LTEXT "1/1/1/1",IDC_LABEL11,230,70,38,8 + LTEXT "1/1/1/1",IDC_LABEL12,250,110,38,8 + LTEXT "1/1/1/1",IDC_LABEL13,290,110,38,8 + LTEXT "1/1/1/1",IDC_LABEL16,310,70,38,8 + LTEXT "1/1/1/1",IDC_LABEL17,330,110,38,8 + LTEXT "1/1/1/1",IDC_LABEL18,350,70,38,8 + LTEXT "1/1/1/1",IDC_LABEL19,370,110,38,8 + LTEXT "1/1/1/1",IDC_LABEL20,410,110,38,8 + LTEXT "1/1/1/1",IDC_LABEL21,430,70,38,8 + LTEXT "1/1/1/1",IDC_LABEL24,450,110,38,8 + LTEXT "1/1/1/1",IDC_LABEL25,470,70,38,8 + LTEXT "1/1/1/1",IDC_LABEL26,490,110,38,8 + LTEXT "1/1/1/1",IDC_LABEL27,510,70,38,8 + LTEXT "1/1/1/1",IDC_LABEL28,530,110,38,8 + + PUSHBUTTON "Reset all",IDC_DELALL,5,140,50,15 + DEFPUSHBUTTON "OK",IDOK,470,140,50,15 + PUSHBUTTON "Cancel",IDCANCEL,525,140,50,15 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -317,6 +388,10 @@ BEGIN IDD_DLG_BUZZ, DIALOG BEGIN END + + IDD_DLG_KEYBOARDMANIA, DIALOG + BEGIN + END END #endif // APSTUDIO_INVOKED @@ -345,6 +420,11 @@ BEGIN 0 END +IDD_DLG_KEYBOARDMANIA AFX_DIALOG_LAYOUT +BEGIN + 0 +END + #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/src/usb-pad/raw/raw-config.cpp b/src/usb-pad/raw/raw-config.cpp index ac3e0282..70c4ca78 100644 --- a/src/usb-pad/raw/raw-config.cpp +++ b/src/usb-pad/raw/raw-config.cpp @@ -283,7 +283,7 @@ void populate(HWND hW, RawDlgConfig *cfg) HidP_GetCaps(pPreparsedData, &caps); if(caps.UsagePage == HID_USAGE_PAGE_GENERIC && - caps.Usage == HID_USAGE_GENERIC_JOYSTICK) + (caps.Usage == HID_USAGE_GENERIC_JOYSTICK || caps.Usage == HID_USAGE_GENERIC_GAMEPAD)) { OSDebugOut(TEXT("Joystick found %04X:%04X\n"), attr.VendorID, attr.ProductID); std::wstring strPath(didData->DevicePath); diff --git a/src/usb-pad/raw/usb-pad-raw.cpp b/src/usb-pad/raw/usb-pad-raw.cpp index 4494885c..805c3335 100644 --- a/src/usb-pad/raw/usb-pad-raw.cpp +++ b/src/usb-pad/raw/usb-pad-raw.cpp @@ -430,7 +430,10 @@ int RawInputPad::Open() mOLWrite.hEvent = CreateEvent(0, 0, 0, 0); HidD_GetAttributes(mUsbHandle, &(attr)); - if (attr.VendorID != PAD_VID || attr.ProductID == 0xC262) { + + bool isClassicLogitech = (attr.VendorID == PAD_VID) && (attr.ProductID != 0xC262); + bool isKeyboardmania = (attr.VendorID == 0x0507) && (attr.ProductID == 0x0010); + if (!isClassicLogitech && !isKeyboardmania) { fwprintf(stderr, TEXT("USBqemu: Vendor is not Logitech or wheel is G920. Not sending force feedback commands for safety reasons.\n")); mDoPassthrough = 0; Close(); diff --git a/src/usb-pad/usb-pad.cpp b/src/usb-pad/usb-pad.cpp index cf043c66..6b44c796 100644 --- a/src/usb-pad/usb-pad.cpp +++ b/src/usb-pad/usb-pad.cpp @@ -36,6 +36,12 @@ static const USBDescStrings buzz_desc_strings = { "", "Logitech" }; +static const USBDescStrings kbm_desc_strings = { + "", + "USB Multipurpose Controller", + "", + "KONAMI" +}; std::list PadDevice::ListAPIs() { @@ -70,6 +76,16 @@ const TCHAR* BuzzDevice::LongAPIName(const std::string& name) return PadDevice::LongAPIName(name); } +std::list KeyboardmaniaDevice::ListAPIs() +{ + return PadDevice::ListAPIs(); +} + +const TCHAR* KeyboardmaniaDevice::LongAPIName(const std::string& name) +{ + return PadDevice::LongAPIName(name); +} + #ifdef _DEBUG void PrintBits(void * data, int size) { @@ -223,6 +239,11 @@ static void pad_handle_control(USBDevice *dev, USBPacket *p, int request, int va ret = sizeof(pad_gtforce_hid_report_descriptor); memcpy(data, pad_gtforce_hid_report_descriptor, ret); } + else if (t == WT_KEYBOARDMANIA_CONTROLLER) + { + ret = sizeof(kbm_hid_report_descriptor); + memcpy(data, kbm_hid_report_descriptor, ret); + } else { ret = sizeof(pad_driving_force_hid_separate_report_descriptor); @@ -391,6 +412,14 @@ void pad_copy_data(PS2WheelTypes type, uint8_t *buf, wheel_data_t &data) buf[4] = (data.buttons >> 4) & 0x3F; // 10 - 4 = 6 bits break; + case WT_KEYBOARDMANIA_CONTROLLER: + buf[0] = 0x3F; + buf[1] = data.buttons & 0xFF; + buf[2] = (data.buttons >> 8) & 0xFF; + buf[3] = (data.buttons >> 16) & 0xFF; + buf[4] = (data.buttons >> 24) & 0xFF; + break; + default: break; } @@ -753,4 +782,74 @@ int BuzzDevice::Freeze(int mode, USBDevice* dev, void* data) return PadDevice::Freeze(mode, dev, data); } +// ---- Keyboardmania ---- + +USBDevice* KeyboardmaniaDevice::CreateDevice(int port) +{ + std::string varApi; + LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi); + PadProxyBase* proxy = RegisterPad::instance().Proxy(varApi); + if (!proxy) + { + SysMessage(TEXT("Keyboardmania: Invalid input API.\n")); + USB_LOG("usb-pad: %s: Invalid input API.\n", TypeName()); + return NULL; + } + + USB_LOG("usb-pad: creating device '%s' on port %d with %s\n", TypeName(), port, varApi.c_str()); + Pad* pad = proxy->CreateObject(port, TypeName()); + + if (!pad) + return NULL; + + pad->Type(WT_KEYBOARDMANIA_CONTROLLER); + PADState* s = new PADState(); + + s->desc.full = &s->desc_dev; + s->desc.str = kbm_desc_strings; + + if (usb_desc_parse_dev(kbm_dev_descriptor, sizeof(kbm_dev_descriptor), s->desc, s->desc_dev) < 0) + goto fail; + if (usb_desc_parse_config(kbm_config_descriptor, sizeof(kbm_config_descriptor), s->desc_dev) < 0) + goto fail; + + s->f.wheel_type = pad->Type(); + s->pad = pad; + s->port = port; + s->dev.speed = USB_SPEED_FULL; + s->dev.klass.handle_attach = usb_desc_attach; + s->dev.klass.handle_reset = pad_handle_reset; + s->dev.klass.handle_control = pad_handle_control; + s->dev.klass.handle_data = pad_handle_data; + s->dev.klass.unrealize = pad_handle_destroy; + s->dev.klass.open = pad_open; + s->dev.klass.close = pad_close; + s->dev.klass.usb_desc = &s->desc; + s->dev.klass.product_desc = s->desc.str[2]; + + usb_desc_init(&s->dev); + usb_ep_init(&s->dev); + pad_handle_reset((USBDevice*)s); + + return (USBDevice*)s; + +fail: + pad_handle_destroy((USBDevice*)s); + return nullptr; +} + +int KeyboardmaniaDevice::Configure(int port, const std::string& api, void* data) +{ + auto proxy = RegisterPad::instance().Proxy(api); + if (proxy) + return proxy->Configure(port, TypeName(), data); + return RESULT_CANCELED; +} + +int KeyboardmaniaDevice::Freeze(int mode, USBDevice* dev, void* data) +{ + return PadDevice::Freeze(mode, dev, data); +} + + } //namespace diff --git a/src/usb-pad/usb-pad.h b/src/usb-pad/usb-pad.h index 4eb2faca..45f1c94d 100644 --- a/src/usb-pad/usb-pad.h +++ b/src/usb-pad/usb-pad.h @@ -90,6 +90,25 @@ class SeamicDevice static int Freeze(int mode, USBDevice *dev, void *data); }; +class KeyboardmaniaDevice +{ +public: + virtual ~KeyboardmaniaDevice() {} + static USBDevice* CreateDevice(int port); + static const TCHAR* Name() + { + return TEXT("Keyboardmania"); + } + static const char* TypeName() + { + return "keyboardmania"; + } + static std::list ListAPIs(); + static const TCHAR* LongAPIName(const std::string& name); + static int Configure(int port, const std::string& api, void *data); + static int Freeze(int mode, USBDevice *dev, void *data); +}; + // Most likely as seen on https://github.com/matlo/GIMX #define CMD_DOWNLOAD 0x00 #define CMD_DOWNLOAD_AND_PLAY 0x01 @@ -138,6 +157,7 @@ enum PS2WheelTypes { WT_ROCKBAND1_DRUMKIT, WT_BUZZ_CONTROLLER, WT_SEGA_SEAMIC, + WT_KEYBOARDMANIA_CONTROLLER, }; inline int range_max(PS2WheelTypes type) @@ -1233,6 +1253,141 @@ static const uint8_t buzz_hid_report_descriptor[] = { // 78 bytes }; +/////////////////// +// Keyboardmania // +/////////////////// +static const uint8_t kbm_dev_descriptor[] = { + 0x12, // bLength + 0x01, // bDescriptorType (Device) + 0x10, 0x01, // bcdUSB 1.10 + 0x00, // bDeviceClass (Use class information in the Interface Descriptors) + 0x00, // bDeviceSubClass + 0x00, // bDeviceProtocol + 0x08, // bMaxPacketSize0 8 + 0x07, 0x05, // idVendor 0x0507 + 0x10, 0x00, // idProduct 0x0010 + 0x00, 0x01, // bcdDevice 01.00 + 0x01, // iManufacturer (String Index) + 0x02, // iProduct (String Index) + 0x00, // iSerialNumber (String Index) + 0x01, // bNumConfigurations 1 +}; + +static const uint8_t kbm_config_descriptor[] = { + 0x09, // bLength + 0x02, // bDescriptorType (Configuration) + 0x22, 0x00, // wTotalLength 34 + 0x01, // bNumInterfaces 1 + 0x01, // bConfigurationValue + 0x00, // iConfiguration (String Index) + 0x80, // bmAttributes + 0x19, // bMaxPower 50mA + + 0x09, // bLength + 0x04, // bDescriptorType (Interface) + 0x00, // bInterfaceNumber 0 + 0x00, // bAlternateSetting + 0x01, // bNumEndpoints 1 + 0x03, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0x02, // iInterface (String Index) + + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x10, 0x01, // bcdHID 1.11 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0x96, 0x00, // wDescriptorLength[0] 150 + + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x81, // bEndpointAddress (IN/D2H) + 0x03, // bmAttributes (Interrupt) + 0x08, 0x00, // wMaxPacketSize 8 + 0x04, // bInterval 4 (unit depends on device speed) +}; + +static const uint8_t kbm_hid_report_descriptor[] = { + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x05, // USAGE (Game Pad) + 0xA1, 0x01, // COLLECTION (Application) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x3A, // USAGE_MINIMUM (Button 58) + 0x29, 0x3F, // USAGE_MAXIMUM (Button 63) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x06, // REPORT_COUNT (6) + 0x81, 0x02, // INPUT (Data,Variable,Absolute,NoWrap,Linear,PrefState,NoNull,NonVolatile,Bitmap) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x01, // INPUT (Constant,Array,Absolute) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x07, // USAGE_MAXIMUM (Button 7) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x07, // REPORT_COUNT (7) + 0x81, 0x02, // INPUT (Data,Variable,Absolute,NoWrap,Linear,PrefState,NoNull,NonVolatile,Bitmap) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x01, // INPUT (Constant,Array,Absolute) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x08, // USAGE_MINIMUM (Button 8) + 0x29, 0x0E, // USAGE_MAXIMUM (Button 14) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x07, // REPORT_COUNT (7) + 0x81, 0x02, // INPUT (Data,Variable,Absolute,NoWrap,Linear,PrefState,NoNull,NonVolatile,Bitmap) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x01, // INPUT (Constant,Array,Absolute) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x0F, // USAGE_MINIMUM (Button 15) + 0x29, 0x15, // USAGE_MAXIMUM (Button 21) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x07, // REPORT_COUNT (7) + 0x81, 0x02, // INPUT (Data,Variable,Absolute,NoWrap,Linear,PrefState,NoNull,NonVolatile,Bitmap) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x01, // INPUT (Constant,Array,Absolute) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x16, // USAGE_MINIMUM (Button 22) + 0x29, 0x1C, // USAGE_MAXIMUM (Button 28) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x07, // REPORT_COUNT (7) + 0x81, 0x02, // INPUT (Data,Variable,Absolute,NoWrap,Linear,PrefState,NoNull,NonVolatile,Bitmap) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x01, // INPUT (Constant,Array,Absolute) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x01, // USAGE (Pointer) + 0xA1, 0x00, // COLLECTION (Physical) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0xFF, // LOGICAL_MINIMUM (-1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x02, // REPORT_COUNT (2) + 0x75, 0x02, // REPORT_SIZE (2) + 0x81, 0x02, // INPUT (Data,Variable,Absolute,NoWrap,Linear,PrefState,NoNull,NonVolatile,Bitmap) + 0x95, 0x04, // REPORT_COUNT (4) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x01, // INPUT (Constant,Array,Absolute) + 0xC0, // END_COLLECTION + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x01, // INPUT (Constant,Array,Absolute) + 0xc0 // END_COLLECTION +}; + struct dfp_buttons_t { uint16_t cross : 1;