bug#81506: [PATCH] Extend w32 window events to expose IME composition string interface
Eli Zaretskii <[email protected]> Sat, 01 Aug 2026 19:01:15 +0300
| Newsgroups | gmane.emacs.bugs |
|---|---|
| Message-ID | <[email protected]> |
> From: dANiuu zHaO <[email protected]> > Date: Fri, 31 Jul 2026 23:32:09 +0800 > Cc: [email protected] > > [PATCH 3] Implement preedit text rendering for the IME window on w32 > > > This is the second patch. > > I fixed the static buffer issue from yesterday by switching to on-demand allocation.> > > For w32term.c, I removed the direct execution of Lisp code and instead communicate by writing to inev's > args, following the preedit handling approach in xterm.c. > > I kept the w32-ime-preedit flag to toggle the default IME window. > > The hook-based approach has been completely removed. Everything now works through event reading. > > This is a version based on the previous patch. This version adds the following features: > > - When composing CJK strings, the IME window no longer jitters along with the cursor, keeping the behavior > consistent with the native Windows input method behavior. > - When composing CJK strings, while Emacs renders the preedit text, the cursor can respond to arrow keys — > specifically <left> and <right> behavior. > > If you have any questions or concerns about the code, please feel free to contact me. > > I have set up a dedicated example repository to document the development of this patch from scratch: > https://github.com/zHaOdANiuu/emacs-w32-draw-preedit.patch > > Later on, I will attempt to implement the font size feature described in > https://debbugs.gnu.org/cgi/bugreport.cgi?bug=68339 > , in order to improve the overall Windows input method experience in Emacs. Thanks. I would prefer to start with what was described in bug#68339. The reason is twofold: (1) it is a less radical change, in that the window shown by the IME is still used, we just adjust its font size; (2) modifying overlays to present the preedit text will cause the following redisplay of the selected Emacs window to be more thorough, thus more expensive and slower. I'm also not sure what this means if and when the relevant text is in a non-selected window (if this is at all possible). This is why I prefer to begin with a more conservative change that fixes the original problem by adjusting the font of the preedit window, and leave these more extensive changes (really, improvements) for later. A few comments to the code: > --- a/src/w32term.c > +++ b/src/w32term.c > @@ -5387,6 +5387,45 @@ w32_read_socket (struct terminal *terminal, > } > break; > > + case WM_IME_COMPOSITION: > + { > + f = w32_window_to_frame (dpyinfo, msg.msg.hwnd); > + Lisp_Object str = Qnil; > + int size = (int) msg.msg.lParam; > + > + if (size > 0) > + { > + int cursor_pos; > + int utf8_len; > + char *utf8_buf; > + wchar_t *wbuf = (wchar_t *) msg.msg.wParam; > + utf8_len = WideCharToMultiByte (CP_UTF8, 0, > + wbuf, size / sizeof(wchar_t), > + NULL, 0, > + NULL, NULL); > + utf8_buf = alloca (utf8_len); > + utf8_len = WideCharToMultiByte(CP_UTF8, 0, > + wbuf, size / sizeof(wchar_t), > + utf8_buf, utf8_len, > + NULL, NULL); > + str = make_string_from_utf8 (utf8_buf, utf8_len); > + > + /* offaet end, read cursor position. */ > + memcpy (&cursor_pos, (char *) wbuf + size, sizeof (cursor_pos)); > + /* see xic_preedit_draw_callback function. */ > + Fput_text_property (make_fixnum (min (SCHARS (str), max (0, cursor_pos))), > + make_fixnum (min (SCHARS (str), max (0, cursor_pos) + 1)), > + Qcursor, Qt, str); > + } > + > + inev.kind = PREEDIT_TEXT_EVENT; > + inev.arg = str; > + inev.modifiers = msg.dwModifiers; > + XSETFRAME (inev.frame_or_window, f); > + inev.timestamp = msg.msg.time; I believe the processing of the string and the Fput_text_property call should be moved to where this input event is processed in make_lispy_event. The input event structure should have the original preedit data passed via the inev.arg member, and all the rest of the processing above should be in make_lispy_event. > + DEFVAR_BOOL ("w32-ime-preedit", > + w32_ime_preedit, > + doc: /* Non-nil means report IME preedit strings to > +`w32-ime-composition-hook'. When nil, the IME preedit is not > +reported and the IME works as normal. */); The first line of the doc string should be a single complete sentence, so that commands like 'apropos', which show only the first line, could present helpful summary of the variable's doc. More importantly, this doc string explains the technical details of the effect of the variable, whereas it should explain the effect in user-level terms.