Skip to content

[Proposal] API to query whether SDL_Pen devices are internal or external #13065

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Susko3 opened this issue May 17, 2025 · 3 comments
Open
Milestone

Comments

@Susko3
Copy link
Contributor

Susko3 commented May 17, 2025

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. Image Cursor is redundant. Similar to touch. Image

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.

typedef struct SDL_PenInfo
{
SDL_PenCapabilityFlags capabilities; /**< bitflags of device capabilities */
float max_tilt; /**< Physical maximum tilt angle, for XTILT and YTILT, or -1.0f if unknown. Pens cannot typically tilt all the way to 90 degrees, so this value is usually less than 90.0. */
Uint32 wacom_id; /**< For Wacom devices: wacom tool type ID, otherwise 0 (useful e.g. with libwacom) */
int num_buttons; /**< Number of pen buttons (not counting the pen tip), or -1 if unknown. */
SDL_PenSubtype subtype; /**< type of pen device */
} SDL_PenInfo;
// Backend calls this when a new pen device is hotplugged, plus once for each pen already connected at startup.
// Note that name and info are copied but currently unused; this is placeholder for a potentially more robust API later.
// Both are allowed to be NULL.
extern SDL_PenID SDL_AddPenDevice(Uint64 timestamp, const char *name, const SDL_PenInfo *info, void *handle);

@Susko3
Copy link
Contributor Author

Susko3 commented May 17, 2025

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)

@slouken
Copy link
Collaborator

slouken commented May 18, 2025

There is prior art to naming this direct and indirect in SDL_TouchDeviceType. Should we maybe even use that type here?

@slouken slouken added this to the 3.4.0 milestone May 18, 2025
@Susko3
Copy link
Contributor Author

Susko3 commented May 18, 2025

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants