Index: src/w32fns.c =================================================================== RCS file: /cvsroot/emacs/emacs/src/w32fns.c,v retrieving revision 1.255 diff -u -r1.255 w32fns.c --- src/w32fns.c 28 Jul 2005 09:46:21 -0000 1.255 +++ src/w32fns.c 28 Jul 2005 23:10:09 -0000 @@ -2146,6 +2146,7 @@ static int modifiers[4]; static int modifiers_recorded; static int modifier_key_support_tested; +static BOOL b_menu_pending = FALSE; static void test_modifier_support (unsigned int wparam) @@ -2218,6 +2219,9 @@ /* Emacs doesn't have keyboard focus. Do nothing. */ return; + //printf("resetting menu_pending 2\n"); fflush(stdout); + b_menu_pending = FALSE; + ctrl = GetAsyncKeyState (VK_CONTROL); alt = GetAsyncKeyState (VK_MENU); @@ -2469,6 +2473,14 @@ } } +HWND hwndMain; // for TranslateAccelerator +HACCEL hAccelDyn = NULL; +int cAccelerators = 0; // number of accelerators in table +LPACCEL lpaccelDyn = NULL; + +void add_LowLevelKeyboardProc(); +void remove_LowLevelKeyboardProc(); + /* Main message dispatch loop. */ static void @@ -2477,11 +2489,15 @@ MSG msg; int result; HWND focus_window; + BOOL bRet; msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL); - while (GetMessage (&msg, NULL, 0, 0)) + while ( (bRet = GetMessage (&msg, NULL, 0, 0)) != 0) { + if (-1 == bRet) { + // error, handle? + } else { if (msg.hwnd == NULL) { switch (msg.message) @@ -2489,6 +2505,15 @@ case WM_NULL: /* Produced by complete_deferred_msg; just ignore. */ break; + case WM_EMACS_KDB_LL: + if (msg.wParam) { + //printf("add_LowLevelKeyboardProc();\n"); fflush(stdout); + add_LowLevelKeyboardProc(); + } else { + //printf("remove_LowLevelKeyboardProc();\n"); fflush(stdout); + remove_LowLevelKeyboardProc(); + } + break; case WM_EMACS_CREATEWINDOW: w32_createwindow ((struct frame *) msg.wParam); if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0)) @@ -2564,8 +2589,11 @@ } else { - DispatchMessage (&msg); + BOOL bHandled = FALSE; + if (hAccelDyn) bHandled = TranslateAccelerator(hwndMain, hAccelDyn, &msg); + if (!bHandled) DispatchMessage (&msg); } + } /* Exit nested loop when our deferred message has completed. */ if (msg_buf->completed) @@ -2669,6 +2697,81 @@ PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0); } + + +LRESULT +LowLevelKeyboardProc(INT nCode, WPARAM wParam, LPARAM lParam) +{ + if (nCode == HC_ACTION) + { + KBDLLHOOKSTRUCT *pkbdllhook = (KBDLLHOOKSTRUCT *)lParam; + BOOL bHandle = FALSE; + + switch (wParam) + { + case WM_KEYUP: + case WM_KEYDOWN: // This was not in the MS example, why?? + case WM_SYSKEYUP: + case WM_SYSKEYDOWN: + switch (pkbdllhook->vkCode) + { + /* Since Vw32_pass_lwindow_to_system is just a struct + and NILP a comparision with == we do not have to sync + to make this comparision in the windows thread. The + value might temporarily be wrong, but no crashes can + occor. (But what about cashing of the value in the + windows thread?) */ + case VK_LWIN: + { + bHandle = NILP(Vw32_pass_lwindow_to_system); + break; + } + case VK_RWIN: + { + bHandle = NILP(Vw32_pass_rwindow_to_system); + break; + } + } + } + if (bHandle) { + // Just to be sure check we are in the right thread + if (GetCurrentThreadId() == dwWindowsThreadId) { + // Do we have keyboard focus? + HWND hwnd = GetFocus(); + if (0 != hwnd) { + PostMessage (hwnd, wParam, pkbdllhook->vkCode, 0); + return TRUE; + } + } + } + } + HHOOK hhook; return CallNextHookEx(hhook, nCode, wParam, lParam); +} + +static HHOOK hLowKBhookW = NULL; +void +add_LowLevelKeyboardProc() +{ + if (NULL != hLowKBhookW) return; + if (GetCurrentThreadId() == dwWindowsThreadId) { + hLowKBhookW = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, (HINSTANCE) GetModuleHandle(NULL), 0); + if (NULL == hLowKBhookW) { + printf("hookW is NULL, %s\n", w32_strerror(GetLastError())); fflush(stdout); + } + } else { + printf("add_LowLevelKeyboardProc called from other thread then windows thread\n"); fflush(stdout); + abort(); + } +} +void +remove_LowLevelKeyboardProc() +{ + if (NULL == hLowKBhookW) return; + UnhookWindowsHookEx(hLowKBhookW); + hLowKBhookW = NULL; +} + + DWORD w32_msg_worker (dw) DWORD dw; @@ -2689,8 +2792,21 @@ /* This is the inital message loop which should only exit when the application quits. */ + + // Below is some test code if someone would like to use it. +/* cAccelerators = 1; // number of accelerators in table */ +/* lpaccelDyn = (LPACCEL) LocalAlloc(LPTR, cAccelerators * sizeof(ACCEL)); */ +/* if (!lpaccelDyn) printf("LocalAlloc error: %s\n", w32_strerror(GetLastError())); fflush(stdout); */ +/* hAccelDyn = CreateAcceleratorTable(lpaccelDyn, cAccelerators); */ +/* if (!hAccelDyn) printf("CreateAcceleratorTable error: %s\n", w32_strerror(GetLastError())); fflush(stdout); */ +/* lpaccelDyn[0].fVirt = FALT; */ +/* lpaccelDyn[0].key = 'f'; */ +/* lpaccelDyn[0].cmd = 9; */ + w32_msg_pump (&dummy_buf); +/* if (lpaccelDyn) LocalFree(lpaccelDyn); */ + return 0; } @@ -2705,6 +2821,10 @@ { W32Msg wmsg; + // Never send alt_modifier if system should have ALT + if (!NILP (Vw32_pass_alt_to_system)) { + modifiers = (modifiers | alt_modifier) ^ alt_modifier; + } wmsg.dwModifiers = modifiers; /* Detect quit_char and set quit-flag directly. Note that we @@ -2765,6 +2885,10 @@ WPARAM wParam; LPARAM lParam; { + BOOL bStickyKeysOn = FALSE; + STICKYKEYS stick; + static BOOL b_was_menu_pending = FALSE; + struct frame *f; struct w32_display_info *dpyinfo = &one_w32_display_info; W32Msg wmsg; @@ -2906,11 +3030,31 @@ case WM_KEYUP: case WM_SYSKEYUP: +/* b_was_menu_pending = b_menu_pending; */ +/* if (b_was_menu_pending) { */ +/* HWND hwndIn = hwnd; */ +/* UINT msgIn = msg; */ +/* WPARAM wParamIn = wParam; */ +/* LPARAM lParamIn = lParam; */ +/* //b_menu_pending = FALSE; */ +/* printf("sending WM_SYSCOMMAND, hwnd=%d, menu=%d\n", hwnd, GetMenu(hwnd)); fflush(stdout); */ +/* SendMessage (hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0); */ +/* PostMessage (hwndIn, msgIn, wParamIn, lParamIn); */ +/* return 0; */ +/* } */ + //printf("WM_KEYUP, wparam=%d, lparam=%d\n", wParam, lParam); fflush(stdout); record_keyup (wParam, lParam); goto dflt; case WM_KEYDOWN: case WM_SYSKEYDOWN: + stick.cbSize = sizeof(STICKYKEYS); + if (!SystemParametersInfo(SPI_GETSTICKYKEYS, stick.cbSize, &stick, 0)) { + printf("error in spi: %s\n", w32_strerror(GetLastError)); fflush(stdout); + } else { + bStickyKeysOn = stick.dwFlags & SKF_STICKYKEYSON; + } + //printf("WM_KEYDOWN, wparam=%d, lparam=%d\n", wParam, lParam); fflush(stdout); /* Ignore keystrokes we fake ourself; see below. */ if (dpyinfo->faked_key == wParam) { @@ -2928,6 +3072,8 @@ } /* Synchronize modifiers with current keystroke. */ + b_was_menu_pending = b_menu_pending; + b_menu_pending = FALSE; sync_modifiers (); record_keydown (wParam, lParam); wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0); @@ -2975,11 +3121,21 @@ 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 + 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. */ - return 0; + //printf(" avoiding DefWindowProc cause not w32-pass-alt-to-system\n"); fflush(stdout); + return 0; + } + /* By not testing for StickyKeysOn we get the advantage that + holding down Alt and then typing a letter can open the + menu. This seems to be the way other apps behave on + w32. */ + //if (bStickyKeysOn) { + //printf("setting menu_pending t\n"); fflush(stdout); + b_menu_pending = TRUE; + //} windows_translate = 1; break; case VK_CAPITAL: @@ -3040,6 +3196,21 @@ wParam = VK_NUMLOCK; break; default: + if (b_was_menu_pending) { + HWND hwndIn = hwnd; + UINT msgIn = msg; + WPARAM wParamIn = wParam; + LPARAM lParamIn = lParam; + b_menu_pending = FALSE; + + if(!(modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))) { + //printf("sending WM_SYSCOMMAND, hwnd=%d, menu=%d\n", hwnd, GetMenu(hwnd)); fflush(stdout); + SendMessage (hwnd, WM_SYSCOMMAND, SC_KEYMENU, wParam); + return 0; + } else { + //printf("... no menu, was AltGr...\n"); fflush(stdout); + } + } /* If not defined as a function key, change it to a WM_CHAR message. */ if (lispy_function_keys[wParam] == 0) { @@ -3372,6 +3543,9 @@ goto dflt; case WM_INITMENU: + //printf("WM_INITMENU in w32fns.c, hwnd=%d, wParam=%d\n", hwnd, wParam); fflush(stdout); + //printf("resetting menu_pending 1\n"); fflush(stdout); + b_menu_pending = FALSE; button_state = 0; ReleaseCapture (); /* We must ensure menu bar is fully constructed and up to date @@ -3409,7 +3583,24 @@ if (find_deferred_msg (hwnd, msg) != NULL) abort (); - return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam); + //return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam); + + my_post_msg (&wmsg, hwnd, msg, wParam, lParam); + { + MSG msg; + //printf(" waiting for EMACS_DONE\n"); fflush(stdout); + //GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE); + /* Use PeekMessage to avoid blocking infinitely. 2 sec max + (this an arbitrary choice). 40 ms is choosen to be as + long as possible but still short enough to be + "invisible". */ + int i; + for (i = 1; i < 50; i++) { + if (PeekMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE, PM_REMOVE)) break; + Sleep(40); + } + } + return 0; } case WM_EXITMENULOOP: @@ -3556,6 +3747,7 @@ goto dflt; case WM_SETFOCUS: + hwndMain = GetFocus(); dpyinfo->faked_key = 0; reset_modifiers (); register_hot_keys (hwnd); @@ -8111,6 +8303,38 @@ return HOTKEY (vk_code, w32_modifiers); } +DEFUN ("w32-set-wh-keyboard-ll", Fw32_set_wh_keyboard_ll, + Sw32_set_wh_keyboard_ll, 1, 1, 0, + do: /* Activate/deactivate low level keyboard hook. +A low level Windows keyboard hook must be used to trap keys that other +applications have registered as hot keys. Emacs support this for left +and write windows keys. If ON is non-nil Emacs low level keyboard +hook is activated, if ON is nil it is deactivated. + +The keys that can be trapped are the left and right windows keys (not +present on all keyboards). If `w32-pass-lwindow-to-system' and +`w32-pass-rwindow-to-system' are nil they will not be sent to the +system (ie Explorer). + +WARNING: If you set any of those variables to nil you should activate +this hook. Otherwise Windows will still see these keys and do other +things than you expected. +*/) + + (on) + Lisp_Object on; +{ + DWORD wparam = 1; + if (NILP(on)) { + //printf("before KBD_LL = 0\n"); fflush(stdout); + PostThreadMessage (dwWindowsThreadId, WM_EMACS_KDB_LL, (WPARAM) 0, 0); + } else { + //printf("before KBD_LL = 1\n"); fflush(stdout); + PostThreadMessage (dwWindowsThreadId, WM_EMACS_KDB_LL, (WPARAM) 1, 0); + } + //printf("after postmess KBD_LL\n"); fflush(stdout); +} + DEFUN ("w32-register-hot-key", Fw32_register_hot_key, Sw32_register_hot_key, 1, 1, 0, doc: /* Register KEY as a hot-key combination. @@ -8853,6 +9077,7 @@ defsubr (&Sw32_load_color_file); defsubr (&Sw32_send_sys_command); defsubr (&Sw32_shell_execute); + defsubr (&Sw32_set_wh_keyboard_ll); defsubr (&Sw32_register_hot_key); defsubr (&Sw32_unregister_hot_key); defsubr (&Sw32_registered_hot_keys); Index: src/w32menu.c =================================================================== RCS file: /cvsroot/emacs/emacs/src/w32menu.c,v retrieving revision 1.75 diff -u -r1.75 w32menu.c --- src/w32menu.c 25 Jul 2005 22:16:11 -0000 1.75 +++ src/w32menu.c 28 Jul 2005 23:10:18 -0000 @@ -985,7 +985,8 @@ f->output_data.w32->menubar_active = 1; /* Signal input thread to return from WM_INITMENU. */ - complete_deferred_msg (FRAME_W32_WINDOW (f), WM_INITMENU, 0); + //complete_deferred_msg (FRAME_W32_WINDOW (f), WM_INITMENU, 0); + if (!PostThreadMessage(dwWindowsThreadId, WM_EMACS_DONE, 0, 0)) abort(); } /* This callback is called from the menu bar pulldown menu Index: src/w32term.h =================================================================== RCS file: /cvsroot/emacs/emacs/src/w32term.h,v retrieving revision 1.63 diff -u -r1.63 w32term.h --- src/w32term.h 4 Jul 2005 16:06:37 -0000 1.63 +++ src/w32term.h 28 Jul 2005 23:10:21 -0000 @@ -632,7 +632,8 @@ #define WM_EMACS_SHOW_CARET (WM_EMACS_START + 17) #define WM_EMACS_HIDE_CARET (WM_EMACS_START + 18) #define WM_EMACS_SETCURSOR (WM_EMACS_START + 19) -#define WM_EMACS_END (WM_EMACS_START + 20) +#define WM_EMACS_KDB_LL (WM_EMACS_START + 20) +#define WM_EMACS_END (WM_EMACS_START + 21) #define WND_FONTWIDTH_INDEX (0) #define WND_LINEHEIGHT_INDEX (4)