USB: Add keyboardmania

Signed-off-by: jackun <jack.un@gmail.com>
This commit is contained in:
Aleksander Rem 2020-10-07 23:00:57 +02:00 committed by jackun
parent 9b8239bafa
commit 238da17196
12 changed files with 481 additions and 12 deletions

View File

@ -39,6 +39,7 @@ void RegisterDevice::Register()
inst.Add(DEVTYPE_EYETOY, new DeviceProxy<usb_eyetoy::EyeToyWebCamDevice>());
inst.Add(DEVTYPE_BEATMANIA_DADADA, new DeviceProxy<usb_hid::BeatManiaDevice>());
inst.Add(DEVTYPE_SEGA_SEAMIC, new DeviceProxy<usb_pad::SeamicDevice>());
inst.Add(DEVTYPE_KEYBOARDMANIA, new DeviceProxy<usb_pad::KeyboardmaniaDevice>());
RegisterAPIs();
}

View File

@ -46,6 +46,7 @@ enum DeviceType
DEVTYPE_EYETOY,
DEVTYPE_BEATMANIA_DADADA,
DEVTYPE_SEGA_SEAMIC,
DEVTYPE_KEYBOARDMANIA,
};
struct SelectDeviceName
@ -210,7 +211,7 @@ public:
return *registerDevice;
}
~RegisterDevice() { }
~RegisterDevice() {}
static void Register();
void Unregister();

View File

@ -235,7 +235,6 @@ void USBconfigure()
const char* players[] = {"Player 1:", "Player 2:"};
GtkWidget *rs_cb, *vbox;
uint32_t sel_idx = 0;
// Create the dialog window
GtkWidget* dlg = gtk_dialog_new_with_buttons(

View File

@ -108,6 +108,17 @@ namespace usb_pad
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
@ -990,6 +1001,14 @@ namespace usb_pad
}
}
break;
case IDC_DELALL:
{
for (int i = 0; i < CID_COUNT; i++)
{
DeleteControl(s->port, (ControlID)i);
}
}
break;
case IDC_ASS0:
{
@ -1091,6 +1110,61 @@ namespace usb_pad
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);
@ -1390,6 +1464,10 @@ namespace usb_pad
{
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);
}

View File

@ -74,6 +74,17 @@ namespace usb_pad
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,
};

View File

@ -58,6 +58,19 @@ namespace usb_pad
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){
//mWheelData.steering = 8191 + (int)(GetControl(STEERING, false)* 8191.0f) ;

View File

@ -5,6 +5,7 @@
#define IDC_STATIC -1
#define IDOK2 2
#define IDD_DLG_BUZZ 114
#define IDD_DLG_KEYBOARDMANIA 115
#define IDD_DIALOG1 202
#define IDC_DEL0 1001
#define IDC_ASS0 1002
@ -165,6 +166,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
//

View File

@ -256,6 +256,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
/////////////////////////////////////////////////////////////////////////////
//
@ -276,6 +347,10 @@ BEGIN
IDD_DLG_BUZZ, DIALOG
BEGIN
END
IDD_DLG_KEYBOARDMANIA, DIALOG
BEGIN
END
END
#endif // APSTUDIO_INVOKED
@ -295,6 +370,11 @@ BEGIN
0
END
IDD_DLG_KEYBOARDMANIA AFX_DIALOG_LAYOUT
BEGIN
0
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////

View File

@ -313,7 +313,7 @@ namespace usb_pad
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))
{
std::wstring strPath(didData->DevicePath);
std::transform(strPath.begin(), strPath.end(), strPath.begin(), ::toupper);

View File

@ -443,7 +443,10 @@ namespace usb_pad
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)
{
Console.Warning("USB: Vendor is not Logitech or wheel is G920. Not sending force feedback commands for safety reasons.\n");
mDoPassthrough = 0;

View File

@ -52,6 +52,11 @@ namespace usb_pad
"Logitech Buzz(tm) Controller V1",
"",
"Logitech"};
static const USBDescStrings kbm_desc_strings = {
"",
"USB Multipurpose Controller",
"",
"KONAMI"};
std::list<std::string> PadDevice::ListAPIs()
{
@ -86,6 +91,16 @@ namespace usb_pad
return PadDevice::LongAPIName(name);
}
std::list<std::string> 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)
{
@ -100,7 +115,6 @@ namespace usb_pad
*(ptrB++) = ' ';
}
*ptrB = '\0';
}
#else
@ -240,6 +254,11 @@ namespace usb_pad
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);
@ -409,6 +428,14 @@ namespace usb_pad
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;
}
@ -785,4 +812,77 @@ namespace usb_pad
return PadDevice::Freeze(mode, dev, data);
}
// ---- Keyboardmania ----
USBDevice* KeyboardmaniaDevice::CreateDevice(int port)
{
std::string varApi;
#ifdef _WIN32
std::wstring tmp;
LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp);
varApi = wstr_to_str(tmp);
#else
LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi);
#endif
PadProxyBase* proxy = RegisterPad::instance().Proxy(varApi);
if (!proxy)
{
Console.WriteLn("usb-pad: %s: Invalid input API.", TypeName());
return NULL;
}
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.dev_subtype = 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 usb_pad

View File

@ -45,7 +45,7 @@ namespace usb_pad
class PadDevice
{
public:
virtual ~PadDevice() { }
virtual ~PadDevice() {}
static USBDevice* CreateDevice(int port);
static const TCHAR* Name()
{
@ -135,6 +135,29 @@ namespace usb_pad
}
};
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<std::string> 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);
static std::vector<std::string> SubTypes()
{
return {};
}
};
// Most likely as seen on https://github.com/matlo/GIMX
#define CMD_DOWNLOAD 0x00
#define CMD_DOWNLOAD_AND_PLAY 0x01
@ -184,6 +207,7 @@ namespace usb_pad
WT_ROCKBAND1_DRUMKIT,
WT_BUZZ_CONTROLLER,
WT_SEGA_SEAMIC,
WT_KEYBOARDMANIA_CONTROLLER,
};
inline int range_max(PS2WheelTypes type)
@ -451,16 +475,16 @@ namespace usb_pad
static const int HATS_8TO4[] = {PAD_HAT_N, PAD_HAT_E, PAD_HAT_S, PAD_HAT_W};
#define PAD_VID 0x046D
#define PAD_PID 0xCA03 //black MOMO
#define PAD_PID 0xCA03 //black MOMO
#define GENERIC_PID 0xC294 //actually Driving Force aka PID that most logitech wheels initially report
#define PID_DF 0xC294
#define PID_DFP 0xC298 //SELECT + R3 + RIGHT SHIFT PADDLE (R1) ???
#define PID_DFGT 0xC29A
#define PID_FORMULA 0xC202 //Yellow Wingman Formula
#define PID_FGP 0xC20E //Formula GP (maybe GT FORCE LPRC-1000)
#define PID_FFGP 0xC293 // Formula Force GP
#define PID_GTF 0xC293 // as is Formula Force GP
#define PID_G25 0xC299 // OutRun 2 (jp) supports it apparently
#define PID_FGP 0xC20E //Formula GP (maybe GT FORCE LPRC-1000)
#define PID_FFGP 0xC293 // Formula Force GP
#define PID_GTF 0xC293 // as is Formula Force GP
#define PID_G25 0xC299 // OutRun 2 (jp) supports it apparently
#define MAX_BUTTONS 32
#define MAX_AXES 7 //random 7: axes + hatswitch
#define MAX_JOYS 32
@ -1121,7 +1145,7 @@ namespace usb_pad
0x03, // bmAttributes (Interrupt)
0x40, 0x00, // wMaxPacketSize 64
0x0A, // bInterval 10 (unit depends on device speed)
// 41 bytes
// 41 bytes
};
//Wii Rock Band drum kit
@ -1294,6 +1318,141 @@ namespace usb_pad
// 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;