#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_UIKIT
#include "SDL_uikitevents.h"
#include "SDL_uikitpen.h"
#include "SDL_uikitwindow.h"
#include "../../events/SDL_pen_c.h"
#if !defined(SDL_PLATFORM_TVOS)
@interface UITouch (SDL)
#if !(__IPHONE_OS_VERSION_MAX_ALLOWED >= 170500)
@property (nonatomic, readonly) CGFloat rollAngle;
#endif
@end
@interface UIHoverGestureRecognizer (SDL)
#if !(__IPHONE_OS_VERSION_MAX_ALLOWED >= 160100)
@property (nonatomic, readonly) CGFloat zOffset;
#endif
#if !(__IPHONE_OS_VERSION_MAX_ALLOWED >= 160400)
- (CGFloat) azimuthAngleInView:(UIView *) view;
@property (nonatomic, readonly) CGFloat altitudeAngle;
#endif
#if !(__IPHONE_OS_VERSION_MAX_ALLOWED >= 170500)
@property (nonatomic, readonly) CGFloat rollAngle;
#endif
@end
#endif
static SDL_PenID apple_pencil_id = 0;
bool UIKit_InitPen(SDL_VideoDevice *_this)
{
return true;
}
static SDL_PenID UIKit_AddPenIfNecesary(SDL_Window *window)
{
if (!apple_pencil_id) {
SDL_PenInfo info;
SDL_zero(info);
info.capabilities = SDL_PEN_CAPABILITY_PRESSURE | SDL_PEN_CAPABILITY_XTILT | SDL_PEN_CAPABILITY_YTILT;
info.max_tilt = 90.0f;
info.num_buttons = 0;
info.subtype = SDL_PEN_TYPE_PENCIL;
info.device_type = SDL_PEN_DEVICE_TYPE_DIRECT;
if (@available(iOS 17.5, *)) { info.capabilities |= SDL_PEN_CAPABILITY_ROTATION;
}
if (@available(ios 16.1, *)) { info.capabilities |= SDL_PEN_CAPABILITY_DISTANCE;
}
apple_pencil_id = SDL_AddPenDevice(0, "Apple Pencil", window, &info, (void *) (size_t) 0x1, true);
}
return apple_pencil_id;
}
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(window);
if (penId) {
const Uint64 timestamp = UIKit_GetEventTimestamp(nstimestamp);
const float radians_to_degrees = 180.0f / SDL_PI_F;
const float pressure = force / maximumPossibleForce;
const float azimuth_angle = azimuthAngleInView * radians_to_degrees;
const float altitude_angle = altitudeAngle * radians_to_degrees;
const float xtilt = (180.0f - SDL_fabsf(azimuth_angle)) - 90.0f;
const float ytilt = (azimuth_angle < 0.0f) ? -(90.0f - altitude_angle) : (90.0f - altitude_angle);
const float rotation = rollAngle * radians_to_degrees;
SDL_SendPenMotion(timestamp, penId, window, point->x, point->y);
SDL_SendPenAxis(timestamp, penId, window, SDL_PEN_AXIS_PRESSURE, pressure);
SDL_SendPenAxis(timestamp, penId, window, SDL_PEN_AXIS_XTILT, xtilt);
SDL_SendPenAxis(timestamp, penId, window, SDL_PEN_AXIS_YTILT, ytilt);
SDL_SendPenAxis(timestamp, penId, window, SDL_PEN_AXIS_ROTATION, rotation);
SDL_SendPenAxis(timestamp, penId, window, SDL_PEN_AXIS_DISTANCE, zOffset);
}
}
#if !defined(SDL_PLATFORM_TVOS)
extern void UIKit_HandlePenHover(SDL_uikitview *view, UIHoverGestureRecognizer *recognizer)
{
float zOffset = 0.0f;
if (@available(iOS 16.1, *)) {
zOffset = (float) [recognizer zOffset];
}
float azimuthAngleInView = 0.0f;
if (@available(iOS 16.4, *)) {
azimuthAngleInView = (float) [recognizer azimuthAngleInView:view];
}
float altitudeAngle = 0.0f;
if (@available(iOS 16.4, *)) {
altitudeAngle = (float) [recognizer altitudeAngle];
}
float rollAngle = 0.0f;
if (@available(iOS 17.5, *)) {
rollAngle = (float) [recognizer rollAngle];
}
SDL_Window *window = [view getSDLWindow];
const CGPoint point = [recognizer locationInView:view];
UIKit_HandlePenAxes(window, 0, zOffset, &point, 0.0f, 1.0f, azimuthAngleInView, altitudeAngle, rollAngle);
}
#endif
static void UIKit_HandlePenAxesFromUITouch(SDL_uikitview *view, UITouch *pencil)
{
float rollAngle = 0.0f;
#if !defined(SDL_PLATFORM_TVOS)
if (@available(iOS 17.5, *)) {
rollAngle = (float) [pencil rollAngle];
}
#endif
SDL_Window *window = [view getSDLWindow];
const CGPoint point = [pencil locationInView:view];
UIKit_HandlePenAxes(window, [pencil timestamp], 0.0f, &point, [pencil force], [pencil maximumPossibleForce], [pencil azimuthAngleInView:view], [pencil altitudeAngle], rollAngle);
}
void UIKit_HandlePenMotion(SDL_uikitview *view, UITouch *pencil)
{
UIKit_HandlePenAxesFromUITouch(view, pencil);
}
void UIKit_HandlePenPress(SDL_uikitview *view, UITouch *pencil)
{
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, window, false, true);
}
}
void UIKit_HandlePenRelease(SDL_uikitview *view, UITouch *pencil)
{
SDL_Window *window = [view getSDLWindow];
const SDL_PenID penId = UIKit_AddPenIfNecesary(window);
if (penId) {
SDL_SendPenTouch(UIKit_GetEventTimestamp([pencil timestamp]), penId, window, false, false);
UIKit_HandlePenAxesFromUITouch(view, pencil);
}
}
void UIKit_QuitPen(SDL_VideoDevice *_this)
{
if (apple_pencil_id) {
SDL_RemovePenDevice(0, NULL, apple_pencil_id);
apple_pencil_id = 0;
}
}
#endif