From a9d70dbacb1ac26ee33ca6de93749619518a3c55 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Sun, 26 May 2024 11:38:40 -0400
Subject: [PATCH] pen: Rework public API.
This changes the API in various ways, and updates the backends for this.
Overall, this is a massive simplification of the API, as most future backends
can't support the previously-offered API.
This also removes the testautomation pen code (not only did these interfaces
change completely, it also did something no other test did: mock the internal
API), and replaces testpen.c with a different implementation (the existing
code was fine, it was just easier to start from scratch than update it).
---
.../testautomation/testautomation.vcxproj | 6 -
.../SDLTest/SDLTest.xcodeproj/project.pbxproj | 2 -
include/SDL3/SDL_events.h | 137 +-
include/SDL3/SDL_pen.h | 260 +--
src/dynapi/SDL_dynapi.sym | 8 -
src/dynapi/SDL_dynapi_overrides.h | 8 -
src/dynapi/SDL_dynapi_procs.h | 8 -
src/events/SDL_categories.c | 29 +-
src/events/SDL_categories_c.h | 4 +-
src/events/SDL_events.c | 65 +-
src/events/SDL_events_c.h | 1 +
src/events/SDL_mouse.c | 9 +-
src/events/SDL_pen.c | 1336 ++++--------
src/events/SDL_pen_c.h | 347 +--
src/video/SDL_video.c | 9 +
src/video/wayland/SDL_waylandevents.c | 567 ++---
src/video/wayland/SDL_waylandevents_c.h | 47 +-
src/video/wayland/SDL_waylandvideo.c | 2 +-
src/video/wayland/SDL_waylandvideo.h | 3 +-
src/video/x11/SDL_x11events.c | 3 -
src/video/x11/SDL_x11pen.c | 756 ++-----
src/video/x11/SDL_x11pen.h | 45 +-
src/video/x11/SDL_x11video.c | 3 +-
src/video/x11/SDL_x11video.h | 9 +-
src/video/x11/SDL_x11xinput2.c | 101 +-
test/testautomation.c | 3 -
test/testautomation_pen.c | 1940 -----------------
test/testautomation_suites.h | 1 -
test/testpen.c | 676 ++----
29 files changed, 1334 insertions(+), 5051 deletions(-)
delete mode 100644 test/testautomation_pen.c
diff --git a/VisualC/tests/testautomation/testautomation.vcxproj b/VisualC/tests/testautomation/testautomation.vcxproj
index af345542d0083..8dd3dfc44151b 100644
--- a/VisualC/tests/testautomation/testautomation.vcxproj
+++ b/VisualC/tests/testautomation/testautomation.vcxproj
@@ -212,12 +212,6 @@
<ClCompile Include="..\..\..\test\testautomation_main.c" />
<ClCompile Include="..\..\..\test\testautomation_math.c" />
<ClCompile Include="..\..\..\test\testautomation_mouse.c" />
- <ClCompile Include="..\..\..\test\testautomation_pen.c">
- <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)\..\..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)\..\..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)\..\..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)\..\..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- </ClCompile>
<ClCompile Include="..\..\..\test\testautomation_pixels.c" />
<ClCompile Include="..\..\..\test\testautomation_platform.c" />
<ClCompile Include="..\..\..\test\testautomation_properties.c" />
diff --git a/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj b/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj
index a3b389edca9c0..b1b49715a5521 100644
--- a/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj
+++ b/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj
@@ -1274,7 +1274,6 @@
4537749212091504002F0F45 /* testshape.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = testshape.app; sourceTree = BUILT_PRODUCTS_DIR; };
453774A4120915E3002F0F45 /* testshape.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testshape.c; sourceTree = "<group>"; };
66E88E8A203B778F0004D44E /* testyuv_cvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = testyuv_cvt.c; sourceTree = "<group>"; };
- A1A859442BC72FC20045DD6C /* testautomation_pen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testautomation_pen.c; sourceTree = "<group>"; };
A1A859482BC72FC20045DD6C /* testautomation_properties.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testautomation_properties.c; sourceTree = "<group>"; };
A1A859492BC72FC20045DD6C /* testautomation_subsystems.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testautomation_subsystems.c; sourceTree = "<group>"; };
A1A8594A2BC72FC20045DD6C /* testautomation_log.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testautomation_log.c; sourceTree = "<group>"; };
@@ -1804,7 +1803,6 @@
F35E56B62983130A00A43A5F /* testautomation_main.c */,
F35E56BA2983130B00A43A5F /* testautomation_math.c */,
F35E56CD2983130F00A43A5F /* testautomation_mouse.c */,
- A1A859442BC72FC20045DD6C /* testautomation_pen.c */,
F35E56C02983130C00A43A5F /* testautomation_pixels.c */,
F35E56C32983130D00A43A5F /* testautomation_platform.c */,
A1A859482BC72FC20045DD6C /* testautomation_properties.c */,
diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h
index 1bf311f819d32..57b412df27713 100644
--- a/include/SDL3/SDL_events.h
+++ b/include/SDL3/SDL_events.h
@@ -151,8 +151,6 @@ typedef enum SDL_EventType
in an event watcher, the window handle is still valid and can still be used to retrieve any userdata
associated with the window. Otherwise, the handle has already been destroyed and all resources
associated with it are invalid */
- SDL_EVENT_WINDOW_PEN_ENTER, /**< Window has gained focus of the pressure-sensitive pen with ID "data1" */
- SDL_EVENT_WINDOW_PEN_LEAVE, /**< Window has lost focus of the pressure-sensitive pen with ID "data1" */
SDL_EVENT_WINDOW_HDR_STATE_CHANGED, /**< Window HDR properties have changed */
SDL_EVENT_WINDOW_FIRST = SDL_EVENT_WINDOW_SHOWN,
SDL_EVENT_WINDOW_LAST = SDL_EVENT_WINDOW_HDR_STATE_CHANGED,
@@ -227,11 +225,14 @@ typedef enum SDL_EventType
SDL_EVENT_SENSOR_UPDATE = 0x1200, /**< A sensor was updated */
/* Pressure-sensitive pen events */
- SDL_EVENT_PEN_DOWN = 0x1300, /**< Pressure-sensitive pen touched drawing surface */
+ SDL_EVENT_PEN_PROXIMITY_IN = 0x1300, /**< Pressure-sensitive pen has become available */
+ SDL_EVENT_PEN_PROXIMITY_OUT, /**< Pressure-sensitive pen has become unavailable */
+ SDL_EVENT_PEN_DOWN, /**< Pressure-sensitive pen touched drawing surface */
SDL_EVENT_PEN_UP, /**< Pressure-sensitive pen stopped touching drawing surface */
- SDL_EVENT_PEN_MOTION, /**< Pressure-sensitive pen moved, or angle/pressure changed */
SDL_EVENT_PEN_BUTTON_DOWN, /**< Pressure-sensitive pen button pressed */
SDL_EVENT_PEN_BUTTON_UP, /**< Pressure-sensitive pen button released */
+ SDL_EVENT_PEN_MOTION, /**< Pressure-sensitive pen is moving on the tablet */
+ SDL_EVENT_PEN_AXIS, /**< Pressure-sensitive pen angle/pressure/etc changed */
/* Camera hotplug events */
SDL_EVENT_CAMERA_DEVICE_ADDED = 0x1400, /**< A new camera device is available */
@@ -426,7 +427,7 @@ typedef struct SDL_MouseMotionEvent
Uint32 reserved;
Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */
SDL_WindowID windowID; /**< The window with mouse focus, if any */
- SDL_MouseID which; /**< The mouse instance id, SDL_TOUCH_MOUSEID, or SDL_PEN_MOUSEID */
+ SDL_MouseID which; /**< The mouse instance id or SDL_TOUCH_MOUSEID */
SDL_MouseButtonFlags state; /**< The current button state */
float x; /**< X coordinate, relative to window */
float y; /**< Y coordinate, relative to window */
@@ -445,7 +446,7 @@ typedef struct SDL_MouseButtonEvent
Uint32 reserved;
Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */
SDL_WindowID windowID; /**< The window with mouse focus, if any */
- SDL_MouseID which; /**< The mouse instance id, SDL_TOUCH_MOUSEID, or SDL_PEN_MOUSEID */
+ SDL_MouseID which; /**< The mouse instance id, SDL_TOUCH_MOUSEID */
Uint8 button; /**< The mouse button index */
Uint8 state; /**< SDL_PRESSED or SDL_RELEASED */
Uint8 clicks; /**< 1 for single-click, 2 for double-click, etc. */
@@ -465,7 +466,7 @@ typedef struct SDL_MouseWheelEvent
Uint32 reserved;
Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */
SDL_WindowID windowID; /**< The window with mouse focus, if any */
- SDL_MouseID which; /**< The mouse instance id, SDL_TOUCH_MOUSEID, or SDL_PEN_MOUSEID */
+ SDL_MouseID which; /**< The mouse instance id, SDL_TOUCH_MOUSEID */
float x; /**< The amount scrolled horizontally, positive to the right and negative to the left */
float y; /**< The amount scrolled vertically, positive away from the user and negative toward the user */
SDL_MouseWheelDirection direction; /**< Set to one of the SDL_MOUSEWHEEL_* defines. When FLIPPED the values in X and Y will be opposite. Multiply by -1 to change them back */
@@ -714,67 +715,119 @@ typedef struct SDL_TouchFingerEvent
SDL_WindowID windowID; /**< The window underneath the finger, if any */
} SDL_TouchFingerEvent;
-
/**
- * Pressure-sensitive pen touched or stopped touching surface (event.ptip.*)
+ * Pressure-sensitive pen proximity event structure (event.pmotion.*)
+ *
+ * When a pen becomes visible to the system (it is close enough to a tablet,
+ * etc), SDL will send an SDL_EVENT_PEN_PROXIMITY_IN event with the new
+ * pen's ID. This ID is valid until the pen leaves proximity again (has
+ * been removed from the tablet's area, the tablet has been unplugged, etc).
+ * If the same pen reenters proximity again, it will be given a new ID.
+ *
+ * Note that "proximity" means "close enough for the tablet to know the tool
+ * is there." The pen touching and lifting off from the tablet while not
+ * leaving the area are handled by SDL_EVENT_PEN_DOWN and SDL_EVENT_PEN_UP.
*
* \since This struct is available since SDL 3.0.0.
*/
-typedef struct SDL_PenTipEvent
+typedef struct SDL_PenProximityEvent
{
- SDL_EventType type; /**< SDL_EVENT_PEN_DOWN or SDL_EVENT_PEN_UP */
+ SDL_EventType type; /**< SDL_EVENT_PEN_PROXIMITY_IN or SDL_EVENT_PEN_PROXIMITY_OUT */
Uint32 reserved;
- Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */
- SDL_WindowID windowID; /**< The window with pen focus, if any */
+ Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */
+ SDL_WindowID windowID; /**< The window with mouse focus, if any */
SDL_PenID which; /**< The pen instance id */
- Uint8 tip; /**< SDL_PEN_TIP_INK when using a regular pen tip, or SDL_PEN_TIP_ERASER if the pen is being used as an eraser (e.g., flipped to use the eraser tip) */
- Uint8 state; /**< SDL_PRESSED on SDL_EVENT_PEN_DOWN and SDL_RELEASED on SDL_EVENT_PEN_UP */
- Uint16 pen_state; /**< Pen button masks (where SDL_BUTTON(1) is the first button, SDL_BUTTON(2) is the second button etc.), SDL_PEN_DOWN_MASK is set if the pen is touching the surface, and SDL_PEN_ERASER_MASK is set if the pen is (used as) an eraser. */
- float x; /**< X coordinate, relative to window */
- float y; /**< Y coordinate, relative to window */
- float axes[SDL_PEN_NUM_AXES]; /**< Pen axes such as pressure and tilt (ordered as per SDL_PenAxis) */
-} SDL_PenTipEvent;
+} SDL_PenProximityEvent;
/**
- * Pressure-sensitive pen motion / pressure / angle event structure
- * (event.pmotion.*)
+ * Pressure-sensitive pen motion event structure (event.pmotion.*)
+ *
+ * Depending on the hardware, you may get motion events when the
+ * pen is not touching a tablet, for tracking a pen even when it
+ * isn't drawing. You should listen for SDL_EVENT_PEN_DOWN and
+ * SDL_EVENT_PEN_UP events, or check `pen_state & SDL_PEN_INPUT_DOWN`
+ * to decide if a pen is "drawing" when dealing with pen motion.
*
* \since This struct is available since SDL 3.0.0.
*/
typedef struct SDL_PenMotionEvent
{
- SDL_EventType type; /**< SDL_EVENT_PEN_MOTION */
+ SDL_EventType type; /**< SDL_EVENT_PEN_MOTION */
+ Uint32 reserved;
+ Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */
+ SDL_WindowID windowID; /**< The window with mouse focus, if any */
+ SDL_PenID which; /**< The pen instance id */
+ SDL_PenInputFlags pen_state; /**< Complete pen input state at time of event */
+ float x; /**< X position of pen on tablet */
+ float y; /**< Y position of pen on tablet */
+} SDL_PenMotionEvent;
+
+/**
+ * Pressure-sensitive pen touched event structure (event.ptouch.*)
+ *
+ * These events come when a pen touches a surface (a tablet, etc),
+ * or lifts off from one.
+ *
+ * \since This struct is available since SDL 3.0.0.
+ */
+typedef struct SDL_PenTouchEvent
+{
+ SDL_EventType type; /**< SDL_EVENT_PEN_DOWN or SDL_EVENT_PEN_UP */
Uint32 reserved;
Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */
SDL_WindowID windowID; /**< The window with pen focus, if any */
SDL_PenID which; /**< The pen instance id */
- Uint8 padding1;
- Uint8 padding2;
- Uint16 pen_state; /**< Pen button masks (where SDL_BUTTON(1) is the first button, SDL_BUTTON(2) is the second button etc.), SDL_PEN_DOWN_MASK is set if the pen is touching the surface, and SDL_PEN_ERASER_MASK is set if the pen is (used as) an eraser. */
- float x; /**< X coordinate, relative to window */
- float y; /**< Y coordinate, relative to window */
- float axes[SDL_PEN_NUM_AXES]; /**< Pen axes such as pressure and tilt (ordered as per SDL_PenAxis) */
-} SDL_PenMotionEvent;
+ SDL_PenInputFlags pen_state; /**< Complete pen input state at time of event */
+ float x; /**< X position of pen on tablet */
+ float y; /**< Y position of pen on tablet */
+ Uint8 eraser; /**< Non-zero if eraser end is used (not all pens support this). */
+ Uint8 state; /**< SDL_PRESSED (pen is touching) or SDL_RELEASED (pen is lifted off) */
+} SDL_PenTouchEvent;
/**
* Pressure-sensitive pen button event structure (event.pbutton.*)
*
+ * This is for buttons on the pen itself that the user might click.
+ * The pen itself pressing down to draw triggers a SDL_EVENT_PEN_DOWN
+ * event instead.
+ *
* \since This struct is available since SDL 3.0.0.
*/
typedef struct SDL_PenButtonEvent
{
- SDL_EventType type; /**< SDL_EVENT_PEN_BUTTON_DOWN or SDL_EVENT_PEN_BUTTON_UP */
+ SDL_EventType type; /**< SDL_EVENT_PEN_BUTTON_DOWN or SDL_EVENT_PEN_BUTTON_UP */
+ Uint32 reserved;
+ Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */
+ SDL_WindowID windowID; /**< The window with mouse focus, if any */
+ SDL_PenID which; /**< The pen instance id */
+ SDL_PenInputFlags pen_state; /**< Complete pen input state at time of event */
+ float x; /**< X position of pen on tablet */
+ float y; /**< Y position of pen on tablet */
+ Uint8 button; /**< The pen button index (first button is 1). */
+ Uint8 state; /**< SDL_PRESSED or SDL_RELEASED */
+} SDL_PenButtonEvent;
+
+/**
+ * Pressure-sensitive pen pressure / angle event structure
+ * (event.paxis.*)
+ *
+ * You might get some of these events even if the pen isn't touching the tablet.
+ *
+ * \since This struct is available since SDL 3.0.0.
+ */
+typedef struct SDL_PenAxisEvent
+{
+ SDL_EventType type; /**< SDL_EVENT_PEN_AXIS */
Uint32 reserved;
Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */
SDL_WindowID windowID; /**< The window with pen focus, if any */
SDL_PenID which; /**< The pen instance id */
- Uint8 button; /**< The pen button index (1 represents the pen tip for compatibility with mouse events) */
- Uint8 state; /**< SDL_PRESSED or SDL_RELEASED */
- Uint16 pen_state; /**< Pen button masks (where SDL_BUTTON(1) is the first button, SDL_BUTTON(2) is the second button etc.), SDL_PEN_DOWN_MASK is set if the pen is touching the surface, and SDL_PEN_ERASER_MASK is set if the pen is (used as) an eraser. */
- float x; /**< X coordinate, relative to window */
- float y; /**< Y coordinate, relative to window */
- float axes[SDL_PEN_NUM_AXES]; /**< Pen axes such as pressure and tilt (ordered as per SDL_PenAxis) */
-} SDL_PenButtonEvent;
+ SDL_PenInputFlags pen_state; /**< Complete pen input state at time of event */
+ float x; /**< X position of pen on tablet */
+ float y; /**< Y position of pen on tablet */
+ SDL_PenAxis axis; /**< Axis that has changed */
+ float value; /**< New value of axis */
+} SDL_PenAxisEvent;
/**
* An event used to drop text or request a file open by the system
@@ -894,9 +947,11 @@ typedef union SDL_Event
SDL_QuitEvent quit; /**< Quit request event data */
SDL_UserEvent user; /**< Custom event data */
SDL_TouchFingerEvent tfinger; /**< Touch finger event data */
- SDL_PenTipEvent ptip; /**< Pen tip touching or leaving drawing surface */
- SDL_PenMotionEvent pmotion; /**< Pen change in position, pressure, or angle */
- SDL_PenButtonEvent pbutton; /**< Pen button press */
+ SDL_PenProximityEvent pproximity; /**< Pen proximity event data */
+ SDL_PenTouchEvent ptouch; /**< Pen tip touching event data */
+ SDL_PenMotionEvent pmotion; /**< Pen motion event data */
+ SDL_PenButtonEvent pbutton; /**< Pen button event data */
+ SDL_PenAxisEvent paxis; /**< Pen axis event data */
SDL_DropEvent drop; /**< Drag and drop event data */
SDL_ClipboardEvent clipboard; /**< Clipboard event data */
diff --git a/include/SDL3/SDL_pen.h b/include/SDL3/SDL_pen.h
index c02c0081f2b7e..02b22b07fb90a 100644
--- a/include/SDL3/SDL_pen.h
+++ b/include/SDL3/SDL_pen.h
@@ -22,259 +22,85 @@
/**
* # CategoryPen
*
- * Include file for SDL pen event handling.
+ * SDL pen event handling.
*
- * This file describes operations for pressure-sensitive pen (stylus and/or
+ * SDL provides an API for pressure-sensitive pen (stylus and/or
* eraser) handling, e.g., for input and drawing tablets or suitably equipped
* mobile / tablet devices.
*
- * To get started with pens:
+ * To get started with pens, simply handle SDL_EVENT_PEN_* events. When a pen
+ * starts providing input, SDL will assign it a unique SDL_PenID, which will
+ * remain for the life of the process, as long as the pen stays connected.
*
- * - Listen to SDL_PenMotionEvent and SDL_PenButtonEvent
- * - To avoid treating pen events as mouse events, ignore SDL_MouseMotionEvent
- * and SDL_MouseButtonEvent whenever `which` == SDL_PEN_MOUSEID.
- *
- * We primarily identify pens by SDL_PenID. The implementation makes a best
- * effort to relate each SDL_PenID to the same physical device during a
- * session. Formerly valid SDL_PenID values remain valid even if a device
- * disappears.
- *
- * For identifying pens across sessions, the API provides the type SDL_GUID .
+ * Pens may provide more than simple touch input; they might have other axes,
+ * such as pressure, tilt, rotation, etc.
*/
#ifndef SDL_pen_h_
#define SDL_pen_h_
#include <SDL3/SDL_error.h>
-#include <SDL3/SDL_guid.h>
-#include <SDL3/SDL_mouse.h>
-#include <SDL3/SDL_stdinc.h>
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
-typedef Uint32 SDL_PenID; /**< SDL_PenIDs identify pens uniquely within a session */
-
-#define SDL_PEN_INVALID ((SDL_PenID)0) /**< Reserved invalid SDL_PenID is valid */
-
-#define SDL_PEN_MOUSEID ((SDL_MouseID)-2) /**< Device ID for mouse events triggered by pen events */
-
-#define SDL_PEN_INFO_UNKNOWN (-1) /**< Marks unknown information when querying the pen */
-
/**
- * Pen axis indices
+ * SDL pen instance IDs.
*
- * Below are the valid indices to the "axis" array from SDL_PenMotionEvent and
- * SDL_PenButtonEvent. The axis indices form a contiguous range of ints from 0
- * to SDL_PEN_AXIS_LAST, inclusive. All "axis[]" entries are either normalised
- * to 0..1 or report a (positive or negative) angle in degrees, with 0.0
- * representing the centre. Not all pens/backends support all axes:
- * unsupported entries are always "0.0f".
+ * Zero is used to signify an invalid/null device.
*
- * To convert angles for tilt and rotation into vector representation, use
- * SDL_sinf on the XTILT, YTILT, or ROTATION component, for example:
- *
- * `SDL_sinf(xtilt * SDL_PI_F / 180.0)`.
- *
- * \since This enum is available since SDL 3.0.0
- */
-typedef enum SDL_PenAxis
-{
- SDL_PEN_AXIS_PRESSURE = 0, /**< Pen pressure. Unidirectional: 0..1.0 */
- SDL_PEN_AXIS_XTILT, /**< Pen horizontal tilt angle. Bidirectional: -90.0..90.0 (left-to-right).
- The physical max/min tilt may be smaller than -90.0 / 90.0, cf. SDL_PenCapabilityInfo */
- SDL_PEN_AXIS_YTILT, /**< Pen vertical tilt angle. Bidirectional: -90.0..90.0 (top-to-down).
- The physical max/min tilt may be smaller than -90.0 / 90.0, cf. SDL_PenCapabilityInfo */
- SDL_PEN_AXIS_DISTANCE, /**< Pen distance to drawing surface. Unidirectional: 0.0..1.0 */
- SDL_PEN_AXIS_ROTATION, /**< Pen barrel rotation. Bidirectional: -180..179.9 (clockwise, 0 is facing up, -180.0 is facing down). */
- SDL_PEN_AXIS_SLIDER, /**< Pen finger wheel or slider (e.g., Airbrush Pen). Unidirectional: 0..1.0 */
- SDL_PEN_NUM_AXES, /**< Last valid axis index */
- SDL_PEN_AXIS_LAST = SDL_PEN_NUM_AXES - 1 /**< Last axis index plus 1 */
-} SDL_PenAxis;
-
-/* Pen flags. These share a bitmask space with SDL_BUTTON_LEFT and friends. */
-#define SDL_PEN_FLAG_DOWN_BIT_INDEX 13 /* Bit for storing that pen is touching the surface */
-#define SDL_PEN_FLAG_INK_BIT_INDEX 14 /* Bit for storing has-non-eraser-capability status */
-#define SDL_PEN_FLAG_ERASER_BIT_INDEX 15 /* Bit for storing is-eraser or has-eraser-capability property */
-#define SDL_PEN_FLAG_AXIS_BIT_OFFSET 16 /* Bit for storing has-axis-0 property */
-
-#define SDL_PEN_CAPABILITY(capbit) (1ul << (capbit))
-#define SDL_PEN_AXIS_CAPABILITY(axis) SDL_PEN_CAPABILITY((axis) + SDL_PEN_FLAG_AXIS_BIT_OFFSET)
-
-/* Pen tips */
-#define SDL_PEN_TIP_INK SDL_PEN_FLAG_INK_BIT_INDEX /**< Regular pen tip (for drawing) touched the surface */
-#define SDL_PEN_TIP_ERASER SDL_PEN_FLAG_ERASER_BIT_INDEX /**< Eraser pen tip touched the surface */
-
-/**
- * Pen capabilities reported by SDL_GetPenCapabilities.
+ * These show up in pen events when SDL sees input from them. They remain
+ * consistent as long as SDL can recognize a tool to be the same pen; but if
+ * a pen physically leaves the area and returns, it might get a new ID.
*
* \since This datatype is available since SDL 3.0.0.
*/
-typedef Uint32 SDL_PenCapabilityFlags;
-
-#define SDL_PEN_DOWN_MASK SDL_PEN_CAPABILITY(SDL_PEN_FLAG_DOWN_BIT_INDEX) /**< Pen tip is currently touching the drawing surface. */
-#define SDL_PEN_INK_MASK SDL_PEN_CAPABILITY(SDL_PEN_FLAG_INK_BIT_INDEX) /**< Pen has a regular drawing tip (SDL_GetPenCapabilities). For events (SDL_PenButtonEvent, SDL_PenMotionEvent, SDL_GetPenStatus) this flag is mutually exclusive with SDL_PEN_ERASER_MASK . */
-#define SDL_PEN_ERASER_MASK SDL_PEN_CAPABILITY(SDL_PEN_FLAG_ERASER_BIT_INDEX) /**< Pen has an eraser tip (SDL_GetPenCapabilities) or is being used as eraser (SDL_PenButtonEvent , SDL_PenMotionEvent , SDL_GetPenStatus) */
-#define SDL_PEN_AXIS_PRESSURE_MASK SDL_PEN_AXIS_CAPABILITY(SDL_PEN_AXIS_PRESSURE) /**< Pen provides pressure information in axis SDL_PEN_AXIS_PRESSURE */
-#define SDL_PEN_AXIS_XTILT_MASK SDL_PEN_AXIS_CAPABILITY(SDL_PEN_AXIS_XTILT) /**< Pen provides horizontal tilt information in axis SDL_PEN_AXIS_XTILT */
-#define SDL_PEN_AXIS_YTILT_MASK SDL_PEN_AXIS_CAPABILITY(SDL_PEN_AXIS_YTILT) /**< Pen provides vertical tilt information in axis SDL_PEN_AXIS_YTILT */
-#define SDL_PEN_AXIS_DISTANCE_MASK SDL_PEN_AXIS_CAPABILITY(SDL_PEN_AXIS_DISTANCE) /**< Pen provides distance to drawing tablet in SDL_PEN_AXIS_DISTANCE */
-#define SDL_PEN_AXIS_ROTATION_MASK SDL_PEN_AXIS_CAPABILITY(SDL_PEN_AXIS_ROTATION) /**< Pen provides barrel rotation information in axis SDL_PEN_AXIS_ROTATION */
-#define SDL_PEN_AXIS_SLIDER_MASK SDL_PEN_AXIS_CAPABILITY(SDL_PEN_AXIS_SLIDER) /**< Pen provides slider / finger wheel or similar in axis SDL_PEN_AXIS_SLIDER */
-#define SDL_PEN_AXIS_BIDIRECTIONAL_MASKS (SDL_PEN_AXIS_XTILT_MASK | SDL_PEN_AXIS_YTILT_MASK)
-
-/**
- * Pen types
- *
- * Some pens identify as a particular type of drawing device (e.g., an
- * airbrush or a pencil).
- *
- * \since This enum is available since SDL 3.0.0
- */
-typedef enum SDL_PenSubtype
-{
- SDL_PEN_TYPE_UNKNOWN = 0,
- SDL_PEN_TYPE_ERASER = 1, /**< Eraser */
- SDL_PEN_TYPE_PEN, /**< Generic pen; this is the default. */
- SDL_PEN_TYPE_PENCIL, /**< Pencil */
- SDL_PEN_TYPE_BRUSH, /**< Brush-like device */
- SDL_PEN_TYPE_AIRBRUSH, /**< Airbrush device that "sprays" ink */
- SDL_PEN_TYPE_LAST = SDL_PEN_TYPE_AIRBRUSH /**< Last valid pen type */
-} SDL_PenSubtype;
-
+typedef Uint32 SDL_PenID;
-/* Function prototypes */
/**
- * Retrieves all pens that are connected to the system.
- *
- * Yields an array of SDL_PenID values. These identify and track pens
- * throughout a session. To track pens across sessions (program restart), use
- * SDL_GUID .
- *
- * \param count the number of pens in the array (number of array elements
- * minus 1, i.e., not counting the terminator 0).
- * \returns a 0 terminated array of SDL_PenID values, or NULL on failure. The
- * array must be freed with SDL_free(). On a NULL return,
- * SDL_GetError() is set.
- *
- * \since This function is available since SDL 3.0.0.
- */
-extern SDL_DECLSPEC SDL_PenID * SDLCALL SDL_GetPens(int *count);
-
-/**
- * Retrieves the pen's current status.
- *
- * If the pen is detached (cf. SDL_PenConnected), this operation may return
- * default values.
+ * Pen input flags, as reported by various pen events' `pen_state` field.
*
- * \param instance_id the pen to query.
- * \param x out-mode parameter for pen x coordinate. May be NULL.
- * \param y out-mode parameter for pen y coordinate. May be NULL.
- * \param axes out-mode parameter for axis information. May be null. The axes
- * are in the same order as SDL_PenAxis.
- * \param num_axes maximum number of axes to write to "axes".
- * \returns a bit mask with the current pen button states (SDL_BUTTON_LMASK
- * etc.), possibly SDL_PEN_DOWN_MASK, and exactly one of
- * SDL_PEN_INK_MASK or SDL_PEN_ERASER_MASK , or 0 on error (see
- * SDL_GetError()).
- *
- * \since This function is available since SDL 3.0.0.
- */
-extern SDL_DECLSPEC Uint32 SDLCALL SDL_GetPenStatus(SDL_PenID instance_id, float *x, float *y, float *axes, size_t num_axes);
-
-/**
- * Retrieves an SDL_PenID for the given SDL_GUID.
- *
- * \param guid a pen GUID.
- * \returns a valid SDL_PenID, or SDL_PEN_INVALID if there is no matching
- * SDL_PenID.
- *
- * \since This function is available since SDL 3.0.0.
- */
-extern SDL_DECLSPEC SDL_PenID SDLCALL SDL_GetPenFromGUID(SDL_GUID guid);
-
-/**
- * Retrieves the SDL_GUID for a given SDL_PenID.
- *
- * \param instance_id the pen to query.
- * \returns the corresponding pen GUID; persistent across multiple sessions.
- * If "instance_id" is SDL_PEN_INVALID, returns an all-zeroes GUID.
- *
- * \since This function is available since SDL 3.0.0.
+ * \since This datatype is available since SDL 3.0.0.
*/
-extern SDL_DECLSPEC SDL_GUID SDLCALL SDL_GetPenGUID(SDL_PenID instance_id);
+typedef Uint32 SDL_PenInputFlags;
+#define SDL_PEN_INPUT_DOWN (1u << 0) /**< & to see if pen is pressed down */
+#define SDL_PEN_INPUT_BUTTON_1 (1u << 1) /**< & to see if button 1 is pressed */
+#define SDL_PEN_INPUT_BUTTON_2 (1u << 2) /**< & to see if button 2 is pressed */
+#define SDL_PEN_INPUT_BUTTON_3 (1u << 3) /**< & to see if button 3 is pressed */
+#define SDL_PEN_INPUT_BUTTON_4 (1u << 4) /**< & to see if button 4 is pressed */
+#define SDL_PEN_INPUT_BUTTON_5 (1u << 5) /**< & to see if button 5 is pressed */
+#define SDL_PEN_INPUT_ERASER_TIP (1u << 30) /**< & to see if eraser tip is used */
/**
- * Checks whether a pen is still attached.
+ * Pen axis indices.
*
- * If a pen is detached, it will not show up for SDL_GetPens(). Other
- * operations will still be available but may return default values.
+ * These are the valid values for the `axis` field in SDL_PenAxisEvent.
+ * All axes are either normalised to 0..1 or report a (positive or negative) angle
+ * in degrees, with 0.0 representing the centre. Not all pens/backends support all
+ * axes: unsupported axes are always zero.
*
- * \param instance_id a pen ID.
- * \returns SDL_TRUE if "instance_id" is valid and the corresponding pen is
- * attached, or SDL_FALSE otherwise.
- *
- * \since This function is available since SDL 3.0.0.
- */
-extern SDL_DECLSPEC SDL_bool SDLCALL SDL_PenConnected(SDL_PenID instance_id);
-
-/**
- * Retrieves a human-readable description for a SDL_PenID.
- *
- * \param instance_id the pen to query.
- * \returns a string that contains the name of the pen, intended for human
- * consumption. The string might or might not be localised, depending
- * on platform settings. It is not guaranteed to be unique; use
- * SDL_GetPenGUID() for (best-effort) unique ident
(Patch may be truncated, please check the link at the top of this post.)