//Input Method Functions and Variables //#include "imtable.h" #define IM_BUFFER_LEN 32 #define IM_PREVIEW 1 #define IM_PREVIEW_ENTRIES 6 #define IM_PREVIEW_WIDTH (IM_TABLE_ENTRY_WIDTH+2)*IM_PREVIEW_ENTRIES #define IM_ON_INDICATOR "CN" #define IM_ON_INDICATOR_LEN 2 #define IM_OFF_INDICATOR "EN" #define IM_OFF_INDICATOR_LEN 2 #define IM_INDICATOR_WIDTH 2 #include "boshiamy.h" #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 5 //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(); } //do not passthrough the toggle return 0; } //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 //2 spaces for the im indicator, 2 for buffer brackets, +1 for automargin int im_col = tcols - IM_TABLE_ENTRY_LEN - IM_INDICATOR_WIDTH - 2 - 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,IM_ON_INDICATOR,IM_ON_INDICATOR_LEN); } else { write(fd,IM_OFF_INDICATOR,IM_OFF_INDICATOR_LEN); } write(fd,"[",1); //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); }