diff --git a/common_features.mk b/common_features.mk
index e442222eae..493aab6353 100644
--- a/common_features.mk
+++ b/common_features.mk
@@ -695,6 +695,11 @@ ifeq ($(strip $(JOYSTICK_ENABLE)), digital)
OPT_DEFS += -DDIGITAL_JOYSTICK_ENABLE
endif
+DIGITIZER_ENABLE ?= no
+ifneq ($(strip $(DIGITIZER_ENABLE)), no)
+ SRC += $(QUANTUM_DIR)/digitizer.c
+endif
+
USBPD_ENABLE ?= no
VALID_USBPD_DRIVER_TYPES = custom vendor
USBPD_DRIVER ?= vendor
diff --git a/docs/_summary.md b/docs/_summary.md
index 48115cef46..2f6309e41d 100644
--- a/docs/_summary.md
+++ b/docs/_summary.md
@@ -108,6 +108,7 @@
* [Bluetooth](feature_bluetooth.md)
* [Bootmagic Lite](feature_bootmagic.md)
* [Custom Matrix](custom_matrix.md)
+ * [Digitizer](feature_digitizer.md)
* [DIP Switch](feature_dip_switch.md)
* [Encoders](feature_encoders.md)
* [Haptic Feedback](feature_haptic_feedback.md)
diff --git a/docs/feature_digitizer.md b/docs/feature_digitizer.md
new file mode 100644
index 0000000000..9b6aeddbaa
--- /dev/null
+++ b/docs/feature_digitizer.md
@@ -0,0 +1,35 @@
+## Digitizer
+
+The digitizer HID interface allows setting the mouse cursor position at absolute coordinates, unlike the Pointing Device feature that applies relative displacements.
+
+To enable the digitizer interface, add the following line to your rules.mk:
+
+```makefile
+DIGITIZER_ENABLE = yes
+```
+
+In order to change the mouse cursor position from your keymap.c file, include the digitizer header :
+
+```c
+#include "digitizer.h"
+```
+
+This gives you access to the `digitizer` structure which members allow you to change the cursor position.
+
+The coordinates are normalized, meaning there value must be set between 0 and 1. For the `x` coordinate, the value `0` is the leftmost position, whereas the value `1` is the rightmost position.
+For the `y` coordinate, `0` is at the top and `1` at the bottom.
+
+Here is an example setting the cursor in the middle of the screen:
+
+```c
+digitizer_t digitizer;
+digitizer.x = 0.5;
+digitizer.y = 0.5;
+digitizer.tipswitch = 0;
+digitizer.inrange = 1;
+digitizer_set_report(digitizer);
+```
+
+The `tipswitch` member triggers what equates to a click when set to `1`. The `inrange` member is required for the change in coordinates to be taken. It can then be set to `0` in a new report to signal the end of the digitizer interaction, but it is not strictly required.
+
+Once all members are set to the desired value, the `status` member needs its bitmask `DZ_UPDATED` to be set so the report is sent during the next main loop iteration.
diff --git a/keyboards/handwired/onekey/keymaps/digitizer/keymap.c b/keyboards/handwired/onekey/keymaps/digitizer/keymap.c
new file mode 100644
index 0000000000..6b304e86fe
--- /dev/null
+++ b/keyboards/handwired/onekey/keymaps/digitizer/keymap.c
@@ -0,0 +1,38 @@
+ /* Copyright 2021 QMK
+ *
+ * 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 QMK_KEYBOARD_H
+
+#include "digitizer.h"
+
+#include "math.h"
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {LAYOUT_ortho_1x1(KC_A)};
+
+uint32_t timer = 0;
+
+void matrix_scan_user() {
+ if (timer_elapsed32(timer) < 200) {
+ return;
+ }
+
+ timer = timer_read32();
+ digitizer_t digitizer;
+ digitizer.x = 0.5 - 0.2 * cos(timer_read() / 250. / 6.28);
+ digitizer.y = 0.5 - 0.2 * sin(timer_read() / 250. / 6.28);
+ digitizer.tipswitch = 0;
+ digitizer.inrange = 1;
+ digitizer_set_report(digitizer);
+}
diff --git a/keyboards/handwired/onekey/keymaps/digitizer/rules.mk b/keyboards/handwired/onekey/keymaps/digitizer/rules.mk
new file mode 100644
index 0000000000..ea9f9bd9ac
--- /dev/null
+++ b/keyboards/handwired/onekey/keymaps/digitizer/rules.mk
@@ -0,0 +1 @@
+DIGITIZER_ENABLE = yes
\ No newline at end of file
diff --git a/quantum/digitizer.c b/quantum/digitizer.c
new file mode 100644
index 0000000000..e299867429
--- /dev/null
+++ b/quantum/digitizer.c
@@ -0,0 +1,34 @@
+/* Copyright 2021
+ *
+ * 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 "digitizer.h"
+
+digitizer_t digitizerReport = {.tipswitch = 0, .inrange = 0, .id = 0, .x = 0, .y = 0, .status = DZ_INITIALIZED};
+
+__attribute__((weak)) void digitizer_send(void) {
+ if (digitizerReport.status & DZ_UPDATED) {
+ host_digitizer_send(&digitizerReport);
+ digitizerReport.status &= ~DZ_UPDATED;
+ }
+}
+
+__attribute__((weak)) void digitizer_task(void) { digitizer_send(); }
+
+digitizer_t digitizer_get_report(void) { return digitizerReport; }
+
+void digitizer_set_report(digitizer_t newDigitizerReport) {
+ digitizerReport = newDigitizerReport;
+ digitizerReport.status |= DZ_UPDATED;
+}
\ No newline at end of file
diff --git a/quantum/digitizer.h b/quantum/digitizer.h
new file mode 100644
index 0000000000..cef551567e
--- /dev/null
+++ b/quantum/digitizer.h
@@ -0,0 +1,41 @@
+/* Copyright 2021
+ *
+ * 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
+
+#include "quantum.h"
+
+#include
+
+enum digitizer_status { DZ_INITIALIZED = 1, DZ_UPDATED = 2 };
+
+typedef struct {
+ int8_t tipswitch;
+ int8_t inrange;
+ uint8_t id;
+ float x;
+ float y;
+ uint8_t status : 2;
+} digitizer_t;
+
+extern digitizer_t digitizer;
+
+digitizer_t digitizer_get_report(void);
+
+void digitizer_set_report(digitizer_t newDigitizerReport);
+
+void digitizer_task(void);
+
+void host_digitizer_send(digitizer_t *digitizer);
diff --git a/tmk_core/common.mk b/tmk_core/common.mk
index 6c8cf69356..fa907b47b8 100644
--- a/tmk_core/common.mk
+++ b/tmk_core/common.mk
@@ -106,6 +106,19 @@ ifeq ($(strip $(NO_USB_STARTUP_CHECK)), yes)
TMK_COMMON_DEFS += -DNO_USB_STARTUP_CHECK
endif
+ifeq ($(strip $(DIGITIZER_SHARED_EP)), yes)
+ TMK_COMMON_DEFS += -DDIGITIZER_SHARED_EP
+ SHARED_EP_ENABLE = yes
+endif
+
+ifeq ($(strip $(DIGITIZER_ENABLE)), yes)
+ TMK_COMMON_DEFS += -DDIGITIZER_ENABLE
+ ifeq ($(strip $(SHARED_EP_ENABLE)), yes)
+ TMK_COMMON_DEFS += -DDIGITIZER_SHARED_EP
+ SHARED_EP_ENABLE = yes
+ endif
+endif
+
ifeq ($(strip $(SHARED_EP_ENABLE)), yes)
TMK_COMMON_DEFS += -DSHARED_EP_ENABLE
endif
diff --git a/tmk_core/common/host.c b/tmk_core/common/host.c
index a8b391e893..f0c396b189 100644
--- a/tmk_core/common/host.c
+++ b/tmk_core/common/host.c
@@ -22,6 +22,7 @@ along with this program. If not, see .
#include "host.h"
#include "util.h"
#include "debug.h"
+#include "digitizer.h"
#ifdef NKRO_ENABLE
# include "keycode_config.h"
@@ -103,6 +104,24 @@ void host_consumer_send(uint16_t report) {
(*driver->send_consumer)(report);
}
+void host_digitizer_send(digitizer_t *digitizer) {
+ if (!driver) return;
+
+ report_digitizer_t report = {
+#ifdef DIGITIZER_SHARED_EP
+ .report_id = REPORT_ID_DIGITIZER,
+#endif
+ .tip = digitizer->tipswitch & 0x1,
+ .inrange = digitizer->inrange & 0x1,
+ .x = (uint16_t)(digitizer->x * 0x7FFF),
+ .y = (uint16_t)(digitizer->y * 0x7FFF),
+ };
+
+ send_digitizer(&report);
+}
+
+__attribute__((weak)) void send_digitizer(report_digitizer_t *report) {}
+
uint16_t host_last_system_report(void) { return last_system_report; }
uint16_t host_last_consumer_report(void) { return last_consumer_report; }
diff --git a/tmk_core/common/host_driver.h b/tmk_core/common/host_driver.h
index f34a220530..2aebca043d 100644
--- a/tmk_core/common/host_driver.h
+++ b/tmk_core/common/host_driver.h
@@ -30,3 +30,5 @@ typedef struct {
void (*send_system)(uint16_t);
void (*send_consumer)(uint16_t);
} host_driver_t;
+
+void send_digitizer(report_digitizer_t *report);
\ No newline at end of file
diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c
index 28fa97bc8f..fcc51973fd 100644
--- a/tmk_core/common/keyboard.c
+++ b/tmk_core/common/keyboard.c
@@ -106,6 +106,9 @@ along with this program. If not, see .
#if defined(CRC_ENABLE)
# include "crc.h"
#endif
+#ifdef DIGITIZER_ENABLE
+# include "digitizer.h"
+#endif
static uint32_t last_input_modification_time = 0;
uint32_t last_input_activity_time(void) { return last_input_modification_time; }
@@ -537,6 +540,10 @@ MATRIX_LOOP_END:
joystick_task();
#endif
+#ifdef DIGITIZER_ENABLE
+ digitizer_task();
+#endif
+
// update LED
if (led_status != host_keyboard_leds()) {
led_status = host_keyboard_leds();
diff --git a/tmk_core/common/report.h b/tmk_core/common/report.h
index db6370657d..f2223e8063 100644
--- a/tmk_core/common/report.h
+++ b/tmk_core/common/report.h
@@ -30,7 +30,8 @@ enum hid_report_ids {
REPORT_ID_SYSTEM,
REPORT_ID_CONSUMER,
REPORT_ID_NKRO,
- REPORT_ID_JOYSTICK
+ REPORT_ID_JOYSTICK,
+ REPORT_ID_DIGITIZER
};
/* Mouse buttons */
@@ -205,6 +206,17 @@ typedef struct {
int8_t h;
} __attribute__((packed)) report_mouse_t;
+typedef struct {
+#ifdef DIGITIZER_SHARED_EP
+ uint8_t report_id;
+#endif
+ uint8_t tip : 1;
+ uint8_t inrange : 1;
+ uint8_t pad2 : 6;
+ uint16_t x;
+ uint16_t y;
+} __attribute__((packed)) report_digitizer_t;
+
typedef struct {
#if JOYSTICK_AXES_COUNT > 0
# if JOYSTICK_AXES_RESOLUTION > 8
diff --git a/tmk_core/protocol/chibios/main.c b/tmk_core/protocol/chibios/main.c
index 199741594a..e41d6ff195 100644
--- a/tmk_core/protocol/chibios/main.c
+++ b/tmk_core/protocol/chibios/main.c
@@ -65,6 +65,7 @@ void send_keyboard(report_keyboard_t *report);
void send_mouse(report_mouse_t *report);
void send_system(uint16_t data);
void send_consumer(uint16_t data);
+void send_digitizer(report_digitizer_t *report);
/* host struct */
host_driver_t chibios_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer};
diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c
index e5edd74dcb..cc282e6a9b 100644
--- a/tmk_core/protocol/chibios/usb_main.c
+++ b/tmk_core/protocol/chibios/usb_main.c
@@ -315,6 +315,9 @@ typedef struct {
#endif
#ifdef JOYSTICK_ENABLE
usb_driver_config_t joystick_driver;
+#endif
+#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP)
+ usb_driver_config_t digitizer_driver;
#endif
};
usb_driver_config_t array[0];
@@ -360,6 +363,14 @@ static usb_driver_configs_t drivers = {
# define JOYSTICK_OUT_MODE USB_EP_MODE_TYPE_BULK
.joystick_driver = QMK_USB_DRIVER_CONFIG(JOYSTICK, 0, false),
#endif
+
+#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP)
+# define DIGITIZER_IN_CAPACITY 4
+# define DIGITIZER_OUT_CAPACITY 4
+# define DIGITIZER_IN_MODE USB_EP_MODE_TYPE_BULK
+# define DIGITIZER_OUT_MODE USB_EP_MODE_TYPE_BULK
+ .digitizer_driver = QMK_USB_DRIVER_CONFIG(DIGITIZER, 0, false),
+#endif
};
#define NUM_USB_DRIVERS (sizeof(drivers) / sizeof(usb_driver_config_t))
@@ -930,6 +941,23 @@ void send_consumer(uint16_t data) {
#endif
}
+void send_digitizer(report_digitizer_t *report) {
+#ifdef DIGITIZER_ENABLE
+# ifdef DIGITIZER_SHARED_EP
+ osalSysLock();
+ if (usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
+ osalSysUnlock();
+ return;
+ }
+
+ usbStartTransmitI(&USB_DRIVER, DIGITIZER_IN_EPNUM, (uint8_t *)report, sizeof(report_digitizer_t));
+ osalSysUnlock();
+# else
+ chnWrite(&drivers.digitizer_driver.driver, (uint8_t *)report, sizeof(report_digitizer_t));
+# endif
+#endif
+}
+
/* ---------------------------------------------------------
* Console functions
* ---------------------------------------------------------
diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c
index 4ac079e168..8ddb8b1c4b 100644
--- a/tmk_core/protocol/lufa/lufa.c
+++ b/tmk_core/protocol/lufa/lufa.c
@@ -142,9 +142,7 @@ static void send_keyboard(report_keyboard_t *report);
static void send_mouse(report_mouse_t *report);
static void send_system(uint16_t data);
static void send_consumer(uint16_t data);
-host_driver_t lufa_driver = {
- keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer,
-};
+host_driver_t lufa_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer};
#ifdef VIRTSER_ENABLE
// clang-format off
@@ -525,6 +523,11 @@ void EVENT_USB_Device_ConfigurationChanged(void) {
/* Setup joystick endpoint */
ConfigSuccess &= Endpoint_ConfigureEndpoint((JOYSTICK_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_INTERRUPT, JOYSTICK_EPSIZE, 1);
#endif
+
+#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP)
+ /* Setup digitizer endpoint */
+ ConfigSuccess &= Endpoint_ConfigureEndpoint((DIGITIZER_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_INTERRUPT, DIGITIZER_EPSIZE, 1);
+#endif
}
/* FIXME: Expose this table in the docs somehow
@@ -983,6 +986,23 @@ void virtser_send(const uint8_t byte) {
}
#endif
+void send_digitizer(report_digitizer_t *report) {
+#ifdef DIGITIZER_ENABLE
+ uint8_t timeout = 255;
+
+ if (USB_DeviceState != DEVICE_STATE_Configured) return;
+
+ Endpoint_SelectEndpoint(DIGITIZER_IN_EPNUM);
+
+ /* Check if write ready for a polling interval around 10ms */
+ while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
+ if (!Endpoint_IsReadWriteAllowed()) return;
+
+ Endpoint_Write_Stream_LE(report, sizeof(report_digitizer_t), NULL);
+ Endpoint_ClearIN();
+#endif
+}
+
/*******************************************************************************
* main
******************************************************************************/
diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c
index 7a4a790315..099964ae56 100644
--- a/tmk_core/protocol/usb_descriptor.c
+++ b/tmk_core/protocol/usb_descriptor.c
@@ -158,6 +158,53 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
# endif
#endif
+#ifdef DIGITIZER_ENABLE
+# ifndef DIGITIZER_SHARED_EP
+const USB_Descriptor_HIDReport_Datatype_t PROGMEM DigitizerReport[] = {
+# elif !defined(SHARED_REPORT_STARTED)
+const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
+# define SHARED_REPORT_STARTED
+# endif
+ HID_RI_USAGE_PAGE(8, 0x0D), // Digitizers
+ HID_RI_USAGE(8, 0x01), // Digitizer
+ HID_RI_COLLECTION(8, 0x01), // Application
+# ifdef DIGITIZER_SHARED_EP
+ HID_RI_REPORT_ID(8, REPORT_ID_DIGITIZER),
+# endif
+ HID_RI_USAGE(8, 0x20), // Stylus
+ HID_RI_COLLECTION(8, 0x00), // Physical
+ // Tip Switch (1 bit)
+ HID_RI_USAGE(8, 0x42), // Tip Switch
+ HID_RI_LOGICAL_MINIMUM(8, 0x00),
+ HID_RI_LOGICAL_MAXIMUM(8, 0x01),
+ HID_RI_REPORT_SIZE(8, 0x01),
+ HID_RI_REPORT_COUNT(8, 0x01),
+ HID_RI_INPUT(8, HID_IOF_VARIABLE),
+ // In Range (1 bit)
+ HID_RI_USAGE(8, 0x32), // In Range
+ HID_RI_INPUT(8, HID_IOF_VARIABLE),
+ // Padding (6 bits)
+ HID_RI_REPORT_COUNT(8, 0x06),
+ HID_RI_INPUT(8, HID_IOF_CONSTANT | HID_IOF_VARIABLE),
+
+ // X/Y Position (4 bytes)
+ HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop
+ HID_RI_LOGICAL_MAXIMUM(16, 0x7FFF),
+ HID_RI_REPORT_SIZE(8, 0x10),
+ HID_RI_REPORT_COUNT(8, 0x01),
+ HID_RI_UNIT(8, 0x33), // Inch, English Linear
+ HID_RI_UNIT_EXPONENT(8, 0x0E), // -2
+ HID_RI_USAGE(8, 0x30), // X
+ HID_RI_INPUT(8, HID_IOF_VARIABLE),
+ HID_RI_USAGE(8, 0x31), // Y
+ HID_RI_INPUT(8, HID_IOF_VARIABLE),
+ HID_RI_END_COLLECTION(0),
+ HID_RI_END_COLLECTION(0),
+# ifndef DIGITIZER_SHARED_EP
+};
+# endif
+#endif
+
#if defined(SHARED_EP_ENABLE) && !defined(SHARED_REPORT_STARTED)
const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
#endif
@@ -227,6 +274,7 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
HID_RI_OUTPUT(8, HID_IOF_CONSTANT),
HID_RI_END_COLLECTION(0),
#endif
+
#ifdef SHARED_EP_ENABLE
};
#endif
@@ -921,6 +969,46 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = {
.PollingIntervalMS = USB_POLLING_INTERVAL_MS
}
#endif
+
+#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP)
+ /*
+ * Digitizer
+ */
+ .Digitizer_Interface = {
+ .Header = {
+ .Size = sizeof(USB_Descriptor_Interface_t),
+ .Type = DTYPE_Interface
+ },
+ .InterfaceNumber = DIGITIZER_INTERFACE,
+ .AlternateSetting = 0x00,
+ .TotalEndpoints = 1,
+ .Class = HID_CSCP_HIDClass,
+ .SubClass = HID_CSCP_NonBootSubclass,
+ .Protocol = HID_CSCP_NonBootProtocol,
+ .InterfaceStrIndex = NO_DESCRIPTOR
+ },
+ .Digitizer_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(DigitizerReport)
+ },
+ .Digitizer_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
};
/*
@@ -1059,6 +1147,13 @@ uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const
Size = sizeof(USB_HID_Descriptor_HID_t);
break;
#endif
+#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP)
+ case DIGITIZER_INTERFACE:
+ Address = &ConfigurationDescriptor.Digitizer_HID;
+ Size = sizeof(USB_HID_Descriptor_HID_t);
+
+ break;
+#endif
}
break;
@@ -1108,6 +1203,12 @@ uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const
Address = &JoystickReport;
Size = sizeof(JoystickReport);
break;
+#endif
+#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP)
+ case DIGITIZER_INTERFACE:
+ Address = &DigitizerReport;
+ Size = sizeof(DigitizerReport);
+ break;
#endif
}
diff --git a/tmk_core/protocol/usb_descriptor.h b/tmk_core/protocol/usb_descriptor.h
index 867e549b4f..0f0c78f66c 100644
--- a/tmk_core/protocol/usb_descriptor.h
+++ b/tmk_core/protocol/usb_descriptor.h
@@ -135,6 +135,13 @@ typedef struct {
USB_HID_Descriptor_HID_t Joystick_HID;
USB_Descriptor_Endpoint_t Joystick_INEndpoint;
#endif
+
+#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP)
+ // Digitizer HID Interface
+ USB_Descriptor_Interface_t Digitizer_Interface;
+ USB_HID_Descriptor_HID_t Digitizer_HID;
+ USB_Descriptor_Endpoint_t Digitizer_INEndpoint;
+#endif
} USB_Descriptor_Configuration_t;
/*
@@ -180,6 +187,10 @@ enum usb_interfaces {
#if defined(JOYSTICK_ENABLE)
JOYSTICK_INTERFACE,
#endif
+
+#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP)
+ DIGITIZER_INTERFACE,
+#endif
TOTAL_INTERFACES
};
@@ -226,7 +237,7 @@ enum usb_endpoints {
# if STM32_USB_USE_OTG1
# define CONSOLE_OUT_EPNUM CONSOLE_IN_EPNUM
# else
- CONSOLE_OUT_EPNUM = NEXT_EPNUM,
+ CONSOLE_OUT_EPNUM = NEXT_EPNUM,
# endif
# else
# define CONSOLE_OUT_EPNUM CONSOLE_IN_EPNUM
@@ -259,6 +270,19 @@ enum usb_endpoints {
JOYSTICK_OUT_EPNUM = NEXT_EPNUM,
# endif
#endif
+
+#ifdef DIGITIZER_ENABLE
+# if !defined(DIGITIZER_SHARED_EP)
+ DIGITIZER_IN_EPNUM = NEXT_EPNUM,
+# if STM32_USB_USE_OTG1
+ DIGITIZER_OUT_EPNUM = DIGITIZER_IN_EPNUM,
+# else
+ DIGITIZER_OUT_EPNUM = NEXT_EPNUM,
+# endif
+# else
+# define DIGITIZER_IN_EPNUM SHARED_IN_EPNUM
+# endif
+#endif
};
#ifdef PROTOCOL_LUFA
@@ -284,5 +308,6 @@ enum usb_endpoints {
#define CDC_NOTIFICATION_EPSIZE 8
#define CDC_EPSIZE 16
#define JOYSTICK_EPSIZE 8
+#define DIGITIZER_EPSIZE 8
uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const void** const DescriptorAddress);
diff --git a/tmk_core/protocol/vusb/vusb.c b/tmk_core/protocol/vusb/vusb.c
index 98cebf6012..485b20c900 100644
--- a/tmk_core/protocol/vusb/vusb.c
+++ b/tmk_core/protocol/vusb/vusb.c
@@ -292,6 +292,14 @@ static void send_consumer(uint16_t data) {
#endif
}
+void send_digitizer(report_digitizer_t *report) {
+#ifdef DIGITIZER_ENABLE
+ if (usbInterruptIsReadyShared()) {
+ usbSetInterruptShared((void *)report, sizeof(report_digitizer_t));
+ }
+#endif
+}
+
/*------------------------------------------------------------------*
* Request from host *
*------------------------------------------------------------------*/
@@ -510,8 +518,46 @@ const PROGMEM uchar shared_hid_report[] = {
0x95, 0x01, // Report Count (1)
0x75, 0x10, // Report Size (16)
0x81, 0x00, // Input (Data, Array, Absolute)
- 0xC0 // End Collection
+ 0xC0, // End Collection
#endif
+
+#ifdef DIGITIZER_ENABLE
+ // Digitizer report descriptor
+ 0x05, 0x0D, // Usage Page (Digitizers)
+ 0x09, 0x01, // Usage (Digitizer)
+ 0xA1, 0x01, // Collection (Application)
+ 0x85, REPORT_ID_DIGITIZER, // Report ID
+ 0x09, 0x22, // Usage (Finger)
+ 0xA1, 0x00, // Collection (Physical)
+ // Tip Switch (1 bit)
+ 0x09, 0x42, // Usage (Tip Switch)
+ 0x15, 0x00, // Logical Minimum
+ 0x25, 0x01, // Logical Maximum
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x01, // Report Size (16)
+ 0x81, 0x02, // Input (Data, Variable, Absolute)
+ // In Range (1 bit)
+ 0x09, 0x32, // Usage (In Range)
+ 0x81, 0x02, // Input (Data, Variable, Absolute)
+ // Padding (6 bits)
+ 0x95, 0x06, // Report Count (6)
+ 0x81, 0x03, // Input (Constant)
+
+ // X/Y Position (4 bytes)
+ 0x05, 0x01, // Usage Page (Generic Desktop)
+ 0x26, 0xFF, 0x7F, // Logical Maximum (32767)
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x10, // Report Size (16)
+ 0x65, 0x33, // Unit (Inch, English Linear)
+ 0x55, 0x0E, // Unit Exponent (-2)
+ 0x09, 0x30, // Usage (X)
+ 0x81, 0x02, // Input (Data, Variable, Absolute)
+ 0x09, 0x31, // Usage (Y)
+ 0x81, 0x02, // Input (Data, Variable, Absolute)
+ 0xC0, // End Collection
+ 0xC0 // End Collection
+#endif
+
#ifdef SHARED_EP_ENABLE
};
#endif