diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h index 7513aa249d..4c06e45b10 100644 --- a/include/SDL3/SDL_events.h +++ b/include/SDL3/SDL_events.h @@ -818,6 +818,9 @@ typedef struct SDL_PinchFingerEvent * 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. * + * Not all platforms have a window associated with the pen during proximity + * events. Some wait until motion/button/etc events to offer this info. + * * \since This struct is available since SDL 3.2.0. */ typedef struct SDL_PenProximityEvent diff --git a/src/events/SDL_pen.c b/src/events/SDL_pen.c index f8cdc60830..18a862e865 100644 --- a/src/events/SDL_pen.c +++ b/src/events/SDL_pen.c @@ -218,7 +218,7 @@ SDL_PenCapabilityFlags SDL_GetPenCapabilityFromAxis(SDL_PenAxis axis) return 0; // oh well. } -SDL_PenID SDL_AddPenDevice(Uint64 timestamp, const char *name, const SDL_PenInfo *info, void *handle) +SDL_PenID SDL_AddPenDevice(Uint64 timestamp, const char *name, SDL_Window *window, const SDL_PenInfo *info, void *handle) { SDL_assert(handle != NULL); // just allocate a Uint8 so you have a unique pointer if not needed! SDL_assert(SDL_FindPenByHandle(handle) == 0); // Backends shouldn't double-add pens! @@ -262,13 +262,14 @@ SDL_PenID SDL_AddPenDevice(Uint64 timestamp, const char *name, const SDL_PenInfo event.pproximity.type = SDL_EVENT_PEN_PROXIMITY_IN; event.pproximity.timestamp = timestamp; event.pproximity.which = result; + event.pproximity.windowID = window ? window->id : 0; SDL_PushEvent(&event); } return result; } -void SDL_RemovePenDevice(Uint64 timestamp, SDL_PenID instance_id) +void SDL_RemovePenDevice(Uint64 timestamp, SDL_Window *window, SDL_PenID instance_id) { if (!instance_id) { return; @@ -306,6 +307,7 @@ void SDL_RemovePenDevice(Uint64 timestamp, SDL_PenID instance_id) event.pproximity.type = SDL_EVENT_PEN_PROXIMITY_OUT; event.pproximity.timestamp = timestamp; event.pproximity.which = instance_id; + event.pproximity.windowID = window ? window->id : 0; SDL_PushEvent(&event); } } diff --git a/src/events/SDL_pen_c.h b/src/events/SDL_pen_c.h index 83f412c1a8..69539bde2a 100644 --- a/src/events/SDL_pen_c.h +++ b/src/events/SDL_pen_c.h @@ -61,10 +61,10 @@ typedef struct 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); +extern SDL_PenID SDL_AddPenDevice(Uint64 timestamp, const char *name, SDL_Window *window, const SDL_PenInfo *info, void *handle); // Backend calls this when an existing pen device is disconnected during runtime. They must free their own stuff separately. -extern void SDL_RemovePenDevice(Uint64 timestamp, SDL_PenID instance_id); +extern void SDL_RemovePenDevice(Uint64 timestamp, SDL_Window *window, SDL_PenID instance_id); // Backend can call this to remove all pens, probably during shutdown, with a callback to let them free their own handle. extern void SDL_RemoveAllPenDevices(void (*callback)(SDL_PenID instance_id, void *handle, void *userdata), void *userdata); diff --git a/src/video/android/SDL_androidpen.c b/src/video/android/SDL_androidpen.c index 727d8bd862..7bfde272e7 100644 --- a/src/video/android/SDL_androidpen.c +++ b/src/video/android/SDL_androidpen.c @@ -51,7 +51,7 @@ void Android_OnPen(SDL_Window *window, int pen_id_in, SDL_PenDeviceType device_t peninfo.num_buttons = 2; peninfo.subtype = SDL_PEN_TYPE_PEN; peninfo.device_type = device_type; - pen = SDL_AddPenDevice(0, NULL, &peninfo, (void *) (size_t) pen_id_in); + pen = SDL_AddPenDevice(0, NULL, window, &peninfo, (void *) (size_t) pen_id_in); if (!pen) { SDL_Log("error: can't add a pen device %d", pen_id_in); return; @@ -78,7 +78,7 @@ void Android_OnPen(SDL_Window *window, int pen_id_in, SDL_PenDeviceType device_t switch (action) { case ACTION_CANCEL: case ACTION_HOVER_EXIT: - SDL_RemovePenDevice(0, pen); + SDL_RemovePenDevice(0, window, pen); break; case ACTION_DOWN: diff --git a/src/video/cocoa/SDL_cocoapen.m b/src/video/cocoa/SDL_cocoapen.m index e8a15dac78..b698bc571c 100644 --- a/src/video/cocoa/SDL_cocoapen.m +++ b/src/video/cocoa/SDL_cocoapen.m @@ -105,14 +105,14 @@ static void Cocoa_HandlePenProximityEvent(SDL_CocoaWindowData *_data, NSEvent *e handle->deviceid = devid; handle->toolid = toolid; handle->is_eraser = is_eraser; - handle->pen = SDL_AddPenDevice(Cocoa_GetEventTimestamp([event timestamp]), NULL, &peninfo, handle); + handle->pen = SDL_AddPenDevice(Cocoa_GetEventTimestamp([event timestamp]), NULL, _data.window, &peninfo, handle); if (!handle->pen) { SDL_free(handle); // oh well. } } else { // old pen leaving! Cocoa_PenHandle *handle = Cocoa_FindPenByDeviceID(devid, toolid); if (handle) { - SDL_RemovePenDevice(Cocoa_GetEventTimestamp([event timestamp]), handle->pen); + SDL_RemovePenDevice(Cocoa_GetEventTimestamp([event timestamp]), _data.window, handle->pen); SDL_free(handle); } } diff --git a/src/video/emscripten/SDL_emscriptenevents.c b/src/video/emscripten/SDL_emscriptenevents.c index 87f0cf1b31..07f9b2e43e 100644 --- a/src/video/emscripten/SDL_emscriptenevents.c +++ b/src/video/emscripten/SDL_emscriptenevents.c @@ -855,7 +855,7 @@ static void Emscripten_HandlePenEnter(SDL_WindowData *window_data, const Emscrip peninfo.max_tilt = 90.0f; peninfo.num_buttons = 2; peninfo.subtype = SDL_PEN_TYPE_PEN; - SDL_AddPenDevice(0, NULL, &peninfo, (void *) (size_t) event->pointerid); + SDL_AddPenDevice(0, NULL, window_data->window, &peninfo, (void *) (size_t) event->pointerid); Emscripten_UpdatePenFromEvent(window_data, event); } @@ -878,7 +878,7 @@ static void Emscripten_HandlePenLeave(SDL_WindowData *window_data, const Emscrip const SDL_PenID pen = SDL_FindPenByHandle((void *) (size_t) event->pointerid); if (pen) { Emscripten_UpdatePointerFromEvent(window_data, event); // last data updates? - SDL_RemovePenDevice(0, pen); + SDL_RemovePenDevice(0, window_data->window, pen); } } diff --git a/src/video/uikit/SDL_uikitpen.m b/src/video/uikit/SDL_uikitpen.m index 366580dcb7..9c58e17104 100644 --- a/src/video/uikit/SDL_uikitpen.m +++ b/src/video/uikit/SDL_uikitpen.m @@ -63,7 +63,7 @@ bool UIKit_InitPen(SDL_VideoDevice *_this) // we only have one Apple Pencil at a time, and it must be paired to the iOS device. // We only know about its existence when it first sends an event, so add an single SDL pen // device here if we haven't already. -static SDL_PenID UIKit_AddPenIfNecesary() +static SDL_PenID UIKit_AddPenIfNecesary(SDL_Window *window) { if (!apple_pencil_id) { SDL_PenInfo info; @@ -86,7 +86,7 @@ static SDL_PenID UIKit_AddPenIfNecesary() // so we can't use it for tangential pressure. // There's only ever one Apple Pencil at most, so we just pass a non-zero value for the handle. - apple_pencil_id = SDL_AddPenDevice(0, "Apple Pencil", &info, (void *) (size_t) 0x1); + apple_pencil_id = SDL_AddPenDevice(0, "Apple Pencil", window, &info, (void *) (size_t) 0x1); } return apple_pencil_id; @@ -95,7 +95,7 @@ static SDL_PenID UIKit_AddPenIfNecesary() static void UIKit_HandlePenAxes(SDL_Window *window, NSTimeInterval nstimestamp, float zOffset, const CGPoint *point, float force, float maximumPossibleForce, float azimuthAngleInView, float altitudeAngle, float rollAngle) { - const SDL_PenID penId = UIKit_AddPenIfNecesary(); + const SDL_PenID penId = UIKit_AddPenIfNecesary(window); if (penId) { const Uint64 timestamp = UIKit_GetEventTimestamp(nstimestamp); const float radians_to_degrees = 180.0f / SDL_PI_F; @@ -188,18 +188,20 @@ void UIKit_HandlePenMotion(SDL_uikitview *view, UITouch *pencil) void UIKit_HandlePenPress(SDL_uikitview *view, UITouch *pencil) { - const SDL_PenID penId = UIKit_AddPenIfNecesary(); + SDL_Window *window = [view getSDLWindow]; + const SDL_PenID penId = UIKit_AddPenIfNecesary(window); if (penId) { UIKit_HandlePenAxesFromUITouch(view, pencil); - SDL_SendPenTouch(UIKit_GetEventTimestamp([pencil timestamp]), penId, [view getSDLWindow], false, true); + SDL_SendPenTouch(UIKit_GetEventTimestamp([pencil timestamp]), penId, window, false, true); } } void UIKit_HandlePenRelease(SDL_uikitview *view, UITouch *pencil) { - const SDL_PenID penId = UIKit_AddPenIfNecesary(); + SDL_Window *window = [view getSDLWindow]; + const SDL_PenID penId = UIKit_AddPenIfNecesary(window); if (penId) { - SDL_SendPenTouch(UIKit_GetEventTimestamp([pencil timestamp]), penId, [view getSDLWindow], false, false); + SDL_SendPenTouch(UIKit_GetEventTimestamp([pencil timestamp]), penId, window, false, false); UIKit_HandlePenAxesFromUITouch(view, pencil); } } @@ -207,7 +209,7 @@ void UIKit_HandlePenRelease(SDL_uikitview *view, UITouch *pencil) void UIKit_QuitPen(SDL_VideoDevice *_this) { if (apple_pencil_id) { - SDL_RemovePenDevice(0, apple_pencil_id); + SDL_RemovePenDevice(0, NULL, apple_pencil_id); apple_pencil_id = 0; } } diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index ee1378dec2..59154dab51 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -3306,7 +3306,8 @@ static void tablet_tool_handle_removed(void *data, struct zwp_tablet_tool_v2 *to { SDL_WaylandPenTool *sdltool = (SDL_WaylandPenTool *) data; if (sdltool->instance_id) { - SDL_RemovePenDevice(0, sdltool->instance_id); + SDL_Window *window = sdltool->focus ? sdltool->focus->sdlwindow : NULL; + SDL_RemovePenDevice(0, window, sdltool->instance_id); } Wayland_CursorStateRelease(&sdltool->cursor_state); @@ -3439,7 +3440,7 @@ static void tablet_tool_handle_frame(void *data, struct zwp_tablet_tool_v2 *tool if (sdltool->frame.have_proximity_in) { SDL_assert(sdltool->instance_id == 0); // shouldn't be added at this point. if (sdltool->info.subtype != SDL_PEN_TYPE_UNKNOWN) { // don't tell SDL about it if we don't know its role. - sdltool->instance_id = SDL_AddPenDevice(timestamp, NULL, &sdltool->info, sdltool); + sdltool->instance_id = SDL_AddPenDevice(timestamp, NULL, window, &sdltool->info, sdltool); Wayland_TabletToolUpdateCursor(sdltool); } } @@ -3487,7 +3488,7 @@ static void tablet_tool_handle_frame(void *data, struct zwp_tablet_tool_v2 *tool if (sdltool->frame.have_proximity_out) { sdltool->focus = NULL; Wayland_TabletToolUpdateCursor(sdltool); - SDL_RemovePenDevice(timestamp, sdltool->instance_id); + SDL_RemovePenDevice(timestamp, window, sdltool->instance_id); sdltool->instance_id = 0; } @@ -3656,7 +3657,7 @@ void Wayland_DisplayRemoveWindowReferencesFromSeats(SDL_VideoData *display, SDL_ tool->focus = NULL; Wayland_TabletToolUpdateCursor(tool); if (tool->instance_id) { - SDL_RemovePenDevice(0, tool->instance_id); + SDL_RemovePenDevice(0, window->sdlwindow, tool->instance_id); tool->instance_id = 0; } } diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index b9f6e9dba0..3f7e5c6008 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -1277,7 +1277,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara info.max_tilt = 90.0f; info.num_buttons = 1; info.subtype = SDL_PEN_TYPE_PENCIL; - SDL_AddPenDevice(0, NULL, &info, hpointer); + SDL_AddPenDevice(0, NULL, data->window, &info, hpointer); returnCode = 0; } break; @@ -1293,7 +1293,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara // if this just left the _window_, we don't care. If this is no longer visible to the tablet, time to remove it! if ((msg == WM_POINTERCAPTURECHANGED) || !IS_POINTER_INCONTACT_WPARAM(wParam)) { - SDL_RemovePenDevice(WIN_GetEventTimestamp(), pen); + SDL_RemovePenDevice(WIN_GetEventTimestamp(), data->window, pen); } returnCode = 0; } break; diff --git a/src/video/x11/SDL_x11pen.c b/src/video/x11/SDL_x11pen.c index c29c629c4a..9374b23c84 100644 --- a/src/video/x11/SDL_x11pen.c +++ b/src/video/x11/SDL_x11pen.c @@ -272,7 +272,7 @@ static X11_PenHandle *X11_MaybeAddPen(SDL_VideoDevice *_this, const XIDeviceInfo handle->is_eraser = is_eraser; handle->x11_deviceid = dev->deviceid; - handle->pen = SDL_AddPenDevice(0, dev->name, &peninfo, handle); + handle->pen = SDL_AddPenDevice(0, dev->name, NULL, &peninfo, handle); if (!handle->pen) { SDL_free(handle); return NULL; @@ -301,7 +301,7 @@ void X11_RemovePenByDeviceID(int deviceid) { X11_PenHandle *handle = X11_FindPenByDeviceID(deviceid); if (handle) { - SDL_RemovePenDevice(0, handle->pen); + SDL_RemovePenDevice(0, NULL, handle->pen); SDL_free(handle); } }