From 123c82e8307ca386ba7f161dc725e3953dffc5c0 Mon Sep 17 00:00:00 2001 From: Ilya Zakharevich Date: Fri, 31 Jul 2015 11:50:23 +0300 Subject: [PATCH] Improve handling of Unicode keyboard input on MS-Windows * src/w32fns.c (get_wm_chars, deliver_wm_chars): New functions. (FPRINTF_WM_CHARS) [DEBUG_WM_CHARS]: New macro for debugging. (w32_wnd_proc): Call deliver_wm_chars to process non-special keys upon receiving WM_KEYDOWN or WM_SYSKEYDOWN messages. If that is successful, don't call TranslateMessage. (Bug#19994) --- src/w32fns.c | 979 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 718 insertions(+), 261 deletions(-) diff --git a/src/w32fns.c b/src/w32fns.c index c742ca8534f..fecdf7cb72d 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -270,7 +270,7 @@ check_x_display_info (Lisp_Object object) struct terminal *t = decode_live_terminal (object); if (t->type != output_w32) - error ("Terminal %d is not a W32 display", t->id); + error ("Terminal %d is not a W32 display", t->id); return t->display_info.w32; } @@ -304,7 +304,7 @@ x_window_to_frame (struct w32_display_info *dpyinfo, HWND wdesc) continue; if (FRAME_W32_WINDOW (f) == wdesc) - return f; + return f; } return 0; } @@ -366,7 +366,7 @@ w32_fullscreen_rect (HWND hwnd, int fsmode, RECT normal, RECT *rect) if (monitor_from_window_fn && get_monitor_info_fn) { HMONITOR monitor = - monitor_from_window_fn (hwnd, MONITOR_DEFAULT_TO_NEAREST); + monitor_from_window_fn (hwnd, MONITOR_DEFAULT_TO_NEAREST); get_monitor_info_fn (monitor, &mi); } else @@ -949,8 +949,8 @@ x_to_w32_color (const char * colorname) break; val = (UINT)(0x100 * value); /* We used 0x100 instead of 0xFF to give a continuous - range between 0.0 and 1.0 inclusive. The next statement - fixes the 1.0 case. */ + range between 0.0 and 1.0 inclusive. The next statement + fixes the 1.0 case. */ if (val == 0x100) val = 0xFF; colorval |= (val << pos); @@ -1060,7 +1060,7 @@ w32_map_color (struct frame *f, COLORREF color) while (list) { if (W32_COLOR (list->entry) == color) - { + { ++list->refcount; return; } @@ -1092,7 +1092,7 @@ w32_unmap_color (struct frame *f, COLORREF color) while (list) { if (W32_COLOR (list->entry) == color) - { + { if (--list->refcount == 0) { *prev = list->next; @@ -1121,9 +1121,9 @@ gamma_correct (struct frame *f, COLORREF *color) if (f->gamma) { *color = PALETTERGB ( - pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5, - pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5, - pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5); + pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5, + pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5, + pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5); } } @@ -1144,12 +1144,12 @@ w32_defined_color (struct frame *f, const char *color, XColor *color_def, if (!NILP (tem)) { if (f) - { - /* Apply gamma correction. */ - w32_color_ref = XUINT (tem); - gamma_correct (f, &w32_color_ref); - XSETINT (tem, w32_color_ref); - } + { + /* Apply gamma correction. */ + w32_color_ref = XUINT (tem); + gamma_correct (f, &w32_color_ref); + XSETINT (tem, w32_color_ref); + } /* Map this color to the palette if it is enabled. */ if (!NILP (Vw32_enable_palette)) @@ -1258,7 +1258,7 @@ x_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) update_face_from_frame_parameter (f, Qforeground_color, arg); if (FRAME_VISIBLE_P (f)) - redraw_frame (f); + redraw_frame (f); } } @@ -1271,12 +1271,12 @@ x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) if (FRAME_W32_WINDOW (f) != 0) { SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX, - FRAME_BACKGROUND_PIXEL (f)); + FRAME_BACKGROUND_PIXEL (f)); update_face_from_frame_parameter (f, Qbackground_color, arg); if (FRAME_VISIBLE_P (f)) - redraw_frame (f); + redraw_frame (f); } } @@ -1399,9 +1399,9 @@ x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor, &fore_color, &back_color); XRecolorCursor (FRAME_W32_DISPLAY (f), hand_cursor, - &fore_color, &back_color); + &fore_color, &back_color); XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor, - &fore_color, &back_color); + &fore_color, &back_color); } if (FRAME_W32_WINDOW (f) != 0) @@ -1445,7 +1445,7 @@ x_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) if (!NILP (Vx_cursor_fore_pixel)) fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel, - WHITE_PIX_DEFAULT (f)); + WHITE_PIX_DEFAULT (f)); else fore_pixel = FRAME_BACKGROUND_PIXEL (f); @@ -1494,7 +1494,7 @@ x_set_border_pixel (struct frame *f, int pix) if (FRAME_W32_WINDOW (f) != 0 && f->border_width > 0) { if (FRAME_VISIBLE_P (f)) - redraw_frame (f); + redraw_frame (f); } } @@ -1771,7 +1771,7 @@ w32_set_title_bar_text (struct frame *f, Lisp_Object name) block_input (); #ifdef __CYGWIN__ GUI_FN (SetWindowText) (FRAME_W32_WINDOW (f), - GUI_SDATA (GUI_ENCODE_SYSTEM (name))); + GUI_SDATA (GUI_ENCODE_SYSTEM (name))); #else /* The frame's title many times shows the name of the file visited in the selected window's buffer, so it makes sense to @@ -2319,7 +2319,7 @@ w32_get_modifiers (void) (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) | (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) | (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) | - (modifier_set (VK_MENU) ? + (modifier_set (VK_MENU) ? ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0)); } @@ -2541,13 +2541,13 @@ w32_msg_pump (deferred_msg * msg_buf) /* Produced by complete_deferred_msg; just ignore. */ break; case WM_EMACS_CREATEWINDOW: - /* Initialize COM for this window. Even though we don't use it, - some third party shell extensions can cause it to be used in - system dialogs, which causes a crash if it is not initialized. - This is a known bug in Windows, which was fixed long ago, but - the patch for XP is not publicly available until XP SP3, - and older versions will never be patched. */ - CoInitialize (NULL); + /* Initialize COM for this window. Even though we don't use it, + some third party shell extensions can cause it to be used in + system dialogs, which causes a crash if it is not initialized. + This is a known bug in Windows, which was fixed long ago, but + the patch for XP is not publicly available until XP SP3, + and older versions will never be patched. */ + CoInitialize (NULL); w32_createwindow ((struct frame *) msg.wParam, (int *) msg.lParam); if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0)) @@ -2577,9 +2577,9 @@ w32_msg_pump (deferred_msg * msg_buf) if (focus_window != NULL) UnregisterHotKey (focus_window, RAW_HOTKEY_ID (msg.wParam)); /* Mark item as erased. NB: this code must be - thread-safe. The next line is okay because the cons - cell is never made into garbage and is not relocated by - GC. */ + thread-safe. The next line is okay because the cons + cell is never made into garbage and is not relocated by + GC. */ XSETCAR (make_lisp_ptr ((void *)msg.lParam, Lisp_Cons), Qnil); if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0)) emacs_abort (); @@ -2612,10 +2612,10 @@ w32_msg_pump (deferred_msg * msg_buf) } break; #ifdef MSG_DEBUG - /* Broadcast messages make it here, so you need to be looking - for something in particular for this to be useful. */ + /* Broadcast messages make it here, so you need to be looking + for something in particular for this to be useful. */ default: - DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message)); + DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message)); #endif } } @@ -2809,19 +2809,19 @@ post_character_message (HWND hwnd, UINT msg, signal_quit (); /* As a safety precaution, forcibly complete any deferred - messages. This is a kludge, but I don't see any particularly - clean way to handle the situation where a deferred message is - "dropped" in the lisp thread, and will thus never be - completed, eg. by the user trying to activate the menubar - when the lisp thread is busy, and then typing C-g when the - menubar doesn't open promptly (with the result that the - menubar never responds at all because the deferred - WM_INITMENU message is never completed). Another problem - situation is when the lisp thread calls SendMessage (to send - a window manager command) when a message has been deferred; - the lisp thread gets blocked indefinitely waiting for the - deferred message to be completed, which itself is waiting for - the lisp thread to respond. + messages. This is a kludge, but I don't see any particularly + clean way to handle the situation where a deferred message is + "dropped" in the lisp thread, and will thus never be + completed, eg. by the user trying to activate the menubar + when the lisp thread is busy, and then typing C-g when the + menubar doesn't open promptly (with the result that the + menubar never responds at all because the deferred + WM_INITMENU message is never completed). Another problem + situation is when the lisp thread calls SendMessage (to send + a window manager command) when a message has been deferred; + the lisp thread gets blocked indefinitely waiting for the + deferred message to be completed, which itself is waiting for + the lisp thread to respond. Note that we don't want to block the input thread waiting for a response from the lisp thread (although that would at least @@ -2836,6 +2836,407 @@ post_character_message (HWND hwnd, UINT msg, my_post_msg (&wmsg, hwnd, msg, wParam, lParam); } +static int +get_wm_chars (HWND aWnd, int *buf, int buflen, int ignore_ctrl, int ctrl, + int *ctrl_cnt, int *is_dead, int vk, int exp) +{ + MSG msg; + /* If doubled is at the end, ignore it. */ + int i = buflen, doubled = 0, code_unit; + + if (ctrl_cnt) + *ctrl_cnt = 0; + if (is_dead) + *is_dead = -1; + eassert(w32_unicode_gui); + while (buflen + /* Should be called only when w32_unicode_gui: */ + && PeekMessageW(&msg, aWnd, WM_KEYFIRST, WM_KEYLAST, + PM_NOREMOVE | PM_NOYIELD) + && (msg.message == WM_CHAR || msg.message == WM_SYSCHAR + || msg.message == WM_DEADCHAR || msg.message == WM_SYSDEADCHAR + || msg.message == WM_UNICHAR)) + { + /* We extract character payload, but in this call we handle only the + characters which comes BEFORE the next keyup/keydown message. */ + int dead; + + GetMessageW(&msg, aWnd, msg.message, msg.message); + dead = (msg.message == WM_DEADCHAR || msg.message == WM_SYSDEADCHAR); + if (is_dead) + *is_dead = (dead ? msg.wParam : -1); + if (dead) + continue; + code_unit = msg.wParam; + if (doubled) + { + /* Had surrogate. */ + if (msg.message == WM_UNICHAR + || code_unit < 0xDC00 || code_unit > 0xDFFF) + { /* Mismatched first surrogate. + Pass both code units as if they were two characters. */ + *buf++ = doubled; + if (!--buflen) + return i; /* Drop the 2nd char if at the end of the buffer. */ + } + else /* see https://en.wikipedia.org/wiki/UTF-16 */ + code_unit = (doubled << 10) + code_unit - 0x35FDC00; + doubled = 0; + } + else if (code_unit >= 0xD800 && code_unit <= 0xDBFF) + { + /* Handle mismatched 2nd surrogate the same as a normal character. */ + doubled = code_unit; + continue; + } + + /* The only "fake" characters delivered by ToUnicode() or + TranslateMessage() are: + 0x01 .. 0x1a for Ctrl-letter, Enter, Tab, Ctrl-Break, Esc, Backspace + 0x00 and 0x1b .. 0x1f for Control- []\@^_ + 0x7f for Control-BackSpace + 0x20 for Control-Space */ + if (ignore_ctrl + && (code_unit < 0x20 || code_unit == 0x7f + || (code_unit == 0x20 && ctrl))) + { + /* Non-character payload in a WM_CHAR + (Ctrl-something pressed, see above). Ignore, and report. */ + if (ctrl_cnt) + *ctrl_cnt++; + continue; + } + /* Traditionally, Emacs would ignore the character payload of VK_NUMPAD* + keys, and would treat them later via `function-key-map'. In addition + to usual 102-key NUMPAD keys, this map also treats `kp-'-variants of + space, tab, enter, separator, equal. TAB and EQUAL, apparently, + cannot be generated on Win-GUI branch. ENTER is already handled + by the code above. According to `lispy_function_keys', kp_space is + generated by not-extended VK_CLEAR. (kp-tab != VK_OEM_NEC_EQUAL!). + + We do similarly for backward-compatibility, but ignore only the + characters restorable later by `function-key-map'. */ + if (code_unit < 0x7f + && ((vk >= VK_NUMPAD0 && vk <= VK_DIVIDE) + || (exp && ((vk >= VK_PRIOR && vk <= VK_DOWN) || + vk == VK_INSERT || vk == VK_DELETE || vk == VK_CLEAR))) + && strchr("0123456789/*-+.,", code_unit)) + continue; + *buf++ = code_unit; + buflen--; + } + return i - buflen; +} + +#ifdef DBG_WM_CHARS +# define FPRINTF_WM_CHARS(ARG) fprintf ARG +#else +# define FPRINTF_WM_CHARS(ARG) 0 +#endif + +/* This is a heuristic only. This is supposed to track the state of the + finite automaton in the language environment of Windows. + + However, separate windows (if with the same different language + environments!) should have different values. Moreover, switching to a + non-Emacs window with the same language environment, and using (dead)keys + there would change the value stored in the kernel, but not this value. */ +static int after_deadkey = 0; + +int +deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam, + UINT lParam, int legacy_alt_meta) +{ + /* An "old style" keyboard description may assign up to 125 UTF-16 code + points to a keypress. + (However, the "old style" TranslateMessage() would deliver at most 16 of + them.) Be on a safe side, and prepare to treat many more. */ + int ctrl_cnt, buf[1024], count, is_dead, after_dead = (after_deadkey != -1); + + /* Since the keypress processing logic of Windows has a lot of state, it + is important to call TranslateMessage() for every keyup/keydown, AND + do it exactly once. (The actual change of state is done by + ToUnicode[Ex](), which is called by TranslateMessage(). So one can + call ToUnicode[Ex]() instead.) + + The "usual" message pump calls TranslateMessage() for EVERY event. + Emacs calls TranslateMessage() very selectively (is it needed for doing + some tricky stuff with Win95??? With newer Windows, selectiveness is, + most probably, not needed - and harms a lot). + + So, with the usual message pump, the following call to TranslateMessage() + is not needed (and is going to be VERY harmful). With Emacs' message + pump, the call is needed. */ + if (do_translate) + { + MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} }; + + windows_msg.time = GetMessageTime (); + TranslateMessage (&windows_msg); + } + count = get_wm_chars (hwnd, buf, sizeof(buf)/sizeof(*buf), 1, + /* The message may have been synthesized by + who knows what; be conservative. */ + modifier_set (VK_LCONTROL) + || modifier_set (VK_RCONTROL) + || modifier_set (VK_CONTROL), + &ctrl_cnt, &is_dead, wParam, + (lParam & 0x1000000L) != 0); + if (count) + { + W32Msg wmsg; + DWORD console_modifiers = construct_console_modifiers (); + int *b = buf, strip_Alt = 1, strip_ExtraMods = 1, hairy = 0; + char *type_CtrlAlt = NULL; + + /* XXXX In fact, there may be another case when we need to do the same: + What happens if the string defined in the LIGATURES has length + 0? Probably, we will get count==0, but the state of the finite + automaton would reset to 0??? */ + after_deadkey = -1; + + /* wParam is checked when converting CapsLock to Shift; this is a clone + of w32_get_key_modifiers (). */ + wmsg.dwModifiers = w32_kbd_mods_to_emacs (console_modifiers, wParam); + + /* What follows is just heuristics; the correct treatement requires + non-destructive ToUnicode(): + http://search.cpan.org/~ilyaz/UI-KeyboardLayout/lib/UI/KeyboardLayout.pm#Can_an_application_on_Windows_accept_keyboard_events?_Part_IV:_application-specific_modifiers + + What one needs to find is: + * which of the present modifiers AFFECT the resulting char(s) + (so should be stripped, since their EFFECT is "already + taken into account" in the string in buf), and + * which modifiers are not affecting buf, so should be reported to + the application for further treatment. + + Example: assume that we know: + (A) lCtrl+rCtrl+rAlt modifiers with VK_A key produce a Latin "f" + ("may be logical" in JCUKEN-flavored Russian keyboard flavors); + (B) removing any of lCtrl, rCtrl, rAlt changes the produced char; + (C) Win-modifier is not affecting the produced character + (this is the common case: happens with all "standard" layouts). + + Suppose the user presses Win+lCtrl+rCtrl+rAlt modifiers with VK_A. + What is the intent of the user? We need to guess the intent to decide + which event to deliver to the application. + + This looks like a reasonable logic: since Win- modifier doesn't affect + the output string, the user was pressing Win for SOME OTHER purpose. + So the user wanted to generate Win-SOMETHING event. Now, what is + something? If one takes the mantra that "character payload is more + important than the combination of keypresses which resulted in this + payload", then one should ignore lCtrl+rCtrl+rAlt, ignore VK_A, and + assume that the user wanted to generate Win-f. + + Unfortunately, without non-destructive ToUnicode(), checking (B),(C) + is out of question. So we use heuristics (hopefully, covering + 99.9999% of cases). */ + + /* Another thing to watch for is a possibility to use AltGr-* and + Ctrl-Alt-* with different semantic. + + Background: the layout defining the KLLF_ALTGR bit are treated + specially by the kernel: when VK_RMENU (=rightAlt, =AltGr) is pressed + (released), a press (release) of VK_LCONTROL is emulated (unless Ctrl + is already down). As a result, any press/release of AltGr is seen + by applications as a press/release of lCtrl AND rAlt. This is + applicable, in particular, to ToUnicode[Ex](). (Keyrepeat is covered + the same way!) + + NOTE: it IS possible to see bare rAlt even with KLLF_ALTGR; but this + requires a good finger coordination: doing (physically) + Down-lCtrl Down-rAlt Up-lCtrl Down-a + (doing quick enough, so that key repeat of rAlt [which would + generate new "fake" Down-lCtrl events] does not happens before 'a' + is down) results in no "fake" events, so the application will see + only rAlt down when 'a' is pressed. (However, fake Up-lCtrl WILL + be generated when rAlt goes UP.) + + In fact, note also that KLLF_ALTGR does not prohibit construction of + rCtrl-rAlt (just press them in this order!). + + Moreover: "traditional" layouts do not define distinct modifier-masks + for VK_LMENU and VK_RMENU (same for VK_L/RCONTROL). Instead, they + rely on the KLLF_ALTGR bit to make the behaviour of VK_LMENU and + VK_RMENU distinct. As a corollary, for such layouts, the produced + character is the same for AltGr-* (=rAlt-*) and Ctrl-Alt-* (in any + combination of handedness). For description of masks, see + + http://search.cpan.org/~ilyaz/UI-KeyboardLayout/lib/UI/KeyboardLayout.pm#Keyboard_input_on_Windows,_Part_I:_what_is_the_kernel_doing? + + By default, Emacs was using these coincidences via the following + heuristics: it was treating: + (*) keypresses with lCtrl-rAlt modifiers as if they are carrying + ONLY the character payload (no matter what the actual keyboard + was defining: if lCtrl-lAlt-b was delivering U+05df=beta, then + Emacs saw [beta]; if lCtrl-lAlt-b was undefined in the layout, + the keypress was completely ignored), and + (*) keypresses with the other combinations of handedness of Ctrl-Alt + modifiers (e.g., lCtrl-lAlt) as if they NEVER carry a character + payload (so they were reported "raw": if lCtrl-lAlt-b was + delivering beta, then Emacs saw event [C-A-b], and not [beta]). + This worked good for "traditional" layouts: users could type both + AltGr-x and Ctrl-Alt-x, and one was a character, another a bindable + event. + + However, for layouts which deliver different characters for AltGr-x + and lCtrl-lAlt-x, this scheme makes the latter character unaccessible + in Emacs. While it is easy to access functionality of [C-M-x] in + Emacs by other means (for example, by the `controlify' prefix, or + using lCtrl-rCtrl-x, or rCtrl-rAlt-x [in this order]), missing + characters cannot be reconstructed without a tedious manual work. */ + + /* These two cases are often going to be distinguishable, since at most + one of these character is defined with KBDCTRL | KBDMENU modifier + bitmap. (This heuristic breaks if both lCtrl-lAlt- AND lCtrl-rAlt- + are translated to modifier bitmaps distinct from KBDCTRL | KBDMENU, + or in the cases when lCtrl-lAlt-* and lCtrl-rAlt-* are generally + different, but lCtrl-lAlt-x and lCtrl-rAlt-x happen to deliver the + same character.) + + So we have 2 chunks of info: + (A) is it lCtrl-rAlt-, or lCtrl-lAlt, or some other combination? + (B) is the delivered character defined with KBDCTRL | KBDMENU bits? + Basing on (A) and (B), we should decide whether to ignore the + delivered character. (Before, Emacs was completely ignoring (B), and + was treating the 3-state of (A) as a bit.) This means that we have 6 + bits of customization. + + Additionally, a presence of two Ctrl down may be AltGr-rCtrl-. */ + + /* Strip all non-Shift modifiers if: + - more than one UTF-16 code point delivered (can't call VkKeyScanW ()) + - or the character is a result of combining with a prefix key. */ + if (!after_dead && count == 1 && *b < 0x10000) + { + if (console_modifiers & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED) + && console_modifiers & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) + { + type_CtrlAlt = "bB"; /* generic bindable Ctrl-Alt- modifiers */ + if (console_modifiers & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) + == (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) + /* double-Ctrl: + e.g. AltGr-rCtrl on some layouts (in this order!) */ + type_CtrlAlt = "dD"; + else if (console_modifiers + & (LEFT_CTRL_PRESSED | LEFT_ALT_PRESSED) + == (LEFT_CTRL_PRESSED | LEFT_ALT_PRESSED)) + type_CtrlAlt = "lL"; /* Ctrl-Alt- modifiers on the left */ + else if (!NILP (Vw32_recognize_altgr) + && (console_modifiers + & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)) + == (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)) + type_CtrlAlt = "gG"; /* modifiers as in AltGr */ + } + else if (wmsg.dwModifiers & (alt_modifier | meta_modifier) + || (console_modifiers + & (RIGHT_WIN_PRESSED | RIGHT_WIN_PRESSED + | APPS_PRESSED | SCROLLLOCK_ON))) + { + /* Pure Alt (or combination of Alt, Win, APPS, scrolllock. */ + type_CtrlAlt = "aA"; + } + if (type_CtrlAlt) + { + /* Out of bound bitmap: */ + SHORT r = VkKeyScanW( *b ), bitmap = 0x1FF; + + FPRINTF_WM_CHARS((stderr, "VkKeyScanW %#06x %#04x\n", (int)r, + wParam)); + if ((r & 0xFF) == wParam) + bitmap = r>>8; /* *b is reachable via simple interface */ + if (*type_CtrlAlt == 'a') /* Simple Alt seen */ + { + if ((bitmap & ~1) == 0) /* 1: KBDSHIFT */ + { + /* In "traditional" layouts, Alt without Ctrl does not + change the delivered character. This detects this + situation; it is safe to report this as Alt-something + - as opposed to delivering the reported character + without modifiers. */ + if (legacy_alt_meta + && *b > 0x7f && ('A' <= wParam && wParam <= 'Z')) + /* For backward-compatibility with older Emacsen, let + this be processed by another branch below (which + would convert it to Alt-Latin char via wParam). */ + return 0; + } + else + hairy = 1; + } + /* Check whether the delivered character(s) is accessible via + KBDCTRL | KBDALT ( | KBDSHIFT ) modifier mask (which is 7). */ + else if ((bitmap & ~1) != 6) + { + /* The character is not accessible via plain Ctrl-Alt(-Shift) + (which is, probably, same as AltGr) modifiers. + Either it was after a prefix key, or is combined with + modifier keys which we don't see, or there is an asymmetry + between left-hand and right-hand modifiers, or other hairy + stuff. */ + hairy = 1; + } + /* The best solution is to delegate these tough (but rarely + needed) choices to the user. Temporarily (???), it is + implemented as C macros. + + Essentially, there are 3 things to do: return 0 (handle to the + legacy processing code [ignoring the character payload]; keep + some modifiers (so that they will be processed by the binding + system [on top of the character payload]; strip modifiers [so + that `self-insert' is going to be triggered with the character + payload]). + + The default below should cover 99.9999% of cases: + (a) strip Alt- in the hairy case only; + (stripping = not ignoring) + (l) for lAlt-lCtrl, ignore the char in simple cases only; + (g) for what looks like AltGr, ignore the modifiers; + (d) for what looks like lCtrl-rCtrl-Alt (probably + AltGr-rCtrl), ignore the character in simple cases only; + (b) for other cases of Ctrl-Alt, ignore the character in + simple cases only. + + Essentially, in all hairy cases, and in looks-like-AltGr case, + we keep the character, ignoring the modifiers. In all the + other cases, we ignore the delivered character. */ +#define S_TYPES_TO_IGNORE_CHARACTER_PAYLOAD "aldb" +#define S_TYPES_TO_REPORT_CHARACTER_PAYLOAD_WITH_MODIFIERS "" + if (strchr(S_TYPES_TO_IGNORE_CHARACTER_PAYLOAD, + type_CtrlAlt[hairy])) + return 0; + /* If in neither list, report all the modifiers we see COMBINED + WITH the reported character. */ + if (strchr(S_TYPES_TO_REPORT_CHARACTER_PAYLOAD_WITH_MODIFIERS, + type_CtrlAlt[hairy])) + strip_ExtraMods = 0; + } + } + if (strip_ExtraMods) + wmsg.dwModifiers = wmsg.dwModifiers & shift_modifier; + + signal_user_input (); + while (count--) + { + FPRINTF_WM_CHARS((stderr, "unichar %#06x\n", *b)); + my_post_msg (&wmsg, hwnd, WM_UNICHAR, *b++, lParam); + } + if (!ctrl_cnt) /* Process ALSO as ctrl */ + return 1; + else + FPRINTF_WM_CHARS((stderr, "extra ctrl char\n")); + return -1; + } + else if (is_dead >= 0) + { + FPRINTF_WM_CHARS((stderr, "dead %#06x\n", is_dead)); + after_deadkey = is_dead; + return 1; + } + return 0; +} + /* Main window procedure */ static LRESULT CALLBACK @@ -2869,15 +3270,15 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) f = x_window_to_frame (dpyinfo, hwnd); if (f) { - HDC hdc = get_frame_dc (f); + HDC hdc = get_frame_dc (f); GetUpdateRect (hwnd, &wmsg.rect, FALSE); w32_clear_rect (f, hdc, &wmsg.rect); - release_frame_dc (f, hdc); + release_frame_dc (f, hdc); #if defined (W32_DEBUG_DISPLAY) - DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n", + DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n", f, - wmsg.rect.left, wmsg.rect.top, + wmsg.rect.left, wmsg.rect.top, wmsg.rect.right, wmsg.rect.bottom)); #endif /* W32_DEBUG_DISPLAY */ } @@ -2885,7 +3286,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_PALETTECHANGED: /* ignore our own changes */ if ((HWND)wParam != hwnd) - { + { f = x_window_to_frame (dpyinfo, hwnd); if (f) /* get_frame_dc will realize our palette and force all @@ -2895,24 +3296,24 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) return 0; case WM_PAINT: { - PAINTSTRUCT paintStruct; - RECT update_rect; + PAINTSTRUCT paintStruct; + RECT update_rect; memset (&update_rect, 0, sizeof (update_rect)); f = x_window_to_frame (dpyinfo, hwnd); if (f == 0) { - DebPrint (("WM_PAINT received for unknown window %p\n", hwnd)); + DebPrint (("WM_PAINT received for unknown window %p\n", hwnd)); return 0; } - /* MSDN Docs say not to call BeginPaint if GetUpdateRect - fails. Apparently this can happen under some - circumstances. */ - if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting) - { - enter_crit (); - BeginPaint (hwnd, &paintStruct); + /* MSDN Docs say not to call BeginPaint if GetUpdateRect + fails. Apparently this can happen under some + circumstances. */ + if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting) + { + enter_crit (); + BeginPaint (hwnd, &paintStruct); /* The rectangles returned by GetUpdateRect and BeginPaint do not always match. Play it safe by assuming both areas @@ -2920,40 +3321,49 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) UnionRect (&(wmsg.rect), &update_rect, &(paintStruct.rcPaint)); #if defined (W32_DEBUG_DISPLAY) - DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n", + DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n", f, wmsg.rect.left, wmsg.rect.top, wmsg.rect.right, wmsg.rect.bottom)); - DebPrint ((" [update region is %d,%d-%d,%d]\n", - update_rect.left, update_rect.top, - update_rect.right, update_rect.bottom)); + DebPrint ((" [update region is %d,%d-%d,%d]\n", + update_rect.left, update_rect.top, + update_rect.right, update_rect.bottom)); #endif - EndPaint (hwnd, &paintStruct); - leave_crit (); + EndPaint (hwnd, &paintStruct); + leave_crit (); /* Change the message type to prevent Windows from combining WM_PAINT messages in the Lisp thread's queue, since Windows assumes that each message queue is dedicated to one frame and does not bother checking that hwnd matches before combining them. */ - my_post_msg (&wmsg, hwnd, WM_EMACS_PAINT, wParam, lParam); + my_post_msg (&wmsg, hwnd, WM_EMACS_PAINT, wParam, lParam); - return 0; - } + return 0; + } /* If GetUpdateRect returns 0 (meaning there is no update - region), assume the whole window needs to be repainted. */ + region), assume the whole window needs to be repainted. */ GetClientRect (hwnd, &wmsg.rect); my_post_msg (&wmsg, hwnd, msg, wParam, lParam); - return 0; + return 0; } case WM_INPUTLANGCHANGE: /* Inform lisp thread of keyboard layout changes. */ my_post_msg (&wmsg, hwnd, msg, wParam, lParam); + /* The state of the finite automaton is separate per every input + language environment (so it does not change when one switches + to a different window with the same environment). Moreover, + the experiments show that the state is not remembered when + one switches back to the pre-previous environment. */ + after_deadkey = -1; + + /* XXXX??? What follows is a COMPLETE misunderstanding of Windows! */ + /* Clear dead keys in the keyboard state; for simplicity only - preserve modifier key states. */ + preserve modifier key states. */ { int i; BYTE keystate[256]; @@ -3011,7 +3421,6 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) /* Synchronize modifiers with current keystroke. */ sync_modifiers (); record_keydown (wParam, lParam); - wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0); windows_translate = 0; @@ -3052,14 +3461,14 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) if (!NILP (Vw32_rwindow_modifier)) return 0; break; - case VK_APPS: + case VK_APPS: if (!NILP (Vw32_apps_modifier)) return 0; break; case VK_MENU: if (NILP (Vw32_pass_alt_to_system)) /* Prevent DefWindowProc from activating the menu bar if an - Alt key is pressed and released by itself. */ + Alt key is pressed and released by itself. */ return 0; windows_translate = 1; break; @@ -3083,9 +3492,9 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) break; disable_lock_key: /* Ensure the appropriate lock key state (and indicator light) - remains in the same state. We do this by faking another - press of the relevant key. Apparently, this really is the - only way to toggle the state of the indicator lights. */ + remains in the same state. We do this by faking another + press of the relevant key. Apparently, this really is the + only way to toggle the state of the indicator lights. */ dpyinfo->faked_key = wParam; keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); @@ -3094,8 +3503,8 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); /* Ensure indicator lights are updated promptly on Windows 9x - (TranslateMessage apparently does this), after forwarding - input event. */ + (TranslateMessage apparently does this), after forwarding + input event. */ post_character_message (hwnd, msg, wParam, lParam, w32_get_key_modifiers (wParam, lParam)); windows_translate = 1; @@ -3107,21 +3516,67 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) break; case VK_CANCEL: /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL, - which is confusing for purposes of key binding; convert + which is confusing for purposes of key binding; convert VK_CANCEL events into VK_PAUSE events. */ wParam = VK_PAUSE; break; case VK_PAUSE: /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing - for purposes of key binding; convert these back into - VK_NUMLOCK events, at least when we want to see NumLock key - presses. (Note that there is never any possibility that - VK_PAUSE with Ctrl really is C-Pause as per above.) */ + for purposes of key binding; convert these back into + VK_NUMLOCK events, at least when we want to see NumLock key + presses. (Note that there is never any possibility that + VK_PAUSE with Ctrl really is C-Pause as per above.) */ if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL)) wParam = VK_NUMLOCK; break; default: - /* If not defined as a function key, change it to a WM_CHAR message. */ + if (w32_unicode_gui) + { + /* If this event generates characters or deadkeys, do + not interpret it as a "raw combination of modifiers + and keysym". Hide deadkeys, and use the generated + character(s) instead of the keysym. (Backward + compatibility: exceptions for numpad keys generating + 0-9 . , / * - +, and for extra-Alt combined with a + non-Latin char.) + + Try to not report modifiers which have effect on + which character or deadkey is generated. + + Example (contrived): if rightAlt-? generates f (on a + Cyrillic keyboard layout), and Ctrl, leftAlt do not + affect the generated character, one wants to report + Ctrl-leftAlt-f if the user presses + Ctrl-leftAlt-rightAlt-?. */ + int res; +#if 0 + /* Some of WM_CHAR may be fed to us directly, some are + results of TranslateMessage(). Using 0 as the first + argument (in a separate call) might help us + distinguish these two cases. + + However, the keypress feeders would most probably + expect the "standard" message pump, when + TranslateMessage() is called on EVERY KeyDown/Keyup + event. So they may feed us Down-Ctrl Down-FAKE + Char-o and expect us to recognize it as Ctrl-o. + Using 0 as the first argument would interfere with + this. */ + deliver_wm_chars (0, hwnd, msg, wParam, lParam, 1); +#endif + /* Processing the generated WM_CHAR messages *WHILE* we + handle KEYDOWN/UP event is the best choice, since + withoug any fuss, we know all 3 of: scancode, virtual + keycode, and expansion. (Additionally, one knows + boundaries of expansion of different keypresses.) */ + res = deliver_wm_chars (1, hwnd, msg, wParam, lParam, 1); + windows_translate = -( res != 0 ); + if (res > 0) /* Bound to character(s) or a deadkey */ + break; + /* deliver_wm_chars may make some branches after this vestigal. */ + } + wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0); + /* If not defined as a function key, change it to a WM_CHAR message. */ if (wParam > 255 || !lispy_function_keys[wParam]) { DWORD modifiers = construct_console_modifiers (); @@ -3173,7 +3628,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) /* Forward asciified character sequence. */ post_character_message (hwnd, WM_CHAR, - (unsigned char) key.uChar.AsciiChar, lParam, + (unsigned char) key.uChar.AsciiChar, lParam, w32_get_key_modifiers (wParam, lParam)); w32_kbd_patch_key (&key, w32_keyboard_codepage); } @@ -3188,6 +3643,8 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } } + if (windows_translate == -1) + break; translate: if (windows_translate) { @@ -3202,73 +3659,73 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_SYSCHAR: case WM_CHAR: if (wParam > 255 ) - { - W32Msg wmsg; + { + W32Msg wmsg; - wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam); - signal_user_input (); - my_post_msg (&wmsg, hwnd, WM_UNICHAR, wParam, lParam); + wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam); + signal_user_input (); + my_post_msg (&wmsg, hwnd, WM_UNICHAR, wParam, lParam); - } + } else - post_character_message (hwnd, msg, wParam, lParam, - w32_get_key_modifiers (wParam, lParam)); + post_character_message (hwnd, msg, wParam, lParam, + w32_get_key_modifiers (wParam, lParam)); break; case WM_UNICHAR: /* WM_UNICHAR looks promising from the docs, but the exact - circumstances in which TranslateMessage sends it is one of those - Microsoft secret API things that EU and US courts are supposed - to have put a stop to already. Spy++ shows it being sent to Notepad - and other MS apps, but never to Emacs. + circumstances in which TranslateMessage sends it is one of those + Microsoft secret API things that EU and US courts are supposed + to have put a stop to already. Spy++ shows it being sent to Notepad + and other MS apps, but never to Emacs. - Some third party IMEs send it in accordance with the official - documentation though, so handle it here. + Some third party IMEs send it in accordance with the official + documentation though, so handle it here. - UNICODE_NOCHAR is used to test for support for this message. - TRUE indicates that the message is supported. */ + UNICODE_NOCHAR is used to test for support for this message. + TRUE indicates that the message is supported. */ if (wParam == UNICODE_NOCHAR) - return TRUE; + return TRUE; { - W32Msg wmsg; - wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam); - signal_user_input (); - my_post_msg (&wmsg, hwnd, msg, wParam, lParam); + W32Msg wmsg; + wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam); + signal_user_input (); + my_post_msg (&wmsg, hwnd, msg, wParam, lParam); } break; case WM_IME_CHAR: /* If we can't get the IME result as Unicode, use default processing, - which will at least allow characters decodable in the system locale - get through. */ + which will at least allow characters decodable in the system locale + get through. */ if (!get_composition_string_fn) - goto dflt; + goto dflt; else if (!ignore_ime_char) - { - wchar_t * buffer; - int size, i; - W32Msg wmsg; - HIMC context = get_ime_context_fn (hwnd); - wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam); - /* Get buffer size. */ - size = get_composition_string_fn (context, GCS_RESULTSTR, NULL, 0); - buffer = alloca (size); - size = get_composition_string_fn (context, GCS_RESULTSTR, - buffer, size); + { + wchar_t * buffer; + int size, i; + W32Msg wmsg; + HIMC context = get_ime_context_fn (hwnd); + wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam); + /* Get buffer size. */ + size = get_composition_string_fn (context, GCS_RESULTSTR, NULL, 0); + buffer = alloca (size); + size = get_composition_string_fn (context, GCS_RESULTSTR, + buffer, size); release_ime_context_fn (hwnd, context); - signal_user_input (); - for (i = 0; i < size / sizeof (wchar_t); i++) - { - my_post_msg (&wmsg, hwnd, WM_UNICHAR, (WPARAM) buffer[i], - lParam); - } - /* Ignore the messages for the rest of the + signal_user_input (); + for (i = 0; i < size / sizeof (wchar_t); i++) + { + my_post_msg (&wmsg, hwnd, WM_UNICHAR, (WPARAM) buffer[i], + lParam); + } + /* Ignore the messages for the rest of the characters in the string that was output above. */ - ignore_ime_char = (size / sizeof (wchar_t)) - 1; - } + ignore_ime_char = (size / sizeof (wchar_t)) - 1; + } else ignore_ime_char--; @@ -3490,7 +3947,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) signal_user_input (); /* Need to return true for XBUTTON messages, false for others, - to indicate that we processed the message. */ + to indicate that we processed the message. */ return (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP); case WM_MOUSEMOVE: @@ -3553,11 +4010,11 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_VSCROLL: if (w32_mouse_move_interval <= 0 || (msg == WM_MOUSEMOVE && button_state == 0)) - { + { wmsg.dwModifiers = w32_get_modifiers (); my_post_msg (&wmsg, hwnd, msg, wParam, lParam); return 0; - } + } /* Hang onto mouse move and scroll messages for a bit, to avoid sending such events to Emacs faster than it can process them. @@ -3588,15 +4045,15 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_APPCOMMAND: if (w32_pass_multimedia_buttons_to_system) - goto dflt; + goto dflt; /* Otherwise, pass to lisp, the same way we do with mousehwheel. */ case WM_MOUSEHWHEEL: wmsg.dwModifiers = w32_get_modifiers (); my_post_msg (&wmsg, hwnd, msg, wParam, lParam); signal_user_input (); /* Non-zero must be returned when WM_MOUSEHWHEEL messages are - handled, to prevent the system trying to handle it by faking - scroll bar events. */ + handled, to prevent the system trying to handle it by faking + scroll bar events. */ return 1; case WM_TIMER: @@ -3627,15 +4084,15 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) KillTimer (hwnd, menu_free_timer); menu_free_timer = 0; f = x_window_to_frame (dpyinfo, hwnd); - /* If a popup menu is active, don't wipe its strings. */ + /* If a popup menu is active, don't wipe its strings. */ if (menubar_in_use - && current_popup_menu == NULL) + && current_popup_menu == NULL) { /* Free memory used by owner-drawn and help-echo strings. */ w32_free_menu_strings (hwnd); if (f) f->output_data.w32->menubar_active = 0; - menubar_in_use = 0; + menubar_in_use = 0; } } return 0; @@ -3687,7 +4144,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) if (find_deferred_msg (hwnd, msg) != NULL) emacs_abort (); - menubar_in_use = 1; + menubar_in_use = 1; return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam); } @@ -3698,8 +4155,8 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) /* If a menu is still active, check again after a short delay, since Windows often (always?) sends the WM_EXITMENULOOP before the corresponding WM_COMMAND message. - Don't do this if a popup menu is active, since it is only - menubar menus that require cleaning up in this way. + Don't do this if a popup menu is active, since it is only + menubar menus that require cleaning up in this way. */ if (f && menubar_in_use && current_popup_menu == NULL) menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL); @@ -3744,9 +4201,9 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) menu_font = CreateFontIndirect (&menu_logfont); old_font = SelectObject (hdc, menu_font); - pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE); - if (title) - { + pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE); + if (title) + { if (unicode_append_menu) GetTextExtentPoint32W (hdc, (WCHAR *) title, wcslen ((WCHAR *) title), @@ -3754,12 +4211,12 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) else GetTextExtentPoint32 (hdc, title, strlen (title), &size); - pMis->itemWidth = size.cx; - if (pMis->itemHeight < size.cy) - pMis->itemHeight = size.cy; - } - else - pMis->itemWidth = 0; + pMis->itemWidth = size.cx; + if (pMis->itemHeight < size.cy) + pMis->itemHeight = size.cy; + } + else + pMis->itemWidth = 0; SelectObject (hdc, old_font); DeleteObject (menu_font); @@ -3779,17 +4236,17 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { /* Draw popup menu title. */ char * title = (char *) pDis->itemData; - if (title) - { - HDC hdc = pDis->hDC; - HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT); - LOGFONT menu_logfont; - HFONT old_font; - - GetObject (menu_font, sizeof (menu_logfont), &menu_logfont); - menu_logfont.lfWeight = FW_BOLD; - menu_font = CreateFontIndirect (&menu_logfont); - old_font = SelectObject (hdc, menu_font); + if (title) + { + HDC hdc = pDis->hDC; + HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT); + LOGFONT menu_logfont; + HFONT old_font; + + GetObject (menu_font, sizeof (menu_logfont), &menu_logfont); + menu_logfont.lfWeight = FW_BOLD; + menu_font = CreateFontIndirect (&menu_logfont); + old_font = SelectObject (hdc, menu_font); /* Always draw title as if not selected. */ if (unicode_append_menu) @@ -3808,9 +4265,9 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) ETO_OPAQUE, &pDis->rcItem, title, strlen (title), NULL); - SelectObject (hdc, old_font); - DeleteObject (menu_font); - } + SelectObject (hdc, old_font); + DeleteObject (menu_font); + } return TRUE; } } @@ -3891,16 +4348,16 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) /* Don't restrict the sizing of any kind of frames. If the window manager doesn't, there's no reason to do it ourselves. */ #if 0 - if (frame_resize_pixelwise || hwnd == tip_window) + if (frame_resize_pixelwise || hwnd == tip_window) #endif return 0; #if 0 /* Don't restrict the sizing of fullscreened frames, allowing them to be - flush with the sides of the screen. */ + flush with the sides of the screen. */ f = x_window_to_frame (dpyinfo, hwnd); if (f && FRAME_PREV_FSMODE (f) != FULLSCREEN_NONE) - return 0; + return 0; { WINDOWPLACEMENT wp; @@ -4049,30 +4506,30 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_EMACS_BRINGTOTOP: case WM_EMACS_SETFOREGROUND: { - HWND foreground_window; - DWORD foreground_thread, retval; + HWND foreground_window; + DWORD foreground_thread, retval; - /* On NT 5.0, and apparently Windows 98, it is necessary to - attach to the thread that currently has focus in order to - pull the focus away from it. */ - foreground_window = GetForegroundWindow (); + /* On NT 5.0, and apparently Windows 98, it is necessary to + attach to the thread that currently has focus in order to + pull the focus away from it. */ + foreground_window = GetForegroundWindow (); foreground_thread = GetWindowThreadProcessId (foreground_window, NULL); - if (!foreground_window - || foreground_thread == GetCurrentThreadId () - || !AttachThreadInput (GetCurrentThreadId (), - foreground_thread, TRUE)) - foreground_thread = 0; - - retval = SetForegroundWindow ((HWND) wParam); - if (msg == WM_EMACS_BRINGTOTOP) - retval = BringWindowToTop ((HWND) wParam); - - /* Detach from the previous foreground thread. */ - if (foreground_thread) - AttachThreadInput (GetCurrentThreadId (), - foreground_thread, FALSE); - - return retval; + if (!foreground_window + || foreground_thread == GetCurrentThreadId () + || !AttachThreadInput (GetCurrentThreadId (), + foreground_thread, TRUE)) + foreground_thread = 0; + + retval = SetForegroundWindow ((HWND) wParam); + if (msg == WM_EMACS_BRINGTOTOP) + retval = BringWindowToTop ((HWND) wParam); + + /* Detach from the previous foreground thread. */ + if (foreground_thread) + AttachThreadInput (GetCurrentThreadId (), + foreground_thread, FALSE); + + return retval; } case WM_EMACS_SETWINDOWPOS: @@ -4145,7 +4602,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) button_state = 0; /* Use menubar_active to indicate that WM_INITMENU is from - TrackPopupMenu below, and should be ignored. */ + TrackPopupMenu below, and should be ignored. */ f = x_window_to_frame (dpyinfo, hwnd); if (f) f->output_data.w32->menubar_active = 1; @@ -4452,20 +4909,20 @@ x_default_font_parameter (struct frame *f, Lisp_Object parms) { int i; static char *names[] - = { "Courier New-10", - "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1", - "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1", - "Fixedsys", - NULL }; + = { "Courier New-10", + "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1", + "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1", + "Fixedsys", + NULL }; for (i = 0; names[i]; i++) - { - font = font_open_by_name (f, build_unibyte_string (names[i])); - if (! NILP (font)) - break; - } + { + font = font_open_by_name (f, build_unibyte_string (names[i])); + if (! NILP (font)) + break; + } if (NILP (font)) - error ("No suitable font was found"); + error ("No suitable font was found"); } else if (!NILP (font_param)) { @@ -4573,7 +5030,7 @@ This function is an internal primitive--use `make-frame' instead. */) fset_icon_name (f, x_get_arg (dpyinfo, parameters, Qicon_name, "iconName", "Title", - RES_TYPE_STRING)); + RES_TYPE_STRING)); if (! STRINGP (f->icon_name)) fset_icon_name (f, Qnil); @@ -4797,7 +5254,7 @@ This function is an internal primitive--use `make-frame' instead. */) frame on this terminal. */ if (FRAME_HAS_MINIBUF_P (f) && (!FRAMEP (KVAR (kb, Vdefault_minibuffer_frame)) - || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame))))) + || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame))))) kset_default_minibuffer_frame (kb, frame); /* All remaining specified parameters, which have not been "used" @@ -5522,7 +5979,7 @@ If TERMINAL is omitted or nil, that stands for the selected frame's display. */ /*********************************************************************** - Window properties + Window properties ***********************************************************************/ #if 0 /* TODO : port window properties to W32 */ @@ -5658,9 +6115,9 @@ no value of TYPE (always string in the MS Windows case). */) ***********************************************************************/ static Lisp_Object x_create_tip_frame (struct w32_display_info *, - Lisp_Object, Lisp_Object); + Lisp_Object, Lisp_Object); static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, - Lisp_Object, int, int, int *, int *); + Lisp_Object, int, int, int *, int *); /* The frame of a currently visible tooltip. */ @@ -5868,7 +6325,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, "cursorType", "CursorType", RES_TYPE_SYMBOL); /* Process alpha here (Bug#17344). */ x_default_parameter (f, parms, Qalpha, Qnil, - "alpha", "Alpha", RES_TYPE_NUMBER); + "alpha", "Alpha", RES_TYPE_NUMBER); /* Dimensions, especially FRAME_LINES (f), must be done via change_frame_size. Change will not be effected unless different @@ -6766,25 +7223,25 @@ value of DIR as in previous invocations; this is standard Windows behavior. */) if (file_opened) { - /* Get an Emacs string from the value Windows gave us. */ + /* Get an Emacs string from the value Windows gave us. */ #ifdef NTGUI_UNICODE - filename = from_unicode_buffer (filename_buf_w); + filename = from_unicode_buffer (filename_buf_w); #else /* !NTGUI_UNICODE */ if (use_unicode) filename_from_utf16 (filename_buf_w, fname_ret); else filename_from_ansi (filename_buf_a, fname_ret); dostounix_filename (fname_ret); - filename = DECODE_FILE (build_unibyte_string (fname_ret)); + filename = DECODE_FILE (build_unibyte_string (fname_ret)); #endif /* NTGUI_UNICODE */ #ifdef CYGWIN - filename = Fcygwin_convert_file_name_from_windows (filename, Qt); + filename = Fcygwin_convert_file_name_from_windows (filename, Qt); #endif /* CYGWIN */ - /* Strip the dummy filename off the end of the string if we - added it to select a directory. */ - if ((use_unicode && file_details_w->nFilterIndex == 2) + /* Strip the dummy filename off the end of the string if we + added it to select a directory. */ + if ((use_unicode && file_details_w->nFilterIndex == 2) #ifndef NTGUI_UNICODE || (!use_unicode && file_details_a->nFilterIndex == 2) #endif @@ -6797,14 +7254,14 @@ value of DIR as in previous invocations; this is standard Windows behavior. */) /* An error occurred, fallback on reading from the mini-buffer. */ else filename = Fcompleting_read ( - orig_prompt, - intern ("read-file-name-internal"), - orig_dir, - mustmatch, - orig_dir, - Qfile_name_history, - default_filename, - Qnil); + orig_prompt, + intern ("read-file-name-internal"), + orig_dir, + mustmatch, + orig_dir, + Qfile_name_history, + default_filename, + Qnil); UNGCPRO; } @@ -6917,7 +7374,7 @@ DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash, /*********************************************************************** - w32 specialized functions + w32 specialized functions ***********************************************************************/ DEFUN ("w32-send-sys-command", Fw32_send_sys_command, @@ -6952,37 +7409,37 @@ handler application, but typically it is one of the following common operations: \"open\" - open DOCUMENT, which could be a file, a directory, or an - executable program (application). If it is an application, - that application is launched in the current buffer's default - directory. Otherwise, the application associated with - DOCUMENT is launched in the buffer's default directory. + executable program (application). If it is an application, + that application is launched in the current buffer's default + directory. Otherwise, the application associated with + DOCUMENT is launched in the buffer's default directory. \"opennew\" - like \"open\", but instruct the application to open - DOCUMENT in a new window. + DOCUMENT in a new window. \"openas\" - open the \"Open With\" dialog for DOCUMENT. \"print\" - print DOCUMENT, which must be a file. \"printto\" - print DOCUMENT, which must be a file, to a specified printer. - The printer should be provided in PARAMETERS, see below. + The printer should be provided in PARAMETERS, see below. \"explore\" - start the Windows Explorer on DOCUMENT. \"edit\" - launch an editor and open DOCUMENT for editing; which - editor is launched depends on the association for the - specified DOCUMENT. + editor is launched depends on the association for the + specified DOCUMENT. \"find\" - initiate search starting from DOCUMENT, which must specify - a directory. + a directory. \"delete\" - move DOCUMENT, a file or a directory, to Recycle Bin. \"copy\" - copy DOCUMENT, which must be a file or a directory, into - the clipboard. + the clipboard. \"cut\" - move DOCUMENT, a file or a directory, into the clipboard. \"paste\" - paste the file whose name is in the clipboard into DOCUMENT, - which must be a directory. + which must be a directory. \"pastelink\" - - create a shortcut in DOCUMENT (which must be a directory) - the file or directory whose name is in the clipboard. + - create a shortcut in DOCUMENT (which must be a directory) + the file or directory whose name is in the clipboard. \"runas\" - run DOCUMENT, which must be an excutable file, with - elevated privileges (a.k.a. \"as Administrator\"). + elevated privileges (a.k.a. \"as Administrator\"). \"properties\" - - open the property sheet dialog for DOCUMENT. + - open the property sheet dialog for DOCUMENT. nil - invoke the default OPERATION, or \"open\" if default is - not defined or unavailable. + not defined or unavailable. DOCUMENT is typically the name of a document file or a URL, but can also be an executable program to run, or a directory to open in the @@ -7678,7 +8135,7 @@ elements (all size values are in pixels). ? Fcons (make_number (0), make_number (0)) : Fcons (make_number (border_width), make_number (border_height)))), - Fcons (Qtitle_height, + Fcons (Qtitle_height, ((EQ (fullscreen, Qfullboth) || EQ (fullscreen, Qfullscreen)) ? make_number (0) : make_number (title_height))), @@ -8063,14 +8520,14 @@ w32_strerror (int error_no) error_no = GetLastError (); ret = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - error_no, - 0, /* choose most suitable language */ - buf, sizeof (buf), NULL); + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + error_no, + 0, /* choose most suitable language */ + buf, sizeof (buf), NULL); while (ret > 0 && (buf[ret - 1] == '\n' || - buf[ret - 1] == '\r' )) + buf[ret - 1] == '\r' )) --ret; buf[ret] = '\0'; if (!ret) @@ -8316,7 +8773,7 @@ w32_kbd_patch_key (KEY_EVENT_RECORD *event, int cpId) else { isdead = ToAscii (event->wVirtualKeyCode, event->wVirtualScanCode, - keystate, (LPWORD) ansi_code, 0); + keystate, (LPWORD) ansi_code, 0); } if (isdead == 0) @@ -8580,8 +9037,8 @@ system to handle them. */); w32_pass_extra_mouse_buttons_to_system = 0; DEFVAR_BOOL ("w32-pass-multimedia-buttons-to-system", - w32_pass_multimedia_buttons_to_system, - doc: /* If non-nil, media buttons are passed to Windows. + w32_pass_multimedia_buttons_to_system, + doc: /* If non-nil, media buttons are passed to Windows. Some modern keyboards contain buttons for controlling media players, web browsers and other applications. Generally these buttons are handled on a system wide basis, but by setting this to nil they are made available @@ -8669,12 +9126,12 @@ Chinese, Japanese, and Korean. */); Vx_pixel_size_width_font_regexp = Qnil; DEFVAR_LISP ("w32-bdf-filename-alist", - Vw32_bdf_filename_alist, - doc: /* List of bdf fonts and their corresponding filenames. */); + Vw32_bdf_filename_alist, + doc: /* List of bdf fonts and their corresponding filenames. */); Vw32_bdf_filename_alist = Qnil; DEFVAR_BOOL ("w32-strict-fontnames", - w32_strict_fontnames, + w32_strict_fontnames, doc: /* Non-nil means only use fonts that are exact matches for those requested. Default is nil, which allows old fontnames that are not XLFD compliant, and allows third-party CJK display to work by specifying false charset @@ -8684,7 +9141,7 @@ fontsets are automatically created. */); w32_strict_fontnames = 0; DEFVAR_BOOL ("w32-strict-painting", - w32_strict_painting, + w32_strict_painting, doc: /* Non-nil means use strict rules for repainting frames. Set this to nil to get the old behavior for repainting; this should only be necessary if the default setting causes problems. */); -- 2.39.2