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
|
package main
// #cgo linux LDFLAGS: -lX11 -lXtst -lXi
// #include "keyboard_writer.h"
// #include "keyboard_reader.h"
import "C"
import (
"errors"
"fmt"
"github.com/BurntSushi/toml"
"github.com/sirupsen/logrus"
"reflect"
"strings"
"time"
)
type tomlConfig struct {
Bindings map[string]binding
}
type binding struct {
Keypress string
Text string
}
func main() {
// Startup Load the config
config, err := get_config()
if err != nil {
logrus.Println(err)
return
}
for {
expansion := wait_for_autocomplete(config)
logrus.Println(fmt.Sprintf("executing: %s", expansion))
time.Sleep(100 * time.Millisecond)
for _, v := range expansion {
cs := C.CString(char_to_x11(string(v)))
if stringInSlice(string(v), needsShift) {
C.x11_key_shift(cs)
} else {
C.x11_key(cs)
}
}
}
}
func get_config() (tomlConfig, error) {
var config tomlConfig
if _, err := toml.DecodeFile("incantation.toml", &config); err != nil {
return config, errors.New("Can't load config file")
}
return config, nil
}
func wait_for_autocomplete(config tomlConfig) string {
max_length := 10
buffer := make([]string, max_length)
for {
key_press := x11_to_char(C.GoString(C.get_key()))
// Cut down length
if len(buffer) == max_length {
buffer = buffer[1:]
}
buffer = append(buffer, key_press)
logrus.Println(strings.Join(buffer, ", "))
// Check for expansion matches, windowing through buffer
for _, binding := range config.Bindings {
// Build kepress string into slice for slice comparison
keypress_slice := make([]string, 0)
for _, v := range binding.Keypress {
keypress_slice = append(keypress_slice, string(v))
}
for i := 0; i < len(buffer)-len(keypress_slice)+1; i++ {
tmp_buf := buffer[i : i+len(keypress_slice)]
if reflect.DeepEqual(tmp_buf, keypress_slice) {
// Erase the keypresses
for range binding.Keypress {
cs := C.CString("BackSpace")
C.x11_key(cs)
}
return binding.Text
}
}
}
}
}
func char_to_x11(code string) string {
for k, v := range x11Map {
if k == code {
return v
}
}
return code
}
func x11_to_char(code string) string {
for k, v := range x11Map {
if v == code {
return k
}
}
return code
}
func stringInSlice(a string, list []string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}
|