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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
|
//Input Method Functions and Variables
//#include "imtable.h"
#include "boshiamy.h"
#define IM_BUFFER_LEN 32
#define IM_PREVIEW 1
#define IM_PREVIEW_ENTRIES 6
#define IM_PREVIEW_WIDTH 4*IM_PREVIEW_ENTRIES
#define ENTER_KEY 0x0D
#define BACKSPACE_KEY 0x7F
//setting it to the actual escape character interferes with arrow keys and
//whatnot
//#define ESCAPE_KEY 0x1B
#define ESCAPE_KEY '`'
//Vertical Tab Ctrl+K
#define TOGGLE_KEY 0x0B
#define IM_KEY_RANGE_LEN 7
//Array of Input method key ranges(inclusive) seperate from the above
char im_key_ranges[IM_KEY_RANGE_LEN][2] = {
{'a','z'},
{'0','9'},
{' ',' '},
{',',','},
{'.','.'},
{'[','['},
{']',']'},
};
int is_im_key(char input) {
for (int i = 0; i < IM_KEY_RANGE_LEN; i++) {
if (input >= im_key_ranges[i][0] && input <= im_key_ranges[i][1]) {
return 1;
}
}
return 0;
}
char im_buffer[IM_BUFFER_LEN+1];
char im_buffer_pos = 0;
int im_on = 1;
//clears the im buffer
void clear_im_buffer() {
im_buffer[0] = 0;
im_buffer_pos = 0;
}
//recursive search, returns -1 on failure
//searches from [start, end),
//can limit itself to n bytes, if n=0, use IM_TABLE_ENTRY_LEN
int im_search(char * input, int start, int end, int n) {
if (n == 0) {
n = IM_TABLE_ENTRY_LEN;
}
// 0 width search
if (end <= start) {
return -1;
}
//test for middle, works even for 1 width middle=start
int middle = start + (end-start)/2;
//printf("testing:%s\n",im_table[middle][0]);
int test = strncmp(im_table[middle][0], input, n);
if (test == 0) {
return middle;
}
//special case for width 1,2 region
if ((end - start) == 1) {
if (test == 0) {
return start;
} else {
return -1;
}
}
if (test == 0) {
return 0;
} else {
if (test > 0) {
return im_search(input,start,middle,n);
} else {
return im_search(input,middle,end,n);
}
}
}
//update_im_state is fed input characters 1 at a time, and gives 0 to
//IM_BUFFER_LEN output characters.
//returns output len
int update_im_state(char input, char * output) {
if (input == TOGGLE_KEY) {
im_on = !im_on;
//clears the im buffer if its toggling off
if (!im_on) {
clear_im_buffer();
}
}
//just passthrough if the im is off
if (!im_on) {
output[0] = input;
output[1] = 0;
return 1;
}
if ( is_im_key(input) ) {
//check if there's enough room in the im buffer
if ( (im_buffer_pos < IM_BUFFER_LEN) && (im_buffer_pos < IM_TABLE_ENTRY_LEN) ){
im_buffer[im_buffer_pos] = input;
im_buffer_pos++;
im_buffer[im_buffer_pos] = 0;
} else {
//passthrough
output[0] = input;
output[1] = 0;
return 1;
}
//if there's a match return it
int im_entry = im_search(im_buffer, 0, IM_TABLE_LEN, 0);
if (im_entry != -1) {
//clear the buffer
clear_im_buffer();
strncpy(output, im_table[im_entry][1], IM_TABLE_ENTRY_LEN);
return strlen(im_table[im_entry][1]);
} else {
return 0;
}
} else {
//these only do something if there's something in the buffer, otherwise
//passthrough
if (im_buffer_pos > 0) {
switch (input) {
//escape, cancels
case ESCAPE_KEY:
clear_im_buffer();
return 0;
break;
//enter, enters the buffer instead of sending it
//to im
case ENTER_KEY:
strncpy(output, im_buffer, IM_BUFFER_LEN);
int tmp = im_buffer_pos;
clear_im_buffer();
return tmp;
break;
//backspace
case BACKSPACE_KEY:
if (im_buffer_pos > 0) {
im_buffer_pos--;
im_buffer[im_buffer_pos] = 0;
}
return 0;
break;
}
}
}
//default behavior of passthrough
output[0] = input;
output[1] = 0;
return 1;
}
//prints im preview, assumes im_disp already moved it to the proper location
void im_preview(int fd, int trows, int tcols) {
//searches for any im entries that match the im buffer, up to the
//im_buffer length, because it's branching search it's not guaranteed to
//be the first entry in the table that matches
int first_entry = im_search(im_buffer, 0, IM_TABLE_LEN, im_buffer_pos);
if (first_entry == -1) {
return;
}
//keeps iterating until it finds the first entry in the table that
//matches
for (int i = first_entry; i>0 && i < IM_TABLE_LEN && (!strncmp(im_table[i][0],im_buffer,im_buffer_pos)); i--) {
first_entry = i;
}
//preview buffer, each utf8 char could be up to 4 bytes, each new entry
//catted on could be IM_TABLE_ENTRY_LEN*2 before next detection in loop,
//so that + 1 margin for null byte
char preview_buffer[IM_PREVIEW_ENTRIES*IM_TABLE_ENTRY_LEN*2+1] = "";
//tracks how many entries we've added to the buffer so far
int k = 0;
for (int j = first_entry; j> 0 && j < IM_TABLE_LEN && (!strncmp(im_table[j][0],im_buffer,im_buffer_pos)); j++) {
if (k >= IM_PREVIEW_ENTRIES) {
break;
}
//even if the string is the same as im_buffer_pos, it will point
//to a null pointer, which is treated as empty
strncat(preview_buffer,&(im_table[j][0][im_buffer_pos]),1);
strncat(preview_buffer,":",1);
//assuming that each output is only 2 characters wide display
strncat(preview_buffer,im_table[j][1], IM_TABLE_ENTRY_LEN);
k++;
}
//writes the preview
write(fd,preview_buffer,strlen(preview_buffer));
}
//Displays the IM on the bottom line, input is the number of actual physical
//rows and columns on the terminal descibed by fd
void disp_im(int fd, int trows, int tcols) {
//generates the position escape sequence for the bottom left corner
//4 spaces for the im indicator +1 for automargin
int im_col = tcols - IM_TABLE_ENTRY_LEN - 4 - 1;
if (IM_PREVIEW) {
im_col = im_col - IM_PREVIEW_WIDTH;
}
char pos_str[32] = "";
int l = snprintf(pos_str, 32, "\033[%d;%df", trows, im_col);
write(fd,"\0337",2); //saves previous cursor position
write(fd, pos_str,l);
write(fd,"\033[7m",4); //invert video
//overwrite what was there previously, this works out to leaving 1 space
//at the end for automargin b/c you need (tcols-im_col)+1 spaces, but
//want -1 space so it doesn't write to the last character position
write(fd," ",
tcols-im_col);
write(fd, pos_str,l);
//im mode indicator
if (im_on) {
write(fd,"漢[",4);
} else {
write(fd,"英[",4);
}
//actual buffer
write(fd,im_buffer,im_buffer_pos);
write(fd,"]",1);
//if preview is set do that
if (IM_PREVIEW) {
im_preview(fd, trows, tcols);
}
//restore cursor pos and attrbutes
write(fd,"\033[0m",4);
write(fd,"\0338",2);
}
|