diff options
author | Haoran S. Diao (刁浩然) <0@hairydiode.xyz> | 2025-09-06 12:59:37 -0700 |
---|---|---|
committer | Haoran S. Diao (刁浩然) <0@hairydiode.xyz> | 2025-09-06 12:59:37 -0700 |
commit | 0353587069784fdf23a6412ab6edbbd9fc81eb0d (patch) | |
tree | 89a11c1e8401f01c9f43ce86119e9807c7cd1ef2 | |
parent | 63b78eed2d0ec3a248ff7537fd7273102cf41e0a (diff) |
Cleaned up input method code, added preview function
-rw-r--r-- | im.h | 158 | ||||
-rw-r--r-- | imtable.h | 1 | ||||
-rw-r--r-- | ptyim.c | 44 |
3 files changed, 135 insertions, 68 deletions
@@ -1,21 +1,52 @@ +//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 -//#define BACKSPACE_KEY '+' //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) -int im_search(char * input, int start, int end) { +//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; @@ -23,7 +54,7 @@ int im_search(char * input, int start, int end) { //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, IM_TABLE_ENTRY_LEN); + int test = strncmp(im_table[middle][0], input, n); if (test == 0) { return middle; } @@ -39,30 +70,32 @@ int im_search(char * input, int start, int end) { return 0; } else { if (test > 0) { - return im_search(input,start,middle); + return im_search(input,start,middle,n); } else { - return im_search(input,middle,end); + return im_search(input,middle,end,n); } } } -//returns output len, since we want to be able to handle null bytes as well +//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) { - im_buffer[0] = 0; - im_buffer_pos = 0; + clear_im_buffer(); } } - //just exit if the im is off + //just passthrough if the im is off if (!im_on) { output[0] = input; output[1] = 0; return 1; } - if ( ('a' <= input && input <= 'z')||('0' <= input && input <= '9') ||(input == ' ') || (input == ',') || (input == '.')) { + 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++; @@ -74,13 +107,14 @@ int update_im_state(char input, char * output) { return 1; } //if there's a match return it - int im_entry = im_search(im_buffer, 0, IM_TABLE_LEN); + int im_entry = im_search(im_buffer, 0, IM_TABLE_LEN, 0); if (im_entry != -1) { //clear the buffer - im_buffer[0] = 0; - im_buffer_pos = 0; + 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 @@ -89,18 +123,15 @@ int update_im_state(char input, char * output) { switch (input) { //escape, cancels case ESCAPE_KEY: - im_buffer[0] = 0; - im_buffer_pos = 0; + clear_im_buffer(); return 0; break; - //enter, enters the buffer + //enter, enters the buffer instead of sending it + //to im case ENTER_KEY: - for (int i = 0; i <im_buffer_pos; i++) { - output[i] = im_buffer[i]; - } - output[im_buffer_pos] = 0; + strncpy(output, im_buffer, IM_BUFFER_LEN); int tmp = im_buffer_pos; - im_buffer_pos = 0; + clear_im_buffer(); return tmp; break; //backspace @@ -113,10 +144,85 @@ int update_im_state(char input, char * output) { break; } } - //default behavior of passthrough - output[0] = input; - output[1] = 0; - return 1; } + //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); +} @@ -1,3 +1,4 @@ +//Generic Input Method Used in Testing, see boshiamy.h for full implementation #define IM_TABLE_LEN 5 #define IM_TABLE_ENTRY_LEN 8 //assumes this is sorted @@ -34,47 +34,7 @@ void winchhook(int a) { ioctl(pty_slave, TIOCSWINSZ, &sz); } -void disp_im() { - //3 spaces for the im indicator +1 for automargin - int im_col = tcols - IM_TABLE_ENTRY_LEN - 4; - char pos_str[32] = ""; - int l = sprintf(pos_str, "\033[%d;%df",trows, im_col); - //printf("\0337"); - //printf("\033[%d;%df",trows,im_col); - //printf("\033[0;0f",trows,im_col); - //printf("\033[7m"); - //if (im_on) { - // printf("漢"); - //} else { - // printf("英"); - //} - //printf("%s",im_buffer); - //printf("\033[0m"); - //printf("\0338"); - write(STDOUT_FILENO,"\0337",2); - //also writes to top left the current im buffer - //write(STDOUT_FILENO,"\033[33;14f",8); - //write(STDOUT_FILENO,"\033[0;4f",6); - //write to the bottom left corner - write(STDOUT_FILENO, pos_str,l); - //invert video - write(STDOUT_FILENO,"\033[7m",4); - //overwrite what was there previously - write(STDOUT_FILENO," ", - IM_TABLE_ENTRY_LEN+4); - write(STDOUT_FILENO, pos_str,l); - //im mode indicator - if (im_on) { - write(STDOUT_FILENO,"漢:",4); - } else { - write(STDOUT_FILENO,"英:",4); - } - //actual buffer - write(STDOUT_FILENO,im_buffer,im_buffer_pos); - //restore cursor pos and attrbutes - write(STDOUT_FILENO,"\033[0m",4); - write(STDOUT_FILENO,"\0338",2); -} + int main (int argc, char * argv[], char * envp[]) { //creates the pty master int pty_master = posix_openpt(O_RDWR); @@ -187,7 +147,7 @@ int main (int argc, char * argv[], char * envp[]) { if (im_chars >0) { write(pty_master,input_buffer,im_chars); } - disp_im(); + disp_im(STDIN_FILENO, trows, tcols); } } } |