[Proposal] API to query whether SDL_Pen devices are internal or external
Definitions
- internal pen device – a pen the user is using directly over the screen – the digitizer "is" the screen (example: S Pen, Apple Pencil, Microsoft Surface, Wacom tablets with built in screen)
- external pen device – a pen where the digitizer and screen are separate (normal graphics tablets, virtual tablets (using S Pen via phone to control PC))
N.B.: it might make sense to call these direct and indirect.
API proposal
// SDL_pen.h
typedef enum SDL_PenLocation // tentative name
{
SDL_PEN_LOCATION_UNKNOWN,
SDL_PEN_LOCATION_INTERNAL,
SDL_PEN_LOCATION_EXTERNAL
} SDL_PenLocation;
extern SDL_DECLSPEC SDL_PenLocation SDLCALL SDL_GetPenLocation(SDL_PenID instance_id);
Usage
SDL_Event event = ...;
switch (event.type)
{
case SDL_EVENT_PEN_PROXIMITY_IN:
SDL_PenID id = event.pproximity.which; // also works for all other pen events
SDL_PenLocation location = SDL_GetPenLocation(id);
// do game logic with `location`
break;
}
This API is useful for any game that has a custom cursor and only wants it visible in certain scenarios. For external pens, it needs to show the cursor so that the user knows where it's pointing. For internal pens, it doesn't need to show the cursor as the physical pen is the cursor, the user can clearly see where it's pointing.
| External | Internal |
|---|---|
| User needs the cursor so they know where they're pointing to. Similar to a mouse. |
Cursor is redundant. Similar to touch. |
Cross-platform support
Windows 🟡
Global state via GetSystemMetrics(SM_DIGITIZER). I've done a bit of testing with an external tablet, and the API reports both NID_INTEGRATED_PEN and NID_EXTERNAL_PEN for it. Might need to find a better API.
N.B.: It might be difficult to tell whether a tablet with a built-in screen is internal or external, as the HDMI screen and the USB digitizer are two separate devices and the user must manually map the two together.
https://learn.microsoft.com/en-us/windows/win32/wintouch/getting-started-with-multi-touch-messages#testing-the-capabilities-of-the-input-digitizer
Android 🟢
Per-pen state via InputDevice.isExternal(). Works quite well, tested on an S Pen and two USB tablets.
iOS ❔
No support for pens?
iPadOS ❔
People tell me the only supported pen is the Apple Pencil, and that is always internal.
Others ❔
Always report SDL_PEN_LOCATION_UNKNOWN.
Implementation
Re-use the existing SDL_PenInfo, just add an extra flag the backends can report, and publicly expose only this flag.
https://github.com/libsdl-org/SDL/blob/dabc93a631903570cc80a56e3a9002ac13535d57/src/events/SDL_pen_c.h#L49-L61
I have a working implementation for android here: https://github.com/libsdl-org/SDL/compare/main...Susko3:SDL:android-pen-external?expand=1.
The InputDevice.isExternal() only works on API 29+ (Android 10, Q)
There is prior art to naming this direct and indirect in SDL_TouchDeviceType. Should we maybe even use that type here?
Agreed, direct and indirect reads better and SDL_PenDeviceType also makes sense.
I guess having that makes the internal SDL_PenSubtype a bit confusing (as it's not a subtype of the device type), but it's not public API and can be easily renamed separately.
Okay, this needs Apple Pencil still (it's the only "pen" you can use with iPads, and not on iPhones at the moment, so basically any pen in UIKit should be considered direct).
Web browsers support pen input but don't offer this information.
Windows, Wayland, and X11 are question marks. It wouldn't surprise me if we could coerce Windows to work but not the others.
But I'm calling this Good Enough after the easy UIKit change.
Oh! macOS!
There's currently no such thing as a Mac with a touchscreen at all--and for the foreseeable future this will be the domain of iOS, right?!--so maybe we mark these as always indirect.
Macs are rumored to get touchscreens: https://www.theverge.com/news/779759/apple-macbook-pro-oled-touchscreen-rumors.
Of course, hahaha. We'll leave Cocoa as "unknown" for now, then.