-
Notifications
You must be signed in to change notification settings - Fork 11
/
hotstrings.cr
79 lines (71 loc) · 2.41 KB
/
hotstrings.cr
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
require "x11"
module Run
alias HotstringAbbrevKeysyms = StaticArray(Char, 30)
# Handles key presses with an internal buffer and calls threads
# on hotstring match.
class Hotstrings
@hotstrings = [] of Hotstring
@runner : Runner
def initialize(@runner, @end_chars)
end
def run
@runner.display.register_key_listener do |key_event, keysym, char, is_paused|
handle_event(key_event, keysym, char, is_paused)
end
end
def add(hotstring)
@hotstrings << hotstring
end
# Not using `String` here because it's more convenient (and also faster) to just
# move a char* pointer around
@key_buff = HotstringAbbrevKeysyms.new('0')
@key_buff_i = 0_u8
@end_chars = [] of Char
@candidate : Hotstring? = nil
@modifier_keysyms : StaticArray(Int32, 13) = StaticArray[::X11::XK_Shift_L, ::X11::XK_Shift_R, ::X11::XK_Control_L, ::X11::XK_Control_R, ::X11::XK_Caps_Lock, ::X11::XK_Shift_Lock, ::X11::XK_Meta_L, ::X11::XK_Meta_R, ::X11::XK_Alt_L, ::X11::XK_Alt_R, ::X11::XK_Super_L, ::X11::XK_Super_R, ::X11::XK_Num_Lock]
def handle_event(key_event, keysym, char, is_paused)
return if is_paused
up = key_event.type == ::X11::KeyPress || key_event.type == ::X11::ButtonPress
return if ! up
prev_candidate = @candidate
@candidate = nil
if ! char
if @modifier_keysyms.includes? keysym
# left/right buttons etc. should cancel current buffer but modifiers not: keep
@candidate = prev_candidate
else
@key_buff_i = 0_u8
end
else
normal_keypress = (::X11::ControlMask | ::X11::Mod1Mask | ::X11::Mod4Mask | ::X11::Mod5Mask) & key_event.state == 0
if normal_keypress
if char == '\b' # ::X11::XK_BackSpace
@key_buff_i -= 1 if @key_buff_i > 0
elsif @end_chars.includes?(char)
@key_buff_i = 0_u8
if ! prev_candidate.nil?
@runner.set_global_built_in_static_var("A_EndChar", char.to_s)
prev_candidate.trigger(@runner, end_char_key_event: key_event)
end
else
@key_buff_i = 0_u8 if @key_buff_i > 29
@key_buff[@key_buff_i] = char
@key_buff_i += 1
match = @hotstrings.find { |hs| hs.keysyms_equal?(@key_buff, @key_buff_i) }
if match
if match.immediate
@key_buff_i = 0_u8
@runner.set_global_built_in_static_var("A_EndChar", "")
match.trigger(@runner)
else
@candidate = match
end
end
end
else
@key_buff_i = 0_u8
end
end
end
end
end