/* Filled in by udev-hid-bpf */ char UDEV_PROP_HUION_FIRMWARE_ID[64];
/* The prefix of the firmware ID we expect for this device. The full firmware *stringhasadatesuffix,e.g.HUION_T21j_221221
*/ char EXPECTED_FIRMWARE_ID[] = "HUION_T21j_";
staticconst __u8 fixed_rdesc_pad[] = {
UsagePage_GenericDesktop
Usage_GD_Keypad
CollectionApplication( // -- Byte 0 in report
ReportId(PAD_REPORT_ID)
LogicalMinimum_i8(0)
LogicalMaximum_i8(1)
UsagePage_Digitizers
Usage_Dig_TabletFunctionKeys
CollectionPhysical( // Byte 1 in report - just exists so we get to be a tablet pad
Usage_Dig_BarrelSwitch // BTN_STYLUS
ReportCount(1)
ReportSize(1)
Input(Var|Abs)
ReportCount(7) // padding
Input(Const) // Bytes 2/3 in report - just exists so we get to be a tablet pad
UsagePage_GenericDesktop
Usage_GD_X
Usage_GD_Y
ReportCount(2)
ReportSize(8)
Input(Var|Abs) // Byte 4 in report is the wheel
Usage_GD_Wheel
LogicalMinimum_i8(-1)
LogicalMaximum_i8(1)
ReportCount(1)
ReportSize(8)
Input(Var|Rel) // Byte 5 is the button state
UsagePage_Button
UsageMinimum_i8(0x1)
UsageMaximum_i8(0x6)
LogicalMinimum_i8(0x1)
LogicalMaximum_i8(0x6)
ReportCount(1)
ReportSize(8)
Input(Arr|Abs)
) // Make sure we match our original report length
FixedSizeVendorReport(PAD_REPORT_LENGTH)
)
};
staticconst __u8 fixed_rdesc_pen[] = {
UsagePage_Digitizers
Usage_Dig_Pen
CollectionApplication( // -- Byte 0 in report
ReportId(PEN_REPORT_ID)
Usage_Dig_Pen
CollectionPhysical( // -- Byte 1 in report
Usage_Dig_TipSwitch
Usage_Dig_BarrelSwitch
Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2
LogicalMinimum_i8(0)
LogicalMaximum_i8(1)
ReportSize(1)
ReportCount(3)
Input(Var|Abs)
ReportCount(4) // Padding
Input(Const)
Usage_Dig_InRange
ReportCount(1)
Input(Var|Abs)
ReportSize(16)
ReportCount(1)
PushPop(
UsagePage_GenericDesktop
Unit(cm)
UnitExponent(-1)
PhysicalMinimum_i16(0)
PhysicalMaximum_i16(160)
LogicalMinimum_i16(0)
LogicalMaximum_i16(32767)
Usage_GD_X
Input(Var|Abs) // Bytes 2+3
PhysicalMinimum_i16(0)
PhysicalMaximum_i16(100)
LogicalMinimum_i16(0)
LogicalMaximum_i16(32767)
Usage_GD_Y
Input(Var|Abs) // Bytes 4+5
)
UsagePage_Digitizers
Usage_Dig_TipPressure
LogicalMinimum_i16(0)
LogicalMaximum_i16(8191)
Input(Var|Abs) // Byte 6+7 // Two bytes padding so we don't need to change the report at all
ReportSize(8)
ReportCount(2)
Input(Const) // Byte 6+7
)
)
};
staticconst __u8 fixed_rdesc_vendor[] = {
UsagePage_Digitizers
Usage_Dig_Pen
CollectionApplication( // Byte 0 // We leave the pen on the vendor report ID
ReportId(VENDOR_REPORT_ID)
Usage_Dig_Pen
CollectionPhysical( // Byte 1 are the buttons
LogicalMinimum_i8(0)
LogicalMaximum_i8(1)
ReportSize(1)
Usage_Dig_TipSwitch
Usage_Dig_BarrelSwitch
Usage_Dig_SecondaryBarrelSwitch
ReportCount(3)
Input(Var|Abs)
ReportCount(4) // Padding
Input(Const)
Usage_Dig_InRange
ReportCount(1)
Input(Var|Abs)
ReportSize(16)
ReportCount(1)
PushPop(
UsagePage_GenericDesktop
Unit(cm)
UnitExponent(-1) // Note: reported logical range differs // from the pen report ID for x and y
LogicalMinimum_i16(0)
LogicalMaximum_i16(32000)
PhysicalMinimum_i16(0)
PhysicalMaximum_i16(160) // Bytes 2/3 in report
Usage_GD_X
Input(Var|Abs)
LogicalMinimum_i16(0)
LogicalMaximum_i16(20000)
PhysicalMinimum_i16(0)
PhysicalMaximum_i16(100) // Bytes 4/5 in report
Usage_GD_Y
Input(Var|Abs)
) // Bytes 6/7 in report
LogicalMinimum_i16(0)
LogicalMaximum_i16(8192)
Usage_Dig_TipPressure
Input(Var|Abs)
)
)
UsagePage_GenericDesktop
Usage_GD_Keypad
CollectionApplication( // Byte 0
ReportId(PAD_REPORT_ID)
LogicalMinimum_i8(0)
LogicalMaximum_i8(1)
UsagePage_Digitizers
Usage_Dig_TabletFunctionKeys
CollectionPhysical( // Byte 1 are the buttons
Usage_Dig_BarrelSwitch // BTN_STYLUS, needed so we get to be a tablet pad
ReportCount(1)
ReportSize(1)
Input(Var|Abs)
ReportCount(7) // Padding
Input(Const) // Bytes 2/3 - x/y just exist so we get to be a tablet pad
UsagePage_GenericDesktop
Usage_GD_X
Usage_GD_Y
ReportCount(2)
ReportSize(8)
Input(Var|Abs) // Byte 4 is the button state
UsagePage_Button
UsageMinimum_i8(0x1)
UsageMaximum_i8(0x6)
LogicalMinimum_i8(0x0)
LogicalMaximum_i8(0x1)
ReportCount(6)
ReportSize(1)
Input(Var|Abs)
ReportCount(2)
Input(Const) // Byte 5 is the wheel
UsagePage_GenericDesktop
Usage_GD_Wheel
LogicalMinimum_i8(-1)
LogicalMaximum_i8(1)
ReportCount(1)
ReportSize(8)
Input(Var|Rel)
) // Make sure we match our original report length
FixedSizeVendorReport(VENDOR_REPORT_LENGTH)
)
};
/* If we have a firmware ID and it matches our expected prefix, we *disablethedefaultpad/pennodes.Theywon'tsendevents *butcauseduplicatedevices.
*/
have_fw_id = __builtin_memcmp(UDEV_PROP_HUION_FIRMWARE_ID,
EXPECTED_FIRMWARE_ID, sizeof(EXPECTED_FIRMWARE_ID) - 1) == 0; if (rdesc_size == PAD_REPORT_DESCRIPTOR_LENGTH) { if (have_fw_id) {
__builtin_memcpy(data, disabled_rdesc_pad, sizeof(disabled_rdesc_pad)); returnsizeof(disabled_rdesc_pad);
}
__builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad)); returnsizeof(fixed_rdesc_pad);
} if (rdesc_size == PEN_REPORT_DESCRIPTOR_LENGTH) { if (have_fw_id) {
__builtin_memcpy(data, disabled_rdesc_pen, sizeof(disabled_rdesc_pen)); returnsizeof(disabled_rdesc_pen);
}
__builtin_memcpy(data, fixed_rdesc_pen, sizeof(fixed_rdesc_pen)); returnsizeof(fixed_rdesc_pen);
} /* Always fix the vendor mode so the tablet will work even if nothing sets *theudevproperty(e.g.huion-switcherrunmanually)
*/ if (rdesc_size == VENDOR_REPORT_DESCRIPTOR_LENGTH) {
__builtin_memcpy(data, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor)); returnsizeof(fixed_rdesc_vendor);
/* Only sent if tablet is in default mode */ if (data[0] == PAD_REPORT_ID) { /* Nicely enough, this device only supports one button down at a time so *thereportsareeasytomatch.Buttonsnumberedfromthetop *Buttonreleased:0300000000000000 *Button1:0300050000000000->b *Button2:03000c0000000000->i *Button3:0300080000000000->e *Button4:0301160000000000->CtrlS *Button5:03002c0000000000->space *Button6:03051d0000000000->CtrlAltZ * *Wheeldown:03012d0000000000->Ctrl- *Wheelup:03012e0000000000->Ctrl=
*/
__u8 button = 0;
__u8 wheel = 0;
/* Nothing to do for the PEN_REPORT_ID, it's already mapped */
/* Only sent if tablet is in raw mode */ if (data[0] == VENDOR_REPORT_ID) { /* Pad reports */ if (data[1] & 0x20) { /* See fixed_rdesc_pad */ struct pad_report {
__u8 report_id;
__u8 btn_stylus;
__u8 x;
__u8 y;
__u8 buttons;
__u8 wheel;
} __attribute__((packed)) *pad_report;
__u8 wheel = 0;
/* Wheel report */ if (data[1] == 0xf1) { if (data[5] == 2)
wheel = 0xff; else
wheel = data[5];
} else { /* data[4] are the buttons, mapped correctly */
last_button_state = data[4];
wheel = 0; // wheel
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.