Atlas - SDL_cocoapen.m
Home / ext / SDL / src / video / cocoa Lines: 1 | Size: 7153 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#ifdef SDL_VIDEO_DRIVER_COCOA 24 25#include "SDL_cocoapen.h" 26#include "SDL_cocoavideo.h" 27 28#include "../../events/SDL_pen_c.h" 29 30bool Cocoa_InitPen(SDL_VideoDevice *_this) 31{ 32 return true; 33} 34 35typedef struct Cocoa_PenHandle 36{ 37 NSUInteger deviceid; 38 NSUInteger toolid; 39 SDL_PenID pen; 40 bool is_eraser; 41} Cocoa_PenHandle; 42 43typedef struct FindPenByDeviceAndToolIDData 44{ 45 NSUInteger deviceid; 46 NSUInteger toolid; 47 void *handle; 48} FindPenByDeviceAndToolIDData; 49 50static bool FindPenByDeviceAndToolID(void *handle, void *userdata) 51{ 52 const Cocoa_PenHandle *cocoa_handle = (const Cocoa_PenHandle *) handle; 53 FindPenByDeviceAndToolIDData *data = (FindPenByDeviceAndToolIDData *) userdata; 54 55 if (cocoa_handle->deviceid != data->deviceid) { 56 return false; 57 } else if (cocoa_handle->toolid != data->toolid) { 58 return false; 59 } 60 data->handle = handle; 61 return true; 62} 63 64static Cocoa_PenHandle *Cocoa_FindPenByDeviceID(NSUInteger deviceid, NSUInteger toolid) 65{ 66 FindPenByDeviceAndToolIDData data; 67 data.deviceid = deviceid; 68 data.toolid = toolid; 69 data.handle = NULL; 70 SDL_FindPenByCallback(FindPenByDeviceAndToolID, &data); 71 return (Cocoa_PenHandle *) data.handle; 72} 73 74static void Cocoa_HandlePenProximityEvent(SDL_CocoaWindowData *_data, NSEvent *event) 75{ 76 const NSUInteger devid = [event deviceID]; 77 const NSUInteger toolid = [event pointingDeviceID]; 78 79 if (event.enteringProximity) { // new pen coming! 80 const NSPointingDeviceType devtype = [event pointingDeviceType]; 81 const bool is_eraser = (devtype == NSPointingDeviceTypeEraser); 82 const bool is_pen = (devtype == NSPointingDeviceTypePen); 83 if (!is_eraser && !is_pen) { 84 return; // we ignore other things, which hopefully is right. 85 } 86 87 Cocoa_PenHandle *handle = Cocoa_FindPenByDeviceID(devid, toolid); 88 if (handle) { 89 handle->is_eraser = is_eraser; // in case this changed. 90 SDL_SendPenProximity(Cocoa_GetEventTimestamp([event timestamp]), handle->pen, _data.window, true); 91 return; // already have this one. 92 } 93 94 handle = (Cocoa_PenHandle *) SDL_calloc(1, sizeof (*handle)); 95 if (!handle) { 96 return; // oh well. 97 } 98 99 // Cocoa offers almost none of this information as specifics, but can without warning offer any of these specific things. 100 SDL_PenInfo peninfo; 101 SDL_zero(peninfo); 102 peninfo.capabilities = SDL_PEN_CAPABILITY_PRESSURE | SDL_PEN_CAPABILITY_ROTATION | SDL_PEN_CAPABILITY_XTILT | SDL_PEN_CAPABILITY_YTILT | SDL_PEN_CAPABILITY_TANGENTIAL_PRESSURE | (is_eraser ? SDL_PEN_CAPABILITY_ERASER : 0); 103 peninfo.max_tilt = 90.0f; 104 peninfo.num_buttons = 2; 105 peninfo.subtype = is_eraser ? SDL_PEN_TYPE_ERASER : SDL_PEN_TYPE_PEN; 106 107 handle->deviceid = devid; 108 handle->toolid = toolid; 109 handle->is_eraser = is_eraser; 110 handle->pen = SDL_AddPenDevice(Cocoa_GetEventTimestamp([event timestamp]), NULL, _data.window, &peninfo, handle, true); 111 if (!handle->pen) { 112 SDL_free(handle); // oh well. 113 } 114 } else { // old pen leaving! 115 Cocoa_PenHandle *handle = Cocoa_FindPenByDeviceID(devid, toolid); 116 if (handle) { 117 // We never remove pens (until shutdown), since Apple gives no indication when they are actually gone. 118 // But unless you are plugging and unplugging a tablet millions of times, generating new device IDs, this shouldn't be a massive memory drain. 119 SDL_SendPenProximity(Cocoa_GetEventTimestamp([event timestamp]), handle->pen, _data.window, false); 120 } 121 } 122} 123 124static void Cocoa_HandlePenPointEvent(SDL_CocoaWindowData *_data, NSEvent *event) 125{ 126 const Uint64 timestamp = Cocoa_GetEventTimestamp([event timestamp]); 127 Cocoa_PenHandle *handle = Cocoa_FindPenByDeviceID([event deviceID], [event pointingDeviceID]); 128 if (!handle) { 129 return; 130 } 131 132 const SDL_PenID pen = handle->pen; 133 const NSEventButtonMask buttons = [event buttonMask]; 134 const NSPoint tilt = [event tilt]; 135 const NSPoint point = [event locationInWindow]; 136 const bool is_touching = (buttons & NSEventButtonMaskPenTip) != 0; 137 SDL_Window *window = _data.window; 138 139 SDL_SendPenTouch(timestamp, pen, window, handle->is_eraser, is_touching); 140 SDL_SendPenMotion(timestamp, pen, window, (float) point.x, (float) (window->h - point.y)); 141 SDL_SendPenButton(timestamp, pen, window, 1, ((buttons & NSEventButtonMaskPenLowerSide) != 0)); 142 SDL_SendPenButton(timestamp, pen, window, 2, ((buttons & NSEventButtonMaskPenUpperSide) != 0)); 143 SDL_SendPenAxis(timestamp, pen, window, SDL_PEN_AXIS_PRESSURE, [event pressure]); 144 SDL_SendPenAxis(timestamp, pen, window, SDL_PEN_AXIS_ROTATION, [event rotation]); 145 SDL_SendPenAxis(timestamp, pen, window, SDL_PEN_AXIS_XTILT, ((float) tilt.x) * 90.0f); 146 SDL_SendPenAxis(timestamp, pen, window, SDL_PEN_AXIS_YTILT, ((float) -tilt.y) * 90.0f); 147 SDL_SendPenAxis(timestamp, pen, window, SDL_PEN_AXIS_TANGENTIAL_PRESSURE, event.tangentialPressure); 148} 149 150bool Cocoa_HandlePenEvent(SDL_CocoaWindowData *_data, NSEvent *event) 151{ 152 NSEventType type = [event type]; 153 154 if ((type != NSEventTypeTabletPoint) && (type != NSEventTypeTabletProximity)) { 155 const NSEventSubtype subtype = [event subtype]; 156 if (subtype == NSEventSubtypeTabletPoint) { 157 type = NSEventTypeTabletPoint; 158 } else if (subtype == NSEventSubtypeTabletProximity) { 159 type = NSEventTypeTabletProximity; 160 } else { 161 return false; // not a tablet event. 162 } 163 } 164 165 if (type == NSEventTypeTabletPoint) { 166 Cocoa_HandlePenPointEvent(_data, event); 167 } else if (type == NSEventTypeTabletProximity) { 168 Cocoa_HandlePenProximityEvent(_data, event); 169 } else { 170 return false; // not a tablet event. 171 } 172 173 return true; 174} 175 176static void Cocoa_FreePenHandle(SDL_PenID instance_id, void *handle, void *userdata) 177{ 178 SDL_free(handle); 179} 180 181void Cocoa_QuitPen(SDL_VideoDevice *_this) 182{ 183 SDL_RemoveAllPenDevices(Cocoa_FreePenHandle, NULL); 184} 185 186#endif // SDL_VIDEO_DRIVER_COCOA 187[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.