dmenu

Kris's build of dmenu
git clone git clone https://git.krisyotam.com/krisyotam/dmenu.git
Log | Files | Refs | README | LICENSE

inputmethod.c (5133B)


      1 static size_t nextrunetext(const char *text, size_t position, int inc)
      2 {
      3 	ssize_t n;
      4 
      5 	/* return location of next utf8 rune in the given direction (+1 or -1) */
      6 	for (n = position + inc; n + inc >= 0 && (text[n] & 0xc0) == 0x80; n += inc)
      7 		;
      8 	return n;
      9 }
     10 
     11 /* return bytes from beginning of text to nth utf8 rune to the right */
     12 static size_t runebytes(const char *text, size_t n)
     13 {
     14 	size_t ret;
     15 
     16 	ret = 0;
     17 	while (n-- > 0)
     18 		ret += nextrunetext(text + ret, 0, 1);
     19 	return ret;
     20 }
     21 
     22 /* return number of characters from beginning of text to nth byte to the right
     23  */
     24 static size_t runechars(const char *text, size_t n)
     25 {
     26 	size_t ret, i;
     27 
     28 	ret = i = 0;
     29 	while (i < n) {
     30 		i += nextrunetext(text + i, 0, 1);
     31 		ret++;
     32 	}
     33 	return ret;
     34 }
     35 
     36 /* move caret on pre-edit text */
     37 static void preeditcaret(XIC xic, XPointer clientdata, XPointer calldata)
     38 {
     39 	XIMPreeditCaretCallbackStruct *pcaret;
     40 
     41 	(void)xic;
     42 	pcaret = (XIMPreeditCaretCallbackStruct *)calldata;
     43 	if (!pcaret)
     44 		return;
     45 	switch (pcaret->direction) {
     46 	case XIMForwardChar:
     47 		cursor = nextrune(+1);
     48 		break;
     49 	case XIMBackwardChar:
     50 		cursor = nextrune(-1);
     51 		break;
     52 	case XIMForwardWord:
     53 		movewordedge(+1);
     54 		break;
     55 	case XIMBackwardWord:
     56 		movewordedge(-1);
     57 		break;
     58 	case XIMLineStart:
     59 		cursor = 0;
     60 		break;
     61 	case XIMLineEnd:
     62 		if (preview[cursor] != '\0')
     63 			cursor = strlen(preview);
     64 		break;
     65 	case XIMAbsolutePosition:
     66 		cursor = runebytes(text, pcaret->position);
     67 		break;
     68 	case XIMDontChange:
     69 		/* do nothing */
     70 		break;
     71 	case XIMCaretUp:
     72 	case XIMCaretDown:
     73 	case XIMNextLine:
     74 	case XIMPreviousLine:
     75 		/* not implemented */
     76 		break;
     77 	}
     78 	pcaret->position = runechars(preview, cursor);
     79 }
     80 
     81 /* start input method pre-editing */
     82 static int preeditstart(XIC xic, XPointer clientdata, XPointer calldata)
     83 {
     84 	(void)xic;
     85 	(void)calldata;
     86 	(void)clientdata;
     87 	composing = 1;
     88 	printf("PREEDIT\n");
     89 	return BUFSIZ;
     90 }
     91 
     92 /* end input method pre-editing */
     93 static void preeditdone(XIC xic, XPointer clientdata, XPointer calldata)
     94 {
     95 	(void)xic;
     96 	(void)clientdata;
     97 	(void)calldata;
     98 	printf("DONE\n");
     99 
    100 	composing = 0;
    101 }
    102 
    103 /* draw input method pre-edit text */
    104 static void preeditdraw(XIC xic, XPointer clientdata, XPointer calldata)
    105 {
    106 	XIMPreeditDrawCallbackStruct *pdraw;
    107 	size_t beg, dellen, inslen, endlen;
    108 
    109 	printf("DRAW\n");
    110 
    111 	(void)xic;
    112 	pdraw = (XIMPreeditDrawCallbackStruct *)calldata;
    113 	if (!pdraw)
    114 		return;
    115 
    116 	/* we do not support wide characters */
    117 	if (pdraw->text && pdraw->text->encoding_is_wchar == True) {
    118 		fputs("warning: wchar is not supportecd; use utf8", stderr);
    119 		return;
    120 	}
    121 
    122 	beg = runebytes(text, pdraw->chg_first);
    123 	dellen = runebytes(preview + beg, pdraw->chg_length);
    124 	inslen = pdraw->text ? runebytes(pdraw->text->string.multi_byte, pdraw->text->length) : 0;
    125 	endlen = 0;
    126 	if (beg + dellen < strlen(preview))
    127 		endlen = strlen(preview + beg + dellen);
    128 
    129 	/* we cannot change text past the end of our pre-edit string */
    130 
    131 	if (beg + dellen >= BUFSIZ || beg + inslen >= BUFSIZ)
    132 		return;
    133 
    134 	/* get space for text to be copied, and copy it */
    135 	memmove(preview + beg + inslen, preview + beg + dellen, endlen + 1);
    136 	if (pdraw->text && pdraw->text->length)
    137 		memcpy(preview + beg, pdraw->text->string.multi_byte, inslen);
    138 	(preview + beg + inslen + endlen)[0] = '\0';
    139 
    140 	/* get caret position */
    141 	cursor = runebytes(text, pdraw->caret);
    142 }
    143 
    144 static void init_input_method(XIM xim)
    145 {
    146 	XVaNestedList preedit = NULL;
    147 	XICCallback start, done, draw, caret;
    148 	XIMStyle preeditstyle;
    149 	XIMStyle statusstyle;
    150 	XIMStyles *imstyles;
    151 	int i;
    152 
    153 	/* get styles supported by input method */
    154 	if (XGetIMValues(xim, XNQueryInputStyle, &imstyles, NULL) != NULL)
    155 		fputs("XGetIMValues: could not obtain input method values", stderr);
    156 
    157 	/* check whether input method support on-the-spot pre-editing */
    158 	preeditstyle = XIMPreeditNothing;
    159 	statusstyle = XIMStatusNothing;
    160 	for (i = 0; i < imstyles->count_styles; i++) {
    161 		if (imstyles->supported_styles[i] & XIMPreeditCallbacks) {
    162 			preeditstyle = XIMPreeditCallbacks;
    163 			break;
    164 		}
    165 	}
    166 
    167 	/* create callbacks for the input context */
    168 	start.client_data = NULL;
    169 	done.client_data = NULL;
    170 	draw.client_data = (XPointer)text;
    171 	caret.client_data = (XPointer)text;
    172 	start.callback = (XICProc)preeditstart;
    173 	done.callback = (XICProc)preeditdone;
    174 	draw.callback = (XICProc)preeditdraw;
    175 	caret.callback = (XICProc)preeditcaret;
    176 
    177 	/* create list of values for input context */
    178 	preedit = XVaCreateNestedList(0, XNPreeditStartCallback, &start, XNPreeditDoneCallback,
    179 				      &done, XNPreeditDrawCallback, &draw, XNPreeditCaretCallback,
    180 				      &caret, NULL);
    181 	if (preedit == NULL)
    182 		fputs("XVaCreateNestedList: could not create nested list", stderr);
    183 
    184 	xic = XCreateIC(xim, XNInputStyle, preeditstyle | statusstyle, XNPreeditAttributes, preedit,
    185 			XNClientWindow, win, XNFocusWindow, win, NULL);
    186 	XFree(preedit);
    187 
    188 	long eventmask;
    189 	/* get events the input method is interested in */
    190 	if (XGetICValues(xic, XNFilterEvents, &eventmask, NULL))
    191 		fputs("XGetICValues: could not obtain input context values", stderr);
    192 
    193 	XSelectInput(dpy, win,
    194 		     ExposureMask | KeyPressMask | VisibilityChangeMask | ButtonPressMask |
    195 			     PointerMotionMask | eventmask);
    196 }