Input method in FreeBSD virtual terminal (Week9 & 10)

Date: 08/02 ~ 08/15


During these two weeks, I have almost done the part of the display of the status bar.

The general vt display process begins with the one of vt hardware backends such as vga reading the instance of vt_buf content, then rendering it pixel by pixel onto the screen. However, we don’t want to mess up the terminal content buffer when showing the status bar. To separate the status bar from the data buffer vb_buffer in struct vt_buf, I defined an additional member called vb_ime_buffer in vt_buf for storing the data.

Furthermore, the macro VTBUF_GET_FIELD, which serves as a helper to access the data buffer with the given row and column, also needs to be changed. I extended the macro into a inline function and added a if-else statement to access vb_ime_buffer only when the IME mode is enabled and the hardware is accessing at the row 0 (line 0); otherwise, read the origin buffer. That will show the status bar on the top of screen when the IME mode is enabled and hide it when disabled. The following code snippet shows the diff.

   1 - #define       VTBUF_GET_FIELD(vb, r, c) \
   3 + #ifdef VT_IME
   4 + inline term_char_t
   5 + VTBUF_GET_FIELD(const struct vt_buf *vb, int r, int c)
   6 + {
   7 +       if (vt_ime_buf_state && r == 0)
   8 +               return vb->vb_ime_buffer[c];
   9 +       else
  10 +               return ((vb)->vb_rows[((vb)->vb_roffset + (r)) % VTBUF_MAX_HEIGHT(vb)][(c)]);
  11 + }
  12 + #else
  13 + #define VTBUF_GET_FIELD(vb, r, c) \
  14 +       ((vb)->vb_rows[((vb)->vb_roffset + (r)) % VTBUF_MAX_HEIGHT(vb)][(c)])
  15 + #endif

Next, we need to consider how to store the status bar data in the buffer. As the string sent from the IME server is a utf-8-encoded character sequence, we cannot directly place those utf-8 characters into the buffer. Fortunately, this issue has been solved in Week8 as we can take use of the functions teken_input_byte() and teken_input() to convert them into the term_char_t string.

Also we need to deal with the issue caused by the width of a single CJK character, which takes twice the width of a single Latin character does. To address this, we first check the width of the character; if is 2, we know it is a CJK character, and we must render the character twice: one for the left half, and another for the right half with TFORMAT(TF_CJK_RIGHT); otherwise, just output it. The following code snippet shows the process of printing a character.

   1 while (len-- > 0) {
   2         ret = vt_ime_convert_utf8_byte(&utf8_left, &utf8_partial, *c++);
   3         if (ret <= 0)
   4                 continue;
   6         if (teken_wcwidth(utf8_partial) == 2 &&
   7             blen < vb->vb_scr_size.tp_col - 2) {
   8                 vb->vb_ime_buffer[blen++] = utf8_partial | (ch);
   9                 vb->vb_ime_buffer[blen++] = utf8_partial | (ch) | TFORMAT(TF_CJK_RIGHT);
  10         } else if (blen < vb->vb_scr_size.tp_col - 1) {
  11                         vb->vb_ime_buffer[blen++] = utf8_partial | (ch);
  12         } else {
  13                 break;
  14         }
  15 }


SummerOfCode2021Projects/InputMethodInFreeBSDVirtualTerminal/Week9 (last edited 2021-08-30T17:05:03+0000 by FanChung)