Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
3-manifolds
GitHub Repository: 3-manifolds/Sage_macOS
Path: blob/main/Sage_framework/files/osx.py
173 views
1
"""Inputhook for OS X
2
3
Calls NSApp / CoreFoundation APIs via ctypes.
4
"""
5
6
# obj-c boilerplate from appnope, used under BSD 2-clause
7
8
import ctypes
9
import ctypes.util
10
from threading import Event
11
12
objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("objc")) # type: ignore
13
14
void_p = ctypes.c_void_p
15
16
objc.objc_getClass.restype = void_p
17
objc.sel_registerName.restype = void_p
18
objc.objc_msgSend.restype = void_p
19
objc.objc_msgSend.argtypes = [void_p, void_p]
20
21
msg = objc.objc_msgSend
22
23
def _utf8(s):
24
"""ensure utf8 bytes"""
25
if not isinstance(s, bytes):
26
s = s.encode('utf8')
27
return s
28
29
def n(name):
30
"""create a selector name (for ObjC methods)"""
31
return objc.sel_registerName(_utf8(name))
32
33
def C(classname):
34
"""get an ObjC Class by name"""
35
return objc.objc_getClass(_utf8(classname))
36
37
# end obj-c boilerplate from appnope
38
39
# CoreFoundation C-API calls we will use:
40
CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library("CoreFoundation")) # type: ignore
41
42
CFFileDescriptorCreate = CoreFoundation.CFFileDescriptorCreate
43
CFFileDescriptorCreate.restype = void_p
44
CFFileDescriptorCreate.argtypes = [void_p, ctypes.c_int, ctypes.c_bool, void_p, void_p]
45
46
CFFileDescriptorGetNativeDescriptor = CoreFoundation.CFFileDescriptorGetNativeDescriptor
47
CFFileDescriptorGetNativeDescriptor.restype = ctypes.c_int
48
CFFileDescriptorGetNativeDescriptor.argtypes = [void_p]
49
50
CFFileDescriptorEnableCallBacks = CoreFoundation.CFFileDescriptorEnableCallBacks
51
CFFileDescriptorEnableCallBacks.restype = None
52
CFFileDescriptorEnableCallBacks.argtypes = [void_p, ctypes.c_ulong]
53
54
CFFileDescriptorCreateRunLoopSource = CoreFoundation.CFFileDescriptorCreateRunLoopSource
55
CFFileDescriptorCreateRunLoopSource.restype = void_p
56
CFFileDescriptorCreateRunLoopSource.argtypes = [void_p, void_p, void_p]
57
58
CFRunLoopGetCurrent = CoreFoundation.CFRunLoopGetCurrent
59
CFRunLoopGetCurrent.restype = void_p
60
61
CFRunLoopAddSource = CoreFoundation.CFRunLoopAddSource
62
CFRunLoopAddSource.restype = None
63
CFRunLoopAddSource.argtypes = [void_p, void_p, void_p]
64
65
CFRelease = CoreFoundation.CFRelease
66
CFRelease.restype = None
67
CFRelease.argtypes = [void_p]
68
69
CFFileDescriptorInvalidate = CoreFoundation.CFFileDescriptorInvalidate
70
CFFileDescriptorInvalidate.restype = None
71
CFFileDescriptorInvalidate.argtypes = [void_p]
72
73
# From CFFileDescriptor.h
74
kCFFileDescriptorReadCallBack = 1
75
kCFRunLoopCommonModes = void_p.in_dll(CoreFoundation, 'kCFRunLoopCommonModes')
76
77
78
def _NSApp():
79
"""Return the global NSApplication instance (NSApp)"""
80
objc.objc_msgSend.argtypes = [void_p, void_p]
81
return msg(C('NSApplication'), n('sharedApplication'))
82
83
84
def _wake(NSApp):
85
"""Wake the Application"""
86
objc.objc_msgSend.argtypes = [
87
void_p,
88
void_p,
89
void_p,
90
void_p,
91
void_p,
92
void_p,
93
void_p,
94
void_p,
95
void_p,
96
void_p,
97
void_p,
98
]
99
event = msg(
100
C("NSEvent"),
101
n(
102
"otherEventWithType:location:modifierFlags:"
103
"timestamp:windowNumber:context:subtype:data1:data2:"
104
),
105
15, # Type
106
0, # location
107
0, # flags
108
0, # timestamp
109
0, # window
110
None, # context
111
0, # subtype
112
0, # data1
113
0, # data2
114
)
115
objc.objc_msgSend.argtypes = [void_p, void_p, void_p, void_p]
116
msg(NSApp, n('postEvent:atStart:'), void_p(event), True)
117
118
119
def _input_callback(fdref, flags, info):
120
"""Callback to fire when there's input to be read"""
121
CFFileDescriptorInvalidate(fdref)
122
CFRelease(fdref)
123
NSApp = _NSApp()
124
objc.objc_msgSend.argtypes = [void_p, void_p, void_p]
125
msg(NSApp, n('stop:'), NSApp)
126
_wake(NSApp)
127
128
_c_callback_func_type = ctypes.CFUNCTYPE(None, void_p, void_p, void_p)
129
_c_input_callback = _c_callback_func_type(_input_callback)
130
131
132
def _stop_on_read(fd):
133
"""Register callback to stop eventloop when there's data on fd"""
134
fdref = CFFileDescriptorCreate(None, fd, False, _c_input_callback, None)
135
CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack)
136
source = CFFileDescriptorCreateRunLoopSource(None, fdref, 0)
137
loop = CFRunLoopGetCurrent()
138
CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes)
139
CFRelease(source)
140
141
142
def inputhook(context):
143
"""Inputhook for Cocoa (NSApp)"""
144
NSApp = _NSApp()
145
_stop_on_read(context.fileno())
146
objc.objc_msgSend.argtypes = [void_p, void_p]
147
msg(NSApp, n('run'))
148
149