rb_termbox 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +11 -13
- data/README.md +14 -0
- data/ext/termbox/bytebuffer.inl +78 -0
- data/ext/termbox/extconf.rb +3 -0
- data/ext/termbox/input.inl +96 -0
- data/ext/termbox/term.inl +291 -0
- data/ext/termbox/termbox.c +536 -0
- data/ext/termbox/termbox.h +226 -0
- data/ext/termbox/utf8.c +79 -0
- data/lib/termbox.rb +1 -1
- data/lib/termbox/colors.rb +9 -8
- data/lib/termbox/keys.rb +2 -1
- data/lib/termbox/version.rb +1 -1
- data/rb_termbox.gemspec +6 -7
- data/sample/all_colors.rb +37 -0
- data/sample/keyboard.rb +15 -15
- metadata +65 -73
- data/README +0 -10
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 987138e46b00b9460893570cc75437b50c569fa1
|
4
|
+
data.tar.gz: 80c60904af6281c8b8a90b9a021774b6b3402476
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1eb154f3f71cb796a8e7d0ff30e16d8e3ba6db432cb45e1b15edd2d536e23cc529e5ec6417a888b99c3bed0681693be4eb5f8d6ad916d971efdb7bda69100c04
|
7
|
+
data.tar.gz: fb941fb5601b298a72f858c19b177cd2b322768e7245ad3ef9603a15c822eae50dc78cc6efae80576f9a74c8716de472a90c8c85b5274abc029d867a8a4f9f39
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -5,20 +5,18 @@ PATH
|
|
5
5
|
ffi
|
6
6
|
|
7
7
|
GEM
|
8
|
-
remote:
|
8
|
+
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
diff-lcs (1.
|
11
|
-
ffi (1.
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
rspec-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
rspec-
|
20
|
-
diff-lcs (~> 1.1.2)
|
21
|
-
rspec-mocks (2.5.0)
|
10
|
+
diff-lcs (1.2.5)
|
11
|
+
ffi (1.9.3)
|
12
|
+
rspec (2.14.1)
|
13
|
+
rspec-core (~> 2.14.0)
|
14
|
+
rspec-expectations (~> 2.14.0)
|
15
|
+
rspec-mocks (~> 2.14.0)
|
16
|
+
rspec-core (2.14.7)
|
17
|
+
rspec-expectations (2.14.4)
|
18
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
19
|
+
rspec-mocks (2.14.4)
|
22
20
|
|
23
21
|
PLATFORMS
|
24
22
|
ruby
|
data/README.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
rb_termbox - [Termbox](https://github.com/nsf/termbox) binding
|
2
|
+
====================
|
3
|
+
|
4
|
+
### Development Notes ###
|
5
|
+
- Run ```ruby ext/termbox/extconf.rb && make```
|
6
|
+
- Install bundler and ````bundle install````
|
7
|
+
- Run ruby sample/keyboard.rb to get a feel for what you can do. It's a partial port of termbox's own sample keyboard application. (Ctrl + Q to quit)
|
8
|
+
|
9
|
+
WIP Keyboard example:
|
10
|
+
<img src="http://i.imgur.com/aslMxFi.png"/>
|
11
|
+
|
12
|
+
### Contributors ###
|
13
|
+
James Cook
|
14
|
+
Paul Schuegraf [@pscheugr](https://github.com/pschuegr)
|
@@ -0,0 +1,78 @@
|
|
1
|
+
struct bytebuffer {
|
2
|
+
char *buf;
|
3
|
+
int len;
|
4
|
+
int cap;
|
5
|
+
};
|
6
|
+
|
7
|
+
static void bytebuffer_reserve(struct bytebuffer *b, int cap) {
|
8
|
+
if (b->cap >= cap) {
|
9
|
+
return;
|
10
|
+
}
|
11
|
+
|
12
|
+
// prefer doubling capacity
|
13
|
+
if (b->cap * 2 >= cap) {
|
14
|
+
cap = b->cap * 2;
|
15
|
+
}
|
16
|
+
|
17
|
+
char *newbuf = malloc(cap);
|
18
|
+
if (b->len > 0) {
|
19
|
+
// copy what was there, b->len > 0 assumes b->buf != null
|
20
|
+
memcpy(newbuf, b->buf, b->len);
|
21
|
+
}
|
22
|
+
if (b->buf) {
|
23
|
+
// in case there was an allocated buffer, free it
|
24
|
+
free(b->buf);
|
25
|
+
}
|
26
|
+
b->buf = newbuf;
|
27
|
+
b->cap = cap;
|
28
|
+
}
|
29
|
+
|
30
|
+
static void bytebuffer_init(struct bytebuffer *b, int cap) {
|
31
|
+
b->cap = 0;
|
32
|
+
b->len = 0;
|
33
|
+
b->buf = 0;
|
34
|
+
|
35
|
+
if (cap > 0) {
|
36
|
+
b->cap = cap;
|
37
|
+
b->buf = malloc(cap); // just assume malloc works always
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
static void bytebuffer_free(struct bytebuffer *b) {
|
42
|
+
if (b->buf)
|
43
|
+
free(b->buf);
|
44
|
+
}
|
45
|
+
|
46
|
+
static void bytebuffer_clear(struct bytebuffer *b) {
|
47
|
+
b->len = 0;
|
48
|
+
}
|
49
|
+
|
50
|
+
static void bytebuffer_append(struct bytebuffer *b, const char *data, int len) {
|
51
|
+
bytebuffer_reserve(b, b->len + len);
|
52
|
+
memcpy(b->buf + b->len, data, len);
|
53
|
+
b->len += len;
|
54
|
+
}
|
55
|
+
|
56
|
+
static void bytebuffer_puts(struct bytebuffer *b, const char *str) {
|
57
|
+
bytebuffer_append(b, str, strlen(str));
|
58
|
+
}
|
59
|
+
|
60
|
+
static void bytebuffer_resize(struct bytebuffer *b, int len) {
|
61
|
+
bytebuffer_reserve(b, len);
|
62
|
+
b->len = len;
|
63
|
+
}
|
64
|
+
|
65
|
+
static void bytebuffer_flush(struct bytebuffer *b, int fd) {
|
66
|
+
write(fd, b->buf, b->len);
|
67
|
+
bytebuffer_clear(b);
|
68
|
+
}
|
69
|
+
|
70
|
+
static void bytebuffer_truncate(struct bytebuffer *b, int n) {
|
71
|
+
if (n <= 0)
|
72
|
+
return;
|
73
|
+
if (n > b->len)
|
74
|
+
n = b->len;
|
75
|
+
const int nmove = b->len - n;
|
76
|
+
memmove(b->buf, b->buf+n, nmove);
|
77
|
+
b->len -= n;
|
78
|
+
}
|
@@ -0,0 +1,96 @@
|
|
1
|
+
// if s1 starts with s2 returns true, else false
|
2
|
+
// len is the length of s1
|
3
|
+
// s2 should be null-terminated
|
4
|
+
static bool starts_with(const char *s1, int len, const char *s2)
|
5
|
+
{
|
6
|
+
int n = 0;
|
7
|
+
while (*s2 && n < len) {
|
8
|
+
if (*s1++ != *s2++)
|
9
|
+
return false;
|
10
|
+
n++;
|
11
|
+
}
|
12
|
+
return *s2 == 0;
|
13
|
+
}
|
14
|
+
|
15
|
+
// convert escape sequence to event, and return consumed bytes on success (failure == 0)
|
16
|
+
static int parse_escape_seq(struct tb_event *event, const char *buf, int len)
|
17
|
+
{
|
18
|
+
// it's pretty simple here, find 'starts_with' match and return
|
19
|
+
// success, else return failure
|
20
|
+
int i;
|
21
|
+
for (i = 0; keys[i]; i++) {
|
22
|
+
if (starts_with(buf, len, keys[i])) {
|
23
|
+
event->ch = 0;
|
24
|
+
event->key = 0xFFFF-i;
|
25
|
+
return strlen(keys[i]);
|
26
|
+
}
|
27
|
+
}
|
28
|
+
return 0;
|
29
|
+
}
|
30
|
+
|
31
|
+
static bool extract_event(struct tb_event *event, struct bytebuffer *inbuf, int inputmode)
|
32
|
+
{
|
33
|
+
const char *buf = inbuf->buf;
|
34
|
+
const int len = inbuf->len;
|
35
|
+
if (len == 0)
|
36
|
+
return false;
|
37
|
+
|
38
|
+
if (buf[0] == '\033') {
|
39
|
+
int n = parse_escape_seq(event, buf, len);
|
40
|
+
if (n) {
|
41
|
+
bytebuffer_truncate(inbuf, n);
|
42
|
+
return true;
|
43
|
+
} else {
|
44
|
+
// it's not escape sequence, then it's ALT or ESC,
|
45
|
+
// check inputmode
|
46
|
+
switch (inputmode) {
|
47
|
+
case TB_INPUT_ESC:
|
48
|
+
// if we're in escape mode, fill ESC event, pop
|
49
|
+
// buffer, return success
|
50
|
+
event->ch = 0;
|
51
|
+
event->key = TB_KEY_ESC;
|
52
|
+
event->mod = 0;
|
53
|
+
bytebuffer_truncate(inbuf, 1);
|
54
|
+
return true;
|
55
|
+
case TB_INPUT_ALT:
|
56
|
+
// if we're in alt mode, set ALT modifier to
|
57
|
+
// event and redo parsing
|
58
|
+
event->mod = TB_MOD_ALT;
|
59
|
+
bytebuffer_truncate(inbuf, 1);
|
60
|
+
return extract_event(event, inbuf, inputmode);
|
61
|
+
default:
|
62
|
+
assert(!"never got here");
|
63
|
+
break;
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
// if we're here, this is not an escape sequence and not an alt sequence
|
69
|
+
// so, it's a FUNCTIONAL KEY or a UNICODE character
|
70
|
+
|
71
|
+
// first of all check if it's a functional key
|
72
|
+
if ((unsigned char)buf[0] <= TB_KEY_SPACE ||
|
73
|
+
(unsigned char)buf[0] == TB_KEY_BACKSPACE2)
|
74
|
+
{
|
75
|
+
// fill event, pop buffer, return success */
|
76
|
+
event->ch = 0;
|
77
|
+
event->key = (uint16_t)buf[0];
|
78
|
+
bytebuffer_truncate(inbuf, 1);
|
79
|
+
return true;
|
80
|
+
}
|
81
|
+
|
82
|
+
// feh... we got utf8 here
|
83
|
+
|
84
|
+
// check if there is all bytes
|
85
|
+
if (len >= tb_utf8_char_length(buf[0])) {
|
86
|
+
/* everything ok, fill event, pop buffer, return success */
|
87
|
+
tb_utf8_char_to_unicode(&event->ch, buf);
|
88
|
+
event->key = 0;
|
89
|
+
bytebuffer_truncate(inbuf, tb_utf8_char_length(buf[0]));
|
90
|
+
return true;
|
91
|
+
}
|
92
|
+
|
93
|
+
// event isn't recognized, perhaps there is not enough bytes in utf8
|
94
|
+
// sequence
|
95
|
+
return false;
|
96
|
+
}
|
@@ -0,0 +1,291 @@
|
|
1
|
+
enum {
|
2
|
+
T_ENTER_CA,
|
3
|
+
T_EXIT_CA,
|
4
|
+
T_SHOW_CURSOR,
|
5
|
+
T_HIDE_CURSOR,
|
6
|
+
T_CLEAR_SCREEN,
|
7
|
+
T_SGR0,
|
8
|
+
T_UNDERLINE,
|
9
|
+
T_BOLD,
|
10
|
+
T_BLINK,
|
11
|
+
T_REVERSE,
|
12
|
+
T_ENTER_KEYPAD,
|
13
|
+
T_EXIT_KEYPAD,
|
14
|
+
T_FUNCS_NUM,
|
15
|
+
};
|
16
|
+
|
17
|
+
#define EUNSUPPORTED_TERM -1
|
18
|
+
|
19
|
+
// rxvt-256color
|
20
|
+
static const char *rxvt_256color_keys[] = {
|
21
|
+
"\033[11~","\033[12~","\033[13~","\033[14~","\033[15~","\033[17~","\033[18~","\033[19~","\033[20~","\033[21~","\033[23~","\033[24~","\033[2~","\033[3~","\033[7~","\033[8~","\033[5~","\033[6~","\033[A","\033[B","\033[D","\033[C", 0
|
22
|
+
};
|
23
|
+
static const char *rxvt_256color_funcs[] = {
|
24
|
+
"\0337\033[?47h", "\033[2J\033[?47l\0338", "\033[?25h", "\033[?25l", "\033[H\033[2J", "\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "\033=", "\033>",
|
25
|
+
};
|
26
|
+
|
27
|
+
// Eterm
|
28
|
+
static const char *eterm_keys[] = {
|
29
|
+
"\033[11~","\033[12~","\033[13~","\033[14~","\033[15~","\033[17~","\033[18~","\033[19~","\033[20~","\033[21~","\033[23~","\033[24~","\033[2~","\033[3~","\033[7~","\033[8~","\033[5~","\033[6~","\033[A","\033[B","\033[D","\033[C", 0
|
30
|
+
};
|
31
|
+
static const char *eterm_funcs[] = {
|
32
|
+
"\0337\033[?47h", "\033[2J\033[?47l\0338", "\033[?25h", "\033[?25l", "\033[H\033[2J", "\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "", "",
|
33
|
+
};
|
34
|
+
|
35
|
+
// screen
|
36
|
+
static const char *screen_keys[] = {
|
37
|
+
"\033OP","\033OQ","\033OR","\033OS","\033[15~","\033[17~","\033[18~","\033[19~","\033[20~","\033[21~","\033[23~","\033[24~","\033[2~","\033[3~","\033[1~","\033[4~","\033[5~","\033[6~","\033OA","\033OB","\033OD","\033OC", 0
|
38
|
+
};
|
39
|
+
static const char *screen_funcs[] = {
|
40
|
+
"\033[?1049h", "\033[?1049l", "\033[34h\033[?25h", "\033[?25l", "\033[H\033[J", "\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "\033[?1h\033=", "\033[?1l\033>",
|
41
|
+
};
|
42
|
+
|
43
|
+
// rxvt-unicode
|
44
|
+
static const char *rxvt_unicode_keys[] = {
|
45
|
+
"\033[11~","\033[12~","\033[13~","\033[14~","\033[15~","\033[17~","\033[18~","\033[19~","\033[20~","\033[21~","\033[23~","\033[24~","\033[2~","\033[3~","\033[7~","\033[8~","\033[5~","\033[6~","\033[A","\033[B","\033[D","\033[C", 0
|
46
|
+
};
|
47
|
+
static const char *rxvt_unicode_funcs[] = {
|
48
|
+
"\033[?1049h", "\033[r\033[?1049l", "\033[?25h", "\033[?25l", "\033[H\033[2J", "\033[m\033(B", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "\033=", "\033>",
|
49
|
+
};
|
50
|
+
|
51
|
+
// linux
|
52
|
+
static const char *linux_keys[] = {
|
53
|
+
"\033[[A","\033[[B","\033[[C","\033[[D","\033[[E","\033[17~","\033[18~","\033[19~","\033[20~","\033[21~","\033[23~","\033[24~","\033[2~","\033[3~","\033[1~","\033[4~","\033[5~","\033[6~","\033[A","\033[B","\033[D","\033[C", 0
|
54
|
+
};
|
55
|
+
static const char *linux_funcs[] = {
|
56
|
+
"", "", "\033[?25h\033[?0c", "\033[?25l\033[?1c", "\033[H\033[J", "\033[0;10m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "", "",
|
57
|
+
};
|
58
|
+
|
59
|
+
// xterm
|
60
|
+
static const char *xterm_keys[] = {
|
61
|
+
"\033OP","\033OQ","\033OR","\033OS","\033[15~","\033[17~","\033[18~","\033[19~","\033[20~","\033[21~","\033[23~","\033[24~","\033[2~","\033[3~","\033OH","\033OF","\033[5~","\033[6~","\033OA","\033OB","\033OD","\033OC", 0
|
62
|
+
};
|
63
|
+
static const char *xterm_funcs[] = {
|
64
|
+
"\033[?1049h", "\033[?1049l", "\033[?12l\033[?25h", "\033[?25l", "\033[H\033[2J", "\033(B\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "\033[?1h\033=", "\033[?1l\033>",
|
65
|
+
};
|
66
|
+
|
67
|
+
static struct term {
|
68
|
+
const char *name;
|
69
|
+
const char **keys;
|
70
|
+
const char **funcs;
|
71
|
+
} terms[] = {
|
72
|
+
{"rxvt-256color", rxvt_256color_keys, rxvt_256color_funcs},
|
73
|
+
{"Eterm", eterm_keys, eterm_funcs},
|
74
|
+
{"screen", screen_keys, screen_funcs},
|
75
|
+
{"rxvt-unicode", rxvt_unicode_keys, rxvt_unicode_funcs},
|
76
|
+
{"linux", linux_keys, linux_funcs},
|
77
|
+
{"xterm", xterm_keys, xterm_funcs},
|
78
|
+
{0, 0, 0},
|
79
|
+
};
|
80
|
+
|
81
|
+
static bool init_from_terminfo = false;
|
82
|
+
static const char **keys;
|
83
|
+
static const char **funcs;
|
84
|
+
|
85
|
+
static int try_compatible(const char *term, const char *name,
|
86
|
+
const char **tkeys, const char **tfuncs)
|
87
|
+
{
|
88
|
+
if (strstr(term, name)) {
|
89
|
+
keys = tkeys;
|
90
|
+
funcs = tfuncs;
|
91
|
+
return 0;
|
92
|
+
}
|
93
|
+
|
94
|
+
return EUNSUPPORTED_TERM;
|
95
|
+
}
|
96
|
+
|
97
|
+
static int init_term_builtin(void)
|
98
|
+
{
|
99
|
+
int i;
|
100
|
+
const char *term = getenv("TERM");
|
101
|
+
|
102
|
+
if (term) {
|
103
|
+
for (i = 0; terms[i].name; i++) {
|
104
|
+
if (!strcmp(terms[i].name, term)) {
|
105
|
+
keys = terms[i].keys;
|
106
|
+
funcs = terms[i].funcs;
|
107
|
+
return 0;
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
/* let's do some heuristic, maybe it's a compatible terminal */
|
112
|
+
if (try_compatible(term, "xterm", xterm_keys, xterm_funcs) == 0)
|
113
|
+
return 0;
|
114
|
+
if (try_compatible(term, "rxvt", rxvt_unicode_keys, rxvt_unicode_funcs) == 0)
|
115
|
+
return 0;
|
116
|
+
if (try_compatible(term, "linux", linux_keys, linux_funcs) == 0)
|
117
|
+
return 0;
|
118
|
+
if (try_compatible(term, "Eterm", eterm_keys, eterm_funcs) == 0)
|
119
|
+
return 0;
|
120
|
+
if (try_compatible(term, "screen", screen_keys, screen_funcs) == 0)
|
121
|
+
return 0;
|
122
|
+
/* let's assume that 'cygwin' is xterm compatible */
|
123
|
+
if (try_compatible(term, "cygwin", xterm_keys, xterm_funcs) == 0)
|
124
|
+
return 0;
|
125
|
+
}
|
126
|
+
|
127
|
+
return EUNSUPPORTED_TERM;
|
128
|
+
}
|
129
|
+
|
130
|
+
//----------------------------------------------------------------------
|
131
|
+
// terminfo
|
132
|
+
//----------------------------------------------------------------------
|
133
|
+
|
134
|
+
static char *read_file(const char *file) {
|
135
|
+
FILE *f = fopen(file, "rb");
|
136
|
+
if (!f)
|
137
|
+
return 0;
|
138
|
+
|
139
|
+
struct stat st;
|
140
|
+
if (fstat(fileno(f), &st) != 0) {
|
141
|
+
fclose(f);
|
142
|
+
return 0;
|
143
|
+
}
|
144
|
+
|
145
|
+
char *data = malloc(st.st_size);
|
146
|
+
if (!data) {
|
147
|
+
fclose(f);
|
148
|
+
return 0;
|
149
|
+
}
|
150
|
+
|
151
|
+
if (fread(data, 1, st.st_size, f) != (size_t)st.st_size) {
|
152
|
+
fclose(f);
|
153
|
+
free(data);
|
154
|
+
return 0;
|
155
|
+
}
|
156
|
+
|
157
|
+
fclose(f);
|
158
|
+
return data;
|
159
|
+
}
|
160
|
+
|
161
|
+
static char *terminfo_try_path(const char *path, const char *term) {
|
162
|
+
char tmp[4096];
|
163
|
+
snprintf(tmp, sizeof(tmp), "%s/%c/%s", path, term[0], term);
|
164
|
+
tmp[sizeof(tmp)-1] = '\0';
|
165
|
+
char *data = read_file(tmp);
|
166
|
+
if (data) {
|
167
|
+
return data;
|
168
|
+
}
|
169
|
+
|
170
|
+
// fallback to darwin specific dirs structure
|
171
|
+
snprintf(tmp, sizeof(tmp), "%s/%x/%s", path, term[0], term);
|
172
|
+
tmp[sizeof(tmp)-1] = '\0';
|
173
|
+
return read_file(tmp);
|
174
|
+
}
|
175
|
+
|
176
|
+
static char *load_terminfo(void) {
|
177
|
+
char tmp[4096];
|
178
|
+
const char *term = getenv("TERM");
|
179
|
+
if (!term) {
|
180
|
+
return 0;
|
181
|
+
}
|
182
|
+
|
183
|
+
// if TERMINFO is set, no other directory should be searched
|
184
|
+
const char *terminfo = getenv("TERMINFO");
|
185
|
+
if (terminfo) {
|
186
|
+
return terminfo_try_path(terminfo, term);
|
187
|
+
}
|
188
|
+
|
189
|
+
// next, consider ~/.terminfo
|
190
|
+
const char *home = getenv("HOME");
|
191
|
+
if (home) {
|
192
|
+
snprintf(tmp, sizeof(tmp), "%s/.terminfo", home);
|
193
|
+
tmp[sizeof(tmp)-1] = '\0';
|
194
|
+
char *data = terminfo_try_path(tmp, term);
|
195
|
+
if (data)
|
196
|
+
return data;
|
197
|
+
}
|
198
|
+
|
199
|
+
// next, TERMINFO_DIRS
|
200
|
+
const char *dirs = getenv("TERMINFO_DIRS");
|
201
|
+
if (dirs) {
|
202
|
+
snprintf(tmp, sizeof(tmp), "%s", dirs);
|
203
|
+
tmp[sizeof(tmp)-1] = '\0';
|
204
|
+
char *dir = strtok(tmp, ":");
|
205
|
+
while (dir) {
|
206
|
+
const char *cdir = dir;
|
207
|
+
if (strcmp(cdir, "") == 0) {
|
208
|
+
cdir = "/usr/share/terminfo";
|
209
|
+
}
|
210
|
+
char *data = terminfo_try_path(cdir, term);
|
211
|
+
if (data)
|
212
|
+
return data;
|
213
|
+
dir = strtok(0, ":");
|
214
|
+
}
|
215
|
+
}
|
216
|
+
|
217
|
+
// fallback to /usr/share/terminfo
|
218
|
+
return terminfo_try_path("/usr/share/terminfo", term);
|
219
|
+
}
|
220
|
+
|
221
|
+
#define TI_MAGIC 0432
|
222
|
+
#define TI_HEADER_LENGTH 12
|
223
|
+
#define TB_KEYS_NUM 22
|
224
|
+
|
225
|
+
static const char *terminfo_copy_string(char *data, int str, int table) {
|
226
|
+
const int16_t off = *(int16_t*)(data + str);
|
227
|
+
const char *src = data + table + off;
|
228
|
+
int len = strlen(src);
|
229
|
+
char *dst = malloc(len+1);
|
230
|
+
strcpy(dst, src);
|
231
|
+
return dst;
|
232
|
+
}
|
233
|
+
|
234
|
+
static const int16_t ti_funcs[] = {
|
235
|
+
28, 40, 16, 13, 5, 39, 36, 27, 26, 34, 89, 88,
|
236
|
+
};
|
237
|
+
|
238
|
+
static const int16_t ti_keys[] = {
|
239
|
+
66, 68 /* apparently not a typo; 67 is F10 for whatever reason */, 69,
|
240
|
+
70, 71, 72, 73, 74, 75, 67, 216, 217, 77, 59, 76, 164, 82, 81, 87, 61,
|
241
|
+
79, 83,
|
242
|
+
};
|
243
|
+
|
244
|
+
static int init_term(void) {
|
245
|
+
int i;
|
246
|
+
char *data = load_terminfo();
|
247
|
+
if (!data) {
|
248
|
+
init_from_terminfo = false;
|
249
|
+
return init_term_builtin();
|
250
|
+
}
|
251
|
+
|
252
|
+
int16_t *header = (int16_t*)data;
|
253
|
+
if ((header[1] + header[2]) % 2) {
|
254
|
+
// old quirk to align everything on word boundaries
|
255
|
+
header[2] += 1;
|
256
|
+
}
|
257
|
+
|
258
|
+
const int str_offset = TI_HEADER_LENGTH +
|
259
|
+
header[1] + header[2] + 2 * header[3];
|
260
|
+
const int table_offset = str_offset + 2 * header[4];
|
261
|
+
|
262
|
+
keys = malloc(sizeof(const char*) * (TB_KEYS_NUM+1));
|
263
|
+
for (i = 0; i < TB_KEYS_NUM; i++) {
|
264
|
+
keys[i] = terminfo_copy_string(data,
|
265
|
+
str_offset + 2 * ti_keys[i], table_offset);
|
266
|
+
}
|
267
|
+
keys[TB_KEYS_NUM] = 0;
|
268
|
+
|
269
|
+
funcs = malloc(sizeof(const char*) * T_FUNCS_NUM);
|
270
|
+
for (i = 0; i < T_FUNCS_NUM; i++) {
|
271
|
+
funcs[i] = terminfo_copy_string(data,
|
272
|
+
str_offset + 2 * ti_funcs[i], table_offset);
|
273
|
+
}
|
274
|
+
|
275
|
+
init_from_terminfo = true;
|
276
|
+
return 0;
|
277
|
+
}
|
278
|
+
|
279
|
+
static void shutdown_term(void) {
|
280
|
+
if (init_from_terminfo) {
|
281
|
+
int i;
|
282
|
+
for (i = 0; i < TB_KEYS_NUM; i++) {
|
283
|
+
free((void*)keys[i]);
|
284
|
+
}
|
285
|
+
for (i = 0; i < T_FUNCS_NUM; i++) {
|
286
|
+
free((void*)funcs[i]);
|
287
|
+
}
|
288
|
+
free(keys);
|
289
|
+
free(funcs);
|
290
|
+
}
|
291
|
+
}
|