diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk
index c88ce36011c8..7ad1cf4bde96 100644
--- a/builddefs/common_features.mk
+++ b/builddefs/common_features.mk
@@ -855,6 +855,14 @@ ifeq ($(strip $(JOYSTICK_ENABLE)), yes)
endif
endif
+FRAMEWORK_TOUCHPAD_ENABLE ?= no
+ifeq ($(strip $(FRAMEWORK_TOUCHPAD_ENABLE)), yes)
+ OPT_DEFS += -DFRAMEWORK_TOUCHPAD_ENABLE
+ SRC += $(QUANTUM_DIR)/framework_touchpad.c
+
+ I2C_DRIVER_REQUIRED = yes
+endif
+
USBPD_ENABLE ?= no
VALID_USBPD_DRIVER_TYPES = custom vendor
USBPD_DRIVER ?= vendor
diff --git a/quantum/framework_touchpad.c b/quantum/framework_touchpad.c
new file mode 100644
index 000000000000..2f093e533868
--- /dev/null
+++ b/quantum/framework_touchpad.c
@@ -0,0 +1,48 @@
+/* Copyright 2025
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "framework_touchpad.h"
+#include "i2c_master.h"
+#include "print.h"
+
+#define FRAMEWORK_TOUCHPAD_I2C_ADDRESS (0x2c << 1)
+
+void framework_touchpad_init(void) {
+ i2c_init();
+}
+
+void framework_touchpad_task(void) {
+ int length = 0;
+ int status = I2C_STATUS_SUCCESS;
+ uint8_t buffer[37] = {0};
+ uint8_t report[34] = {0};
+
+ status = i2c_receive(FRAMEWORK_TOUCHPAD_I2C_ADDRESS, buffer, 1, 100);
+ length = buffer[0];
+ if (status != I2C_STATUS_SUCCESS || buffer[0] <= 0) {
+ return;
+ }
+
+ status = i2c_receive(FRAMEWORK_TOUCHPAD_I2C_ADDRESS, buffer, length, 100);
+ if (status != I2C_STATUS_SUCCESS || buffer[2] != 0x01) {
+ return;
+ }
+
+ memcpy(report, buffer + 3, 34);
+
+ void host_framework_touchpad_send(uint8_t(*report)[34]);
+ host_framework_touchpad_send(&report);
+}
\ No newline at end of file
diff --git a/quantum/framework_touchpad.h b/quantum/framework_touchpad.h
new file mode 100644
index 000000000000..0656ec329626
--- /dev/null
+++ b/quantum/framework_touchpad.h
@@ -0,0 +1,27 @@
+/* Copyright 2025
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+/**
+ * \brief Handle the initialization of the subsystem.
+ */
+void framework_touchpad_init(void);
+
+/**
+ * \brief Handle various subsystem background tasks.
+ */
+void framework_touchpad_task(void);
\ No newline at end of file
diff --git a/quantum/keyboard.c b/quantum/keyboard.c
index d7836cf36e00..5c097777421c 100644
--- a/quantum/keyboard.c
+++ b/quantum/keyboard.c
@@ -92,6 +92,9 @@ along with this program. If not, see .
#ifdef JOYSTICK_ENABLE
# include "joystick.h"
#endif
+#ifdef FRAMEWORK_TOUCHPAD_ENABLE
+# include "framework_touchpad.h"
+#endif
#ifdef HD44780_ENABLE
# include "hd44780.h"
#endif
@@ -469,6 +472,9 @@ void keyboard_init(void) {
#ifdef JOYSTICK_ENABLE
joystick_init();
#endif
+#ifdef FRAMEWORK_TOUCHPAD_ENABLE
+ framework_touchpad_init();
+#endif
#ifdef SLEEP_LED_ENABLE
sleep_led_init();
#endif
@@ -742,6 +748,10 @@ void keyboard_task(void) {
joystick_task();
#endif
+#ifdef FRAMEWORK_TOUCHPAD_ENABLE
+ framework_touchpad_task();
+#endif
+
#ifdef BLUETOOTH_ENABLE
bluetooth_task();
#endif
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 9db88a54d4ba..70cec38e692b 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -194,6 +194,10 @@ extern layer_state_t layer_state;
# include "digitizer.h"
#endif
+#ifdef FRAMEWORK_TOUCHPAD_ENABLE
+# include "framework_touchpad.h"
+#endif
+
#ifdef VIA_ENABLE
# include "via.h"
#endif
diff --git a/tmk_core/protocol.mk b/tmk_core/protocol.mk
index 8f019765484a..ff9eafbbb42f 100644
--- a/tmk_core/protocol.mk
+++ b/tmk_core/protocol.mk
@@ -92,6 +92,14 @@ ifeq ($(strip $(DIGITIZER_ENABLE)), yes)
endif
endif
+ifeq ($(strip $(FRAMEWORK_TOUCHPAD_ENABLE)), yes)
+ OPT_DEFS += -DFRAMEWORK_TOUCHPAD_ENABLE
+ ifeq ($(strip $(SHARED_EP_ENABLE)), yes)
+ OPT_DEFS += -DFRAMEWORK_TOUCHPAD_SHARED_EP
+ SHARED_EP_ENABLE = yes
+ endif
+endif
+
ifeq ($(strip $(SHARED_EP_ENABLE)), yes)
OPT_DEFS += -DSHARED_EP_ENABLE
endif
diff --git a/tmk_core/protocol/chibios/usb_endpoints.c b/tmk_core/protocol/chibios/usb_endpoints.c
index 856df6242603..5f0bd2382e30 100644
--- a/tmk_core/protocol/chibios/usb_endpoints.c
+++ b/tmk_core/protocol/chibios/usb_endpoints.c
@@ -64,6 +64,10 @@ usb_endpoint_in_t usb_endpoints_in[USB_ENDPOINT_IN_COUNT] = {
[USB_ENDPOINT_IN_DIGITIZER] = QMK_USB_ENDPOINT_IN(USB_EP_MODE_TYPE_INTR, DIGITIZER_EPSIZE, DIGITIZER_IN_EPNUM, DIGITIZER_IN_CAPACITY, NULL, QMK_USB_REPORT_STORAGE_DEFAULT(sizeof(report_digitizer_t))),
#endif
+#if defined(FRAMEWORK_TOUCHPAD_ENABLE) && !defined(FRAMEWORK_TOUCHPAD_SHARED_EP)
+ [USB_ENDPOINT_IN_FRAMEWORK_TOUCHPAD] = QMK_USB_ENDPOINT_IN(USB_EP_MODE_TYPE_INTR, DIGITIZER_EPSIZE, DIGITIZER_IN_EPNUM, DIGITIZER_IN_CAPACITY, NULL, QMK_USB_REPORT_STORAGE_DEFAULT(sizeof(report_digitizer_t))),
+#endif
+
#if defined(CONSOLE_ENABLE)
# if defined(USB_ENDPOINTS_ARE_REORDERABLE)
[USB_ENDPOINT_IN_CONSOLE] = QMK_USB_ENDPOINT_IN_SHARED(USB_EP_MODE_TYPE_INTR, CONSOLE_EPSIZE, CONSOLE_IN_EPNUM, CONSOLE_IN_CAPACITY, NULL, QMK_USB_REPORT_STORAGE_DEFAULT(CONSOLE_EPSIZE)),
@@ -135,6 +139,10 @@ usb_endpoint_in_lut_t usb_endpoint_interface_lut[TOTAL_INTERFACES] = {
#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP)
[DIGITIZER_INTERFACE] = USB_ENDPOINT_IN_DIGITIZER,
#endif
+
+#if defined(FRAMEWORK_TOUCHPAD_ENABLE) && !defined(FRAMEWORK_TOUCHPAD_SHARED_EP)
+ [FRAMEWORK_TOUCHPAD_INTERFACE] = USB_ENDPOINT_IN_FRAMEWORK_TOUCHPAD,
+#endif
};
usb_endpoint_out_t usb_endpoints_out[USB_ENDPOINT_OUT_COUNT] = {
diff --git a/tmk_core/protocol/chibios/usb_endpoints.h b/tmk_core/protocol/chibios/usb_endpoints.h
index a4e5ed88fce3..9d234e6ec909 100644
--- a/tmk_core/protocol/chibios/usb_endpoints.h
+++ b/tmk_core/protocol/chibios/usb_endpoints.h
@@ -82,6 +82,10 @@ typedef enum {
USB_ENDPOINT_IN_DIGITIZER,
#endif
+#if defined(FRAMEWORK_TOUCHPAD_ENABLE) && !defined(FRAMEWORK_TOUCHPAD_SHARED_EP)
+ USB_ENDPOINT_IN_FRAMEWORK_TOUCHPAD,
+#endif
+
#if defined(CONSOLE_ENABLE)
USB_ENDPOINT_IN_CONSOLE,
#endif
@@ -116,6 +120,9 @@ typedef enum {
# if defined(DIGITIZER_SHARED_EP)
USB_ENDPOINT_IN_DIGITIZER = USB_ENDPOINT_IN_SHARED,
# endif
+# if defined(FRAMEWORK_TOUCHPAD_SHARED_EP)
+ USB_ENDPOINT_IN_FRAMEWORK_TOUCHPAD = USB_ENDPOINT_IN_SHARED,
+# endif
#endif
} usb_endpoint_in_lut_t;
diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c
index 5a5354416f48..4fb807959fd2 100644
--- a/tmk_core/protocol/chibios/usb_main.c
+++ b/tmk_core/protocol/chibios/usb_main.c
@@ -497,6 +497,12 @@ void send_digitizer(report_digitizer_t *report) {
#endif
}
+void send_framework_touchpad(report_framework_touchpad_t *report) {
+#ifdef FRAMEWORK_TOUCHPAD_ENABLE
+ send_report(USB_ENDPOINT_IN_FRAMEWORK_TOUCHPAD, report, sizeof(report_framework_touchpad_t));
+#endif
+}
+
/* ---------------------------------------------------------
* Console functions
* ---------------------------------------------------------
diff --git a/tmk_core/protocol/host.c b/tmk_core/protocol/host.c
index df805c827c2a..64232ec52738 100644
--- a/tmk_core/protocol/host.c
+++ b/tmk_core/protocol/host.c
@@ -26,6 +26,10 @@ along with this program. If not, see .
# include "digitizer.h"
#endif
+#ifdef FRAMEWORK_TOUCHPAD_ENABLE
+# include "framework_touchpad.h"
+#endif
+
#ifdef JOYSTICK_ENABLE
# include "joystick.h"
#endif
@@ -240,6 +244,23 @@ void host_digitizer_send(digitizer_t *digitizer) {
__attribute__((weak)) void send_digitizer(report_digitizer_t *report) {}
+#ifdef FRAMEWORK_TOUCHPAD_ENABLE
+void host_framework_touchpad_send(uint8_t (*data)[34]) {
+ report_framework_touchpad_t report = {
+# ifdef FRAMEWORK_TOUCHPAD_SHARED_EP
+ .report_id = REPORT_ID_FRAMEWORK_TOUCHPAD,
+# endif
+ .report = {0},
+ };
+
+ memcpy(report.report, data, 34);
+
+ send_framework_touchpad(&report);
+}
+#endif
+
+__attribute__((weak)) void send_framework_touchpad(report_framework_touchpad_t *report) {}
+
#ifdef PROGRAMMABLE_BUTTON_ENABLE
void host_programmable_button_send(uint32_t data) {
report_programmable_button_t report = {
diff --git a/tmk_core/protocol/host_driver.h b/tmk_core/protocol/host_driver.h
index 8aa38b6dee2c..a364012624b0 100644
--- a/tmk_core/protocol/host_driver.h
+++ b/tmk_core/protocol/host_driver.h
@@ -33,4 +33,5 @@ typedef struct {
void send_joystick(report_joystick_t *report);
void send_digitizer(report_digitizer_t *report);
+void send_framework_touchpad(report_framework_touchpad_t *report);
void send_programmable_button(report_programmable_button_t *report);
diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c
index 81da035f0c03..fe0ca543b4ee 100644
--- a/tmk_core/protocol/lufa/lufa.c
+++ b/tmk_core/protocol/lufa/lufa.c
@@ -385,6 +385,11 @@ void EVENT_USB_Device_ConfigurationChanged(void) {
ConfigSuccess &= Endpoint_ConfigureEndpoint((DIGITIZER_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_INTERRUPT, DIGITIZER_EPSIZE, 1);
#endif
+#if defined(FRAMEWORK_TOUCHPAD_ENABLE) && !defined(FRAMEWORK_TOUCHPAD_SHARED_EP)
+ /* Setup digitizer endpoint */
+ ConfigSuccess &= Endpoint_ConfigureEndpoint((DIGITIZER_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_INTERRUPT, DIGITIZER_EPSIZE, 1);
+#endif
+
usb_device_state_set_configuration(USB_DeviceState == DEVICE_STATE_Configured, USB_Device_ConfigurationNumber);
}
diff --git a/tmk_core/protocol/report.h b/tmk_core/protocol/report.h
index d854f51d5c45..13c8c9a6a50d 100644
--- a/tmk_core/protocol/report.h
+++ b/tmk_core/protocol/report.h
@@ -39,6 +39,7 @@ enum hid_report_ids {
REPORT_ID_NKRO,
REPORT_ID_JOYSTICK,
REPORT_ID_DIGITIZER,
+ REPORT_ID_FRAMEWORK_TOUCHPAD,
REPORT_ID_COUNT = REPORT_ID_DIGITIZER
};
@@ -232,6 +233,13 @@ typedef struct {
uint16_t y;
} PACKED report_digitizer_t;
+typedef struct {
+#ifdef FRAMEWORK_TOUCHPAD_SHARED_EP
+ uint8_t report_id;
+#endif
+ uint8_t report[34];
+} PACKED report_framework_touchpad_t;
+
#if JOYSTICK_AXIS_RESOLUTION > 8
typedef int16_t joystick_axis_t;
#else
diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c
index c7fb660b65d6..c3c4ebc2c066 100644
--- a/tmk_core/protocol/usb_descriptor.c
+++ b/tmk_core/protocol/usb_descriptor.c
@@ -332,6 +332,191 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
# endif
#endif
+#ifdef FRAMEWORK_TOUCHPAD_ENABLE
+# ifndef FRAMEWORK_TOUCHPAD_SHARED_EP
+const USB_Descriptor_HIDReport_Datatype_t PROGMEM TouchPadReport[] = {
+# elif !defined(SHARED_REPORT_STARTED)
+const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
+# define SHARED_REPORT_STARTED
+# endif
+ HID_RI_USAGE_PAGE(8, 0x0D), // Usage Page (Digitizer)
+ HID_RI_USAGE(8, 0x05), // Usage (Touch Pad)
+ HID_RI_COLLECTION(8, 0x01), // Collection (Application)
+# ifdef FRAMEWORK_TOUCHPAD_SHARED_EP
+ HID_RI_REPORT_ID(8, REPORT_ID_FRAMEWORK_TOUCHPAD),
+# endif
+
+#define FINGER(FINGER_NUMBER) \
+ HID_RI_USAGE_PAGE(8, 0x0D), /* Usage Page (Digitizer) */ \
+ HID_RI_USAGE(8, 0x22), /* Usage (Finger) */ \
+ HID_RI_COLLECTION(8, 0x02), /* Collection (Logical) */ \
+ HID_RI_USAGE(8, 0x47), /* Usage (0x47) */ \
+ HID_RI_USAGE(8, 0x42), /* Usage (Tip Switch) */ \
+ HID_RI_LOGICAL_MINIMUM(8, 0x00), /* Logical Minimum (0) */ \
+ HID_RI_LOGICAL_MAXIMUM(8, 0x01), /* Logical Maximum (1) */ \
+ HID_RI_REPORT_SIZE(8, 0x01), /* Report Size (1) */ \
+ HID_RI_REPORT_COUNT(8, 0x02), /* Report Count (2) */ \
+ HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION), /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */ \
+ HID_RI_REPORT_COUNT(8, 0x06), /* Report Count (6) */ \
+ HID_RI_INPUT(8, HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION), /* Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */ \
+ HID_RI_USAGE(8, 0x51), /* Usage (0x51) */ \
+ HID_RI_LOGICAL_MAXIMUM(8, 0x0F), /* Logical Maximum (15) */ \
+ HID_RI_REPORT_SIZE(8, 0x08), /* Report Size (8) */ \
+ HID_RI_REPORT_COUNT(8, 0x01), /* Report Count (1) */ \
+ HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION), /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */ \
+ HID_RI_USAGE_PAGE(8, 0x01), /* Usage Page (Generic Desktop Ctrls) */ \
+ HID_RI_USAGE(8, 0x30), /* Usage (X) */ \
+ HID_RI_REPORT_SIZE(8, 0x10), /* Report Size (16) */ \
+ HID_RI_UNIT_EXPONENT(8, 0x0E), /* Unit Exponent (-2) */ \
+ HID_RI_UNIT(8, 0x11), /* Unit (System: SI Linear, Length: Centimeter) */ \
+ HID_RI_PHYSICAL_MINIMUM(8, 0x00), /* Physical Minimum (0) */ \
+ HID_RI_PHYSICAL_MAXIMUM(16, 0x045A), /* Physical Maximum (1114) */ \
+ HID_RI_LOGICAL_MAXIMUM(32, 0x00000539), /* Logical Maximum (1336) */ \
+ HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION), /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */ \
+ HID_RI_USAGE(8, 0x31), /* Usage (Y) */ \
+ HID_RI_PHYSICAL_MAXIMUM(16, 0x02DA), /* Physical Maximum (730) */ \
+ HID_RI_LOGICAL_MAXIMUM(32, 0x0000036C), /* Logical Maximum (875) */ \
+ HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION), /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */ \
+ HID_RI_END_COLLECTION(0), /* End Collection */
+
+ FINGER(1)
+ FINGER(2)
+ FINGER(3)
+ FINGER(4)
+ FINGER(5)
+
+#undef FINGER
+
+ HID_RI_USAGE_PAGE(8, 0x0D), // Usage Page (Digitizer)
+ HID_RI_USAGE(8, 0x54), // Usage (0x54)
+ HID_RI_LOGICAL_MINIMUM(8, 0x00), // Logical Minimum (0)
+ HID_RI_LOGICAL_MAXIMUM(8, 0x05), // Logical Maximum (5)
+ HID_RI_REPORT_SIZE(8, 0x08), // Report Size (8)
+ HID_RI_REPORT_COUNT(8, 0x01), // Report Count (1)
+ HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION), // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ HID_RI_USAGE_PAGE(8, 0x09), // Usage Page (Button)
+ HID_RI_USAGE(8, 0x01), // Usage (0x01)
+ HID_RI_USAGE(8, 0x02), // Usage (0x02)
+ HID_RI_USAGE(8, 0x03), // Usage (0x03)
+ HID_RI_LOGICAL_MINIMUM(8, 0x00), // Logical Minimum (0)
+ HID_RI_LOGICAL_MAXIMUM(8, 0x01), // Logical Maximum (1)
+ HID_RI_REPORT_SIZE(8, 0x01), // Report Size (1)
+ HID_RI_REPORT_COUNT(8, 0x03), // Report Count (3)
+ HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION), // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ HID_RI_REPORT_COUNT(8, 0x05), // Report Count (5)
+ HID_RI_INPUT(8, HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION), // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ HID_RI_USAGE_PAGE(8, 0x0D), // Usage Page (Digitizer)
+ HID_RI_USAGE(8, 0x56), // Usage (0x56)
+ HID_RI_UNIT_EXPONENT(8, 0x0C), // Unit Exponent (-4)
+ HID_RI_UNIT(16, 0x1001), // Unit (System: SI Linear, Time: Seconds)
+ HID_RI_PHYSICAL_MINIMUM(8, 0x00), // Physical Minimum (0)
+ HID_RI_PHYSICAL_MAXIMUM(32, 0x0000FFFF), // Physical Maximum (65534)
+ HID_RI_LOGICAL_MINIMUM(8, 0x00), // Logical Minimum (0)
+ HID_RI_LOGICAL_MAXIMUM(32, 0x0000FFFF), // Logical Maximum (65534)
+ HID_RI_REPORT_SIZE(8, 0x10), // Report Size (16)
+ HID_RI_REPORT_COUNT(8, 0x01), // Report Count (1)
+ HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION), // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ HID_RI_USAGE_PAGE(8, 0x0D), // Usage Page (Digitizer)
+ HID_RI_USAGE(8, 0x55), // Usage (0x55)
+ HID_RI_LOGICAL_MINIMUM(8, 0x00), // Logical Minimum (0)
+ HID_RI_LOGICAL_MAXIMUM(8, 0x05), // Logical Maximum (5)
+ HID_RI_REPORT_SIZE(8, 0x08), // Report Size (8)
+ HID_RI_REPORT_COUNT(8, 0x01), // Report Count (1)
+ HID_RI_REPORT_ID(8, 0x03), // Report ID (3)
+ HID_RI_FEATURE(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION | HID_IOF_NON_VOLATILE), // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ HID_RI_USAGE_PAGE(8, 0x0D), // Usage Page (Digitizer)
+ HID_RI_USAGE(8, 0x59), // Usage (0x59)
+ HID_RI_LOGICAL_MINIMUM(8, 0x00), // Logical Minimum (0)
+ HID_RI_LOGICAL_MAXIMUM(8, 0x0F), // Logical Maximum (15)
+ HID_RI_REPORT_SIZE(8, 0x08), // Report Size (8)
+ HID_RI_REPORT_COUNT(8, 0x01), // Report Count (1)
+ HID_RI_REPORT_ID(8, 0x04), // Report ID (4)
+ HID_RI_FEATURE(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION | HID_IOF_NON_VOLATILE), // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ HID_RI_USAGE_PAGE(16, 0xFF00), // Usage Page (Vendor Defined 0xFF00)
+ HID_RI_REPORT_ID(8, 0x05), // Report ID (5)
+ HID_RI_REPORT_SIZE(8, 0x08), // Report Size (8)
+ HID_RI_LOGICAL_MINIMUM(8, 0x00), // Logical Minimum (0)
+ HID_RI_USAGE(8, 0xC6), // Usage (0xC6)
+ HID_RI_LOGICAL_MAXIMUM(8, 0x08), // Logical Maximum (8)
+ HID_RI_REPORT_COUNT(8, 0x01), // Report Count (1)
+ HID_RI_FEATURE(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION | HID_IOF_NON_VOLATILE), // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ HID_RI_USAGE(8, 0xC7), // Usage (0xC7)
+ HID_RI_LOGICAL_MAXIMUM(16, 0x00FF), // Logical Maximum (255)
+ HID_RI_REPORT_COUNT(8, 0x20), // Report Count (32)
+ HID_RI_FEATURE(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION | HID_IOF_NON_VOLATILE), // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ HID_RI_END_COLLECTION(0), // End Collection
+
+ HID_RI_USAGE_PAGE(8, 0x0D), // Usage Page (Digitizer)
+ HID_RI_USAGE(8, 0x0E), // Usage (0x0E)
+ HID_RI_COLLECTION(8, 0x01), // Collection (Application)
+ HID_RI_USAGE_PAGE(8, 0x0D), // Usage Page (Digitizer)
+ HID_RI_USAGE(8, 0x22), // Usage (Finger)
+ HID_RI_COLLECTION(8, 0x02), // Collection (Logical)
+ HID_RI_USAGE(8, 0x52), // Usage (0x52)
+ HID_RI_LOGICAL_MINIMUM(8, 0x00), // Logical Minimum (0)
+ HID_RI_LOGICAL_MAXIMUM(8, 0x0A), // Logical Maximum (10)
+ HID_RI_REPORT_SIZE(8, 0x08), // Report Size (8)
+ HID_RI_REPORT_COUNT(8, 0x01), // Report Count (1)
+ HID_RI_REPORT_ID(8, 0x06), // Report ID (6)
+ HID_RI_FEATURE(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION | HID_IOF_NON_VOLATILE), // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ HID_RI_END_COLLECTION(0), // End Collection
+ HID_RI_USAGE_PAGE(8, 0x0D), // Usage Page (Digitizer)
+ HID_RI_USAGE(8, 0x22), // Usage (Finger)
+ HID_RI_COLLECTION(8, 0x00), // Collection (Physical)
+ HID_RI_USAGE(8, 0x57), // Usage (0x57)
+ HID_RI_USAGE(8, 0x58), // Usage (0x58)
+ HID_RI_LOGICAL_MINIMUM(8, 0x00), // Logical Minimum (0)
+ HID_RI_LOGICAL_MAXIMUM(8, 0x01), // Logical Maximum (1)
+ HID_RI_REPORT_SIZE(8, 0x01), // Report Size (1)
+ HID_RI_REPORT_COUNT(8, 0x02), // Report Count (2)
+ HID_RI_REPORT_ID(8, 0x07), // Report ID (7)
+ HID_RI_FEATURE(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION | HID_IOF_NON_VOLATILE), // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ HID_RI_REPORT_COUNT(8, 0x06), // Report Count (6)
+ HID_RI_FEATURE(8, HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION | HID_IOF_NON_VOLATILE), // Feature (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ HID_RI_END_COLLECTION(0), // End Collection
+ HID_RI_USAGE_PAGE(8, 0x0D), // Usage Page (Digitizer)
+ HID_RI_USAGE(8, 0x60), // Usage (0x60)
+ HID_RI_LOGICAL_MINIMUM(8, 0x00), // Logical Minimum (0)
+ HID_RI_LOGICAL_MAXIMUM(8, 0x01), // Logical Maximum (1)
+ HID_RI_REPORT_SIZE(8, 0x01), // Report Size (1)
+ HID_RI_REPORT_COUNT(8, 0x01), // Report Count (1)
+ HID_RI_REPORT_ID(8, 0x08), // Report ID (8)
+ HID_RI_FEATURE(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION | HID_IOF_NON_VOLATILE), // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ HID_RI_REPORT_COUNT(8, 0x07), // Report Count (7)
+ HID_RI_FEATURE(8, HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION | HID_IOF_NON_VOLATILE), // Feature (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ HID_RI_END_COLLECTION(0), // End Collection
+ HID_RI_USAGE_PAGE(16, 0xFF00), // Usage Page (Vendor Defined 0xFF00)
+ HID_RI_USAGE(8, 0x01), // Usage (0x01)
+ HID_RI_COLLECTION(8, 0x01), // Collection (Application)
+ HID_RI_REPORT_ID(8, 0x42), // Report ID (66)
+ HID_RI_USAGE(8, 0x06), // Usage (0x06)
+ HID_RI_LOGICAL_MINIMUM(8, 0x00), // Logical Minimum (0)
+ HID_RI_LOGICAL_MAXIMUM(16, 0x00FF), // Logical Maximum (255)
+ HID_RI_REPORT_SIZE(8, 0x08), // Report Size (8)
+ HID_RI_REPORT_COUNT(8, 0x03), // Report Count (3)
+ HID_RI_FEATURE(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION | HID_IOF_NON_VOLATILE), // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ HID_RI_USAGE_PAGE(16, 0xFF00), // Usage Page (Vendor Defined 0xFF00)
+ HID_RI_USAGE(8, 0x05), // Usage (0x05)
+ HID_RI_LOGICAL_MINIMUM(8, 0x00), // Logical Minimum (0)
+ HID_RI_LOGICAL_MAXIMUM(16, 0x00FF), // Logical Maximum (255)
+ HID_RI_REPORT_SIZE(8, 0x08), // Report Size (8)
+ HID_RI_REPORT_COUNT(16, 0x0100), // Report Count (256)
+ HID_RI_REPORT_ID(8, 0x41), // Report ID (65)
+ HID_RI_FEATURE(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION | HID_IOF_NON_VOLATILE), // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ HID_RI_REPORT_ID(8, 0x43), // Report ID (67)
+ HID_RI_USAGE(8, 0x06), // Usage (0x06)
+ HID_RI_LOGICAL_MINIMUM(8, 0x00), // Logical Minimum (0)
+ HID_RI_LOGICAL_MAXIMUM(16, 0x00FF), // Logical Maximum (255)
+ HID_RI_REPORT_SIZE(8, 0x08), // Report Size (8)
+ HID_RI_REPORT_COUNT(8, 0x03), // Report Count (3)
+ HID_RI_FEATURE(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NO_WRAP | HID_IOF_LINEAR | HID_IOF_PREFERRED_STATE | HID_IOF_NO_NULL_POSITION | HID_IOF_NON_VOLATILE), // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ HID_RI_END_COLLECTION(0), // End Collection
+
+# ifndef FRAMEWORK_TOUCHPAD_SHARED_EP
+};
+# endif
+#endif
+
#if defined(SHARED_EP_ENABLE) && !defined(SHARED_REPORT_STARTED)
const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
#endif
@@ -1073,6 +1258,46 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = {
.PollingIntervalMS = USB_POLLING_INTERVAL_MS
},
#endif
+
+#if defined(FRAMEWORK_TOUCHPAD_ENABLE) && !defined(FRAMEWORK_TOUCHPAD_SHARED_EP)
+ /*
+ * Digitizer
+ */
+ .Framework_Touchpad_Interface = {
+ .Header = {
+ .Size = sizeof(USB_Descriptor_Interface_t),
+ .Type = DTYPE_Interface
+ },
+ .InterfaceNumber = FRAMEWORK_TOUCHPAD_INTERFACE,
+ .AlternateSetting = 0x00,
+ .TotalEndpoints = 1,
+ .Class = HID_CSCP_HIDClass,
+ .SubClass = HID_CSCP_NonBootSubclass,
+ .Protocol = HID_CSCP_NonBootProtocol,
+ .InterfaceStrIndex = NO_DESCRIPTOR
+ },
+ .Framework_Touchpad_HID = {
+ .Header = {
+ .Size = sizeof(USB_HID_Descriptor_HID_t),
+ .Type = HID_DTYPE_HID
+ },
+ .HIDSpec = VERSION_BCD(1, 1, 1),
+ .CountryCode = 0x00,
+ .TotalReportDescriptors = 1,
+ .HIDReportType = HID_DTYPE_Report,
+ .HIDReportLength = sizeof(TouchPadReport)
+ },
+ .Framework_Touchpad_INEndpoint = {
+ .Header = {
+ .Size = sizeof(USB_Descriptor_Endpoint_t),
+ .Type = DTYPE_Endpoint
+ },
+ .EndpointAddress = (ENDPOINT_DIR_IN | DIGITIZER_IN_EPNUM),
+ .Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
+ .EndpointSize = DIGITIZER_EPSIZE,
+ .PollingIntervalMS = USB_POLLING_INTERVAL_MS
+ },
+#endif
};
/*
diff --git a/tmk_core/protocol/usb_descriptor.h b/tmk_core/protocol/usb_descriptor.h
index 1de8c5ec88a3..775a6e49446d 100644
--- a/tmk_core/protocol/usb_descriptor.h
+++ b/tmk_core/protocol/usb_descriptor.h
@@ -144,6 +144,13 @@ typedef struct {
USB_HID_Descriptor_HID_t Digitizer_HID;
USB_Descriptor_Endpoint_t Digitizer_INEndpoint;
#endif
+
+#if defined(FRAMEWORK_TOUCHPAD_ENABLE) && !defined(FRAMEWORK_TOUCHPAD_SHARED_EP)
+ // Touchpad HID Interface
+ USB_Descriptor_Interface_t Framework_Touchpad_Interface;
+ USB_HID_Descriptor_HID_t Framework_Touchpad_HID;
+ USB_Descriptor_Endpoint_t Framework_Touchpad_INEndpoint;
+#endif
} USB_Descriptor_Configuration_t;
/*
@@ -193,6 +200,10 @@ enum usb_interfaces {
#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP)
DIGITIZER_INTERFACE,
#endif
+
+#if defined(FRAMEWORK_TOUCHPAD_ENABLE) && !defined(FRAMEWORK_TOUCHPAD_SHARED_EP)
+ FRAMEWORK_TOUCHPAD_INTERFACE,
+#endif
TOTAL_INTERFACES
};
@@ -269,6 +280,14 @@ enum usb_endpoints {
# define DIGITIZER_IN_EPNUM SHARED_IN_EPNUM
# endif
#endif
+
+#ifdef FRAMEWORK_TOUCHPAD_ENABLE
+# if !defined(FRAMEWORK_TOUCHPAD_SHARED_EP)
+ DIGITIZER_IN_EPNUM = NEXT_EPNUM,
+# else
+# define DIGITIZER_IN_EPNUM SHARED_IN_EPNUM
+# endif
+#endif
};
#ifdef PROTOCOL_LUFA