From 81c965f8e29c7b9fb68e9914d4223ab5fe293d1f Mon Sep 17 00:00:00 2001 From: ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> Date: Wed, 14 Jan 2026 16:16:25 +0100 Subject: Partial fix for the Windows platform of the emoji issue (#1360) This fixes input of emojis to Fl_Input and Fl_Text_editor widgets under Windows with the emoji palette. Most emojis have a Unicode point > 0xFFFF and therefore are encoded as a surrogate pair by Windows which uses UTF-16. Thus, Windows sends 2 consecutive WM_CHAR messages to the window and gives one member of the pair each time. After the second WM_CHAR message arrived FLTK is able to enter the emoji in its text. Windows may also send "variation selectors" and zero-width Unicode points when dealing with emojis. FLTK just skips them. Windows also translates some Unicode emojis into 1 emoji + 1 other Unicode point: for example "woman pilot" produces "pilot emoji" + "woman" unicode point. FLTK now handles this gracefuly. This fix also prefixes the windows class names with "FLTK-" under Windows to prevent collisions with Windows-reserved class names. That fix is necessary for the emoji palette to be usable in some scenarios. That fix is still under debate and may evolve in latter commits. --- src/Fl_win32.cxx | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx index da1db6455..c3770024d 100644 --- a/src/Fl_win32.cxx +++ b/src/Fl_win32.cxx @@ -1561,7 +1561,25 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar static char buffer[1024]; if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) { wchar_t u = (wchar_t)wParam; - Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); + // Windows emoji palette triggered with Windows + dot sends 2 or more WM_CHAR messages: + // the 2 components of a surrogate pair, or variation selectors, or zero-width stuff, + // or extra Unicode points. + if (u >= 0xD800 && u <= 0xDFFF) { // handle the 2 components of a surrogate pair + static wchar_t surrogate_pair[2]; + if (IS_HIGH_SURROGATE(u)) { + surrogate_pair[0] = u; // memorize the 1st member of the pair + Fl::e_length = 0; + return 0; // and wait for next WM_CHAR message that will give the 2nd member + } else { + surrogate_pair[1] = u; // memorize the 2nd member of the pair + Fl::e_length = fl_utf8fromwc(buffer, 1024, surrogate_pair, 2); // transform to UTF-8 + } + } else if ((u >= 0xFE00 && u <= 0xFE0F) || (u >= 0x200B && u <= 0x200D)) { + Fl::e_length = 0; // skip variation selectors and zero-width Unicode points + return 0; + } else { + Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); // process regular Unicode point + } buffer[Fl::e_length] = 0; } else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) { if (state & FL_NUM_LOCK) { @@ -2167,6 +2185,14 @@ void Fl_WinAPI_Window_Driver::makeWindow() { if (!first_class_name) { first_class_name = class_name; } +// Prefix user-set window class name by "FLTK", unless it's already here, +// to avoid collision with system-defined window class names (example "edit") + if (strncmp(class_name, "FLTK", 4)) { + static char new_class_name[100]; + snprintf(new_class_name, sizeof(new_class_name), "FLTK-%s", class_name); + class_name = new_class_name; + } + //fprintf(stderr,"makeWindow: class_name=%s\n",class_name);fflush(stderr); wchar_t class_namew[100]; // (limited) buffer for Windows class name -- cgit v1.2.3