-
Notifications
You must be signed in to change notification settings - Fork 1
/
touchCursorModal.lua
189 lines (164 loc) · 5.48 KB
/
touchCursorModal.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
--local keyStroke = require("keyStrokeMapper")
local module = {}
-- Settings
--[[ module.timeFrame [seconds]
If the spacebar is released within this time it will count as a real key-stroke.
If released after this time it will not trigger a space key-stroke
module.debug
Set to true to enable alerts
]]--
module.timeFrame = 0.15
module.debug = false
module.inAlfred = false
module.inParallels = false
-- Modal hotkey for Touch-cursor mode
local touchCursor = hs.hotkey.modal.new()
-- Publishes an alert if in debug mode
function notify(msg)
if module.debug then
--hs.alert(msg)
hs.notify.new({title="Hammerspoon", informativeText=msg}):send()
end
end
-- When spacebar has been held down long enough
function onCountDown()
--notify("Timer expired")
module.countDownTimer = nil
shouldSendSpace = false
end
-- Pressing space starts a timer and enters touch-cursor mode
function pressedSpace()
touchCursor:enter()
shouldSendSpace = true
module.countDownTimer = hs.timer.doAfter(module.timeFrame, onCountDown)
--notify("TouchCursor ON")
end
--[[ exits touch-cursor mode and stops timer. If spacebar has not been held down longer than
module.timeframe then a "real" space key-stroke is sent.
]]--
function releasedSpace()
--hs.alert("releasedSpace")
touchCursor:exit()
if module.countDownTimer then module.countDownTimer:stop() end
module.countDownTimer = nil
if shouldSendSpace then
--notify("sending space")
disableTC()
keyStrokeNoDelay({}, 'space')
enableTC()
end
--notify("TouchCursor OFF")
end
function holdingSpace()
--Do nothing here
--notify("Holding Space")
end
function enableTC()
--hs.alert("enableTC")
enterTC:enable()
enterTC2:enable()
enterTC3:enable()
enterTC4:enable()
end
function disableTC()
--hs.alert("disableTC")
enterTC:disable()
enterTC2:disable()
enterTC3:disable()
enterTC4:disable()
end
function onAppEvent(appName, event, app)
exitAlfred()
if appName == 'Parallels Desktop' then
if event == hs.application.watcher.activated then
--hs.alert("Disabling TC")
disableTC()
inParallels = true
elseif event == hs.application.watcher.deactivated then
--notify("Enabling TC")
inParallels = false
enableTC()
end
end
end
function enterAlfred()
if inParallels then
if not inAlfred then
--notify("Enabling touch-cursor")
inAlfred = true
enableTC()
else
inAlfred = false
--notify("Disabling touch-cursor")
disableTC()
end
end
keyStrokeNoDelay({"cmd"}, "space")
end
function exitAlfred()
inAlfred = false
if inParallels then
--notify("Disabling touch-cursor")
disableTC()
end
end
-- Helper method for sending a keystroke
function send(modifier, key)
--notify("send {" .. table.concat(modifier, ", ") .. "} " .. key)
if inAlfred or not isVirtualMachine() then
--notify('in send ' .. table.concat(modifier, ', ') .. ' ' .. key)
keyStrokeNoDelay(modifier, key)
end
end
-- Helper method for sending keystroke without Hammerspoons repeat-delay of 200 ms
function keyStrokeNoDelay(modifier, key)
hs.eventtap.event.newKeyEvent(modifier, string.lower(key), true):post()
hs.timer.usleep(1000)
hs.eventtap.event.newKeyEvent(modifier, string.lower(key), false):post()
end
function isVirtualMachine()
local app = hs.application.frontmostApplication()
--notify(app:name())
return app:name() == "Parallels Desktop"
end
-- Helper method for mapping one keystroke to another one
function map(hotkey, modifierFrom, keyFrom, modifierTo, keyTo)
hotkey:bind(modifierFrom, keyFrom, function() send(modifierTo, keyTo) end, nil, function() send(modifierTo, keyTo) end)
end
--[[ Helper method that performs all necessary mappings for arrow-keys functionality,
i.e. adds mapping for all suitable modifiers.
]]--
function mapFull(hotkey, keyFrom, keyTo)
map(hotkey, {}, keyFrom, {}, keyTo)
map(hotkey, {"shift"}, keyFrom, {"shift"}, keyTo)
map(hotkey, {"alt"}, keyFrom, {"alt"}, keyTo)
map(hotkey, {"cmd"}, keyFrom, {"cmd"}, keyTo)
map(hotkey, {"ctrl"}, keyFrom, {"ctrl"}, keyTo)
map(hotkey, {"shift", "alt"}, keyFrom, {"shift", "alt"}, keyTo)
map(hotkey, {"shift", "cmd"}, keyFrom, {"shift", "cmd"}, keyTo)
end
-- Setup space as hotkey for TouchCursor mode
enterTC = hs.hotkey.bind({}, "space", pressedSpace, releasedSpace, holdingSpace)
enterTC2 = hs.hotkey.bind({"shift"}, "space", pressedSpace, releasedSpace, holdingSpace)
enterTC3 = hs.hotkey.bind({"alt"}, "space", pressedSpace, releasedSpace, holdingSpace)
enterTC4 = hs.hotkey.bind({"shift", "alt"}, "space", pressedSpace, releasedSpace, holdingSpace)
-- hs.hotkey.bind({"ctrl", "cmd"}, "space", enterAlfred, nil, nil):enable()
appWatcher = hs.application.watcher.new(onAppEvent):start()
-- Setup arrow key navigation
mapFull(touchCursor, 'N', 'Left')
mapFull(touchCursor, 'U', 'Up')
mapFull(touchCursor, 'E', 'Down')
mapFull(touchCursor, 'I', 'Right')
-- Setup additional navigation keys
map(touchCursor, {}, 'H', {}, 'pageup')
map(touchCursor, {"shift"}, 'H', {"shift"}, 'pageup')
map(touchCursor, {}, 'K', {}, 'pagedown')
map(touchCursor, {"shift"}, 'K', {"shift"}, 'pagedown')
map(touchCursor, {}, 'L', {"cmd"}, 'Left')
map(touchCursor, {"shift"}, 'L', {"shift", "cmd"}, 'Left')
map(touchCursor, {}, 'Y', {"cmd"}, 'Right')
map(touchCursor, {"shift"}, 'Y', {"shift", "cmd"}, 'Right')
-- Setup other useful keys
map(touchCursor, {}, 41, {}, 'escape') -- Ö
map(touchCursor, {}, 'M', {}, 'forwarddelete')
return module