From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: "Lennart Borgman (gmail)" Newsgroups: gmane.emacs.devel Subject: Using windows keys for Emacs META on w32 Date: Sat, 05 Jan 2008 21:48:48 +0100 Message-ID: <477FED30.10201@gmail.com> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------010001070509000101060004" X-Trace: ger.gmane.org 1199566287 32372 80.91.229.12 (5 Jan 2008 20:51:27 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sat, 5 Jan 2008 20:51:27 +0000 (UTC) To: Emacs Devel , Juanma Barranquero , Eli Zaretskii Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sat Jan 05 21:51:44 2008 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1JBFzD-0003di-IM for ged-emacs-devel@m.gmane.org; Sat, 05 Jan 2008 21:51:43 +0100 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1JBFyg-0008Ke-H3 for ged-emacs-devel@m.gmane.org; Sat, 05 Jan 2008 15:50:46 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1JBFya-0008J4-Te for emacs-devel@gnu.org; Sat, 05 Jan 2008 15:50:41 -0500 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1JBFyS-0008CH-NR for emacs-devel@gnu.org; Sat, 05 Jan 2008 15:50:40 -0500 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1JBFyS-0008CE-EZ for emacs-devel@gnu.org; Sat, 05 Jan 2008 15:50:32 -0500 Original-Received: from ch-smtp02.sth.basefarm.net ([80.76.149.213]) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1JBFxX-0002Sq-Mx; Sat, 05 Jan 2008 15:49:47 -0500 Original-Received: from c83-254-148-228.bredband.comhem.se ([83.254.148.228]:61081 helo=[127.0.0.1]) by ch-smtp02.sth.basefarm.net with esmtp (Exim 4.68) (envelope-from ) id 1JBFwn-0000Es-6i; Sat, 05 Jan 2008 21:48:53 +0100 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.9) Gecko/20071031 Thunderbird/2.0.0.9 Mnenhy/0.7.5.666 X-Antivirus: avast! (VPS 080105-0, 2008-01-05), Outbound message X-Antivirus-Status: Clean X-Originating-IP: 83.254.148.228 X-Scan-Result: No virus found in message 1JBFwn-0000Es-6i. X-Scan-Signature: ch-smtp02.sth.basefarm.net 1JBFwn-0000Es-6i 25b3f7dc9fb8f4fdcc4a6543e665ad7b X-detected-kernel: by monty-python.gnu.org: Linux 2.6? (barebone, rare!) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:86231 Archived-At: This is a multi-part message in MIME format. --------------010001070509000101060004 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit I promised Juanma to make a new patch with the changes I have made to allow using the windows left and/or right keys for Emacs meta. Here it is, in a bit rough state. --------------010001070509000101060004 Content-Type: text/plain; name="ll-keyboard.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="ll-keyboard.diff" Index: src/w32fns.c =================================================================== RCS file: /sources/emacs/emacs/src/w32fns.c,v retrieving revision 1.310 diff -u -b -r1.310 w32fns.c --- src/w32fns.c 29 Dec 2007 19:20:04 -0000 1.310 +++ src/w32fns.c 5 Jan 2008 20:05:42 -0000 @@ -2155,9 +2155,20 @@ #define EMACS_LMENU 2 #define EMACS_RMENU 3 -static int modifiers[4]; +/* The keys above are also saved in modifiers[]. To allow + w32-pass-lwindow-to-system to be nil the state of the left and + right windows keys must also be saved in modifiers[]. This is a bit + tricky since Windows does not keep track of the state of those keys + when StickyKeys are on. (Because they are registered as hot + keys?) */ + +#define EMACS_LWIN 4 +#define EMACS_RWIN 5 + +static int modifiers[6]; static int modifiers_recorded; static int modifier_key_support_tested; +static BOOL b_menu_pending = FALSE; static void test_modifier_support (unsigned int wparam) @@ -2191,10 +2202,25 @@ if (!modifier_key_support_tested) test_modifier_support (wparam); + if (VK_LWIN != wparam && VK_RWIN != wparam) { if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded) return; + } else { + if (VK_LWIN == wparam && !NILP(Vw32_pass_lwindow_to_system)) { + return; + } + if (VK_RWIN == wparam && !NILP(Vw32_pass_rwindow_to_system)) { + return; + } + } - if (wparam == VK_CONTROL) + //printf("record_keydow2 wp=%d lp=%x\n", wparam, lparam); fflush(stdout); + + if (VK_LWIN == wparam) { + i = EMACS_LWIN; + } else if (VK_RWIN == wparam) { + i = EMACS_RWIN; + } else if (wparam == VK_CONTROL) i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL; else i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU; @@ -2207,17 +2233,47 @@ { int i; + if (VK_LWIN != wparam && VK_RWIN != wparam) { if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded) return; + } else { + if (VK_LWIN == wparam && !NILP(Vw32_pass_lwindow_to_system)) { + return; + } + if (VK_RWIN == wparam && !NILP(Vw32_pass_rwindow_to_system)) { + return; + } + } + //printf("record_keyup2 wp=%d lp=%x\n", wparam, lparam); fflush(stdout); - if (wparam == VK_CONTROL) + if (VK_LWIN == wparam) { + i = EMACS_LWIN; + } else if (VK_RWIN == wparam) { + i = EMACS_RWIN; + } else if (wparam == VK_CONTROL) i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL; else i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU; + if (EMACS_LWIN == i || EMACS_RWIN == i) { + //printf("record_keyup wp=%d, i=%d\n", wparam, i); fflush(stdout); + } modifiers[i] = 0; } +static void +set_key_state(int vkey, int state) +{ + BYTE keystate[256]; + +#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8) + + GetKeyboardState (keystate); + keystate[vkey] = state; + SetKeyboardState (keystate); +} + + /* Emacs can lose focus while a modifier key has been pressed. When it regains focus, be conservative and clear all modifiers since we cannot reconstruct the left and right modifier state. */ @@ -2230,6 +2286,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); @@ -2241,6 +2300,15 @@ /* Clear any recorded alt modifier state. */ modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0; + if (!(GetAsyncKeyState(VK_LWIN) & 0x08000)) { + //printf("EMACS_LWIN 1=0\n"); fflush(stdout); + modifiers[EMACS_LWIN] = 0; + } + if (!(GetAsyncKeyState(VK_RWIN) & 0x08000)) { + //printf("EMACS_RWIN 1=0\n"); fflush(stdout); + modifiers[EMACS_RWIN] = 0; + } + /* Update the state of all modifier keys, because modifiers used in hot-key combinations can get stuck on if Emacs loses focus as a result of a hot-key being pressed. */ @@ -2279,13 +2347,31 @@ if (!(GetKeyState (VK_MENU) & 0x8000)) modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0; + + if (!(GetKeyState (VK_LWIN) & 0x8000)) { + //printf("EMACS_LWIN 2=0\n"); fflush(stdout); + modifiers[EMACS_LWIN] = 0; + } + if (!(GetKeyState (VK_RWIN) & 0x8000)) { + //printf("EMACS_RWIN 2=0\n"); fflush(stdout); + modifiers[EMACS_RWIN] = 0; + } } static int modifier_set (int vkey) { + //if (vkey) { printf("modifier_set %d\n", vkey); fflush(stdout); } if (vkey == VK_CAPITAL || vkey == VK_SCROLL) return (GetKeyState (vkey) & 0x1); + if (VK_LWIN == vkey && NILP(Vw32_pass_lwindow_to_system)) { + //printf("modifier_set L %d, %d\n", vkey, modifiers[EMACS_LWIN]); fflush(stdout); + return modifiers[EMACS_LWIN]; + } + if (VK_RWIN == vkey && NILP(Vw32_pass_rwindow_to_system)) { + //printf("modifier_set R %d, %d\n", vkey, modifiers[EMACS_RWIN]); fflush(stdout); + return modifiers[EMACS_RWIN]; + } if (!modifiers_recorded) return (GetKeyState (vkey) & 0x8000); @@ -2481,6 +2567,13 @@ } } +int cAccelerators = 0; // number of accelerators in table +static HACCEL hAccelDyn = NULL; +static LPACCEL lpaccelDyn = NULL; + +BOOL add_LowLevelKeyboardProc(); +BOOL remove_LowLevelKeyboardProc(); + /* Main message dispatch loop. */ static void @@ -2489,11 +2582,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) @@ -2501,6 +2598,27 @@ case WM_NULL: /* Produced by complete_deferred_msg; just ignore. */ break; + case WM_QUERYENDSESSION: + //case WM_ENDSESSION: default handling + /* This is currently not used since Emacs does not + recieve this message (at least not to the windows + thread) but might be if Emacs is restructured. */ + { + W32Msg wmsg; + //printf("w32_msg_pump 1: WM_QUERYENDSESSION\n"); fflush(stdout); + my_post_msg (&wmsg, 0, WM_EMACS_KILL, 0, 0); + break; + } + case WM_EMACS_KBD_LL: + if (msg.wParam) { + result = (int) add_LowLevelKeyboardProc(); + } else { + result = (int) remove_LowLevelKeyboardProc(); + } + if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, + result, 0)) + abort (); + 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 @@ -2583,7 +2701,18 @@ } else { - DispatchMessage (&msg); + BOOL bHandled = FALSE; + if (hAccelDyn) + if (Vw32_pass_alt_to_system) { + bHandled = TranslateAccelerator(msg.hwnd, hAccelDyn, &msg); + if (bHandled) { + //printf("...handled\n"); fflush(stdout); + } else { + printf("...TA failed: %s\n", w32_strerror(GetLastError())); fflush(stdout); + } + } + if (!bHandled) DispatchMessage (&msg); + } } /* Exit nested loop when our deferred message has completed. */ @@ -2688,6 +2817,130 @@ PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0); } + + +LRESULT +//HOOKPROC +LowLevelKeyboardProc(INT nCode, WPARAM wParam, LPARAM lParam) +{ + if (nCode == HC_ACTION) + { + KBDLLHOOKSTRUCT *pkbdllhook = (KBDLLHOOKSTRUCT *)lParam; + BOOL bHandle = FALSE; + UINT transition_state; + UINT previous_state = 0; + UINT context_code; + UINT extended_key; + UINT msg; + WPARAM wParamMsg; + LPARAM lParamMsg; + + switch (wParam) + { + case WM_KEYUP: + case WM_SYSKEYUP: + previous_state = 1; + case WM_KEYDOWN: // This was not in the MS example, why?? + case WM_SYSKEYDOWN: + /* Convert the message and send it on. + FIX-ME: This code should be moved down to bHandle part after + testing. */ + transition_state = pkbdllhook->flags >> 7 & 1; + context_code = pkbdllhook->flags >> 5 & 1; + extended_key = pkbdllhook->flags & 1; + msg = wParam; + wParamMsg = pkbdllhook->vkCode; + lParamMsg = + pkbdllhook->scanCode << 16 + | transition_state << 31 + | previous_state << 30 + | context_code << 29 + | extended_key << 24 + | 1; // repeat count +/* if (0 != GetFocus()) { */ +/* if (91 == pkbdllhook->vkCode) { */ +/* printf("ll wp=%d lp=%x, ts=%d, cc=%d, ek=%d\n", wParamMsg, lParamMsg, transition_state, context_code, extended_key); */ +/* fflush(stdout); */ +/* } */ +/* } */ + 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; + } + case VK_CAPITAL: + { + bHandle = NILP(Vw32_enable_caps_lock); + break; + } + case VK_NUMLOCK: + { + bHandle = NILP(Vw32_enable_num_lock); + 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) { + //printf("ll SendMessage(hwnd, msg, %x, %x)\n", wParamMsg, lParamMsg); fflush(stdout); + SendMessage (hwnd, msg, wParamMsg, lParamMsg); + return TRUE; + } + } + } + + + + } + HHOOK hhook; return CallNextHookEx(hhook, nCode, wParam, lParam); +} + +static HHOOK hLowKBhookW = NULL; + +BOOL +add_LowLevelKeyboardProc() +{ + if (NULL != hLowKBhookW) return TRUE; + if (GetCurrentThreadId() == dwWindowsThreadId) { + hLowKBhookW = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC) LowLevelKeyboardProc, (HINSTANCE) GetModuleHandle(NULL), 0); + if (NULL == hLowKBhookW) { + printf("SetWindowsHookEx error: %s\n", w32_strerror(GetLastError())); fflush(stdout); + return FALSE; + } + } else { + printf("add_LowLevelKeyboardProc called from other thread then windows thread\n"); fflush(stdout); + abort(); + } + return TRUE; +} +BOOL +remove_LowLevelKeyboardProc() +{ + if (NULL == hLowKBhookW) return TRUE; + if (!UnhookWindowsHookEx(hLowKBhookW)) { + printf("UnhookWindowsHookEx error: %s\n", w32_strerror(GetLastError())); fflush(stdout); + } + hLowKBhookW = NULL; +} + + DWORD WINAPI w32_msg_worker (void *arg) { @@ -2707,8 +2960,33 @@ /* 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. The + code is written after an example from MS but it does not work ;-) + */ +/* 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); */ +/* } else { */ +/* printf("LocalAlloc ok: %s\n", w32_strerror(GetLastError())); fflush(stdout); */ +/* } */ +/* lpaccelDyn[0].fVirt = FVIRTKEY; */ +/* lpaccelDyn[0].key = VK_F4; */ +/* lpaccelDyn[0].cmd = 0; //SC_CLOSE; */ +/* hAccelDyn = CreateAcceleratorTable(lpaccelDyn, cAccelerators); */ +/* if (!hAccelDyn) { */ +/* printf("CreateAcceleratorTable error: %s\n", w32_strerror(GetLastError())); fflush(stdout); */ +/* } else { */ +/* printf("CreateAcceleratorTable ok: %s\n", w32_strerror(GetLastError())); fflush(stdout); */ +/* } */ + w32_msg_pump (&dummy_buf); + if (lpaccelDyn) { + LocalFree(lpaccelDyn); + } + return 0; } @@ -2731,17 +3009,25 @@ static void -post_character_message (hwnd, msg, wParam, lParam, modifiers) +post_character_message (hwnd, msg, wParam, lParam, dwmodifiers) HWND hwnd; UINT msg; WPARAM wParam; LPARAM lParam; - DWORD modifiers; + DWORD dwmodifiers; { W32Msg wmsg; - wmsg.dwModifiers = modifiers; + //printf("post_char, msg=%d, wp=%x, lp=%x, mod=%x\n", msg, wParam, lParam, dwmodifiers); fflush(stdout); + // Clear LWIN here to be able to handle it for StickyKeys + modifiers[EMACS_LWIN] = modifiers[EMACS_RWIN] = 0; + + // Never post alt_modifier here if system should have ALT + if (!NILP (Vw32_pass_alt_to_system)) { + dwmodifiers = (dwmodifiers | alt_modifier) ^ alt_modifier; + } + wmsg.dwModifiers = dwmodifiers; /* Detect quit_char and set quit-flag directly. Note that we still need to post a message to ensure the main thread will be @@ -2803,6 +3089,17 @@ WPARAM wParam; LPARAM lParam; { + //printf("w32_wnd_proc(hwnd, %d, %x, %x)\n", msg, wParam, lParam); fflush(stdout); + BOOL bStickyKeysOn = FALSE; + STICKYKEYS stick; + /* Bit 24 should be "extended key" for key messages. However + it seems to have some other functions too when StickyKeys are + on. */ + BOOL bit24 = FALSE; + /* Bit 29 is context code for key messages (Alt pressed or not) */ + //BOOL bit29 = FALSE; + static BOOL b_was_menu_pending = FALSE; + struct frame *f; struct w32_display_info *dpyinfo = &one_w32_display_info; W32Msg wmsg; @@ -2942,13 +3239,136 @@ PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0); return (0); - case WM_KEYUP: + case WM_SYSCOMMAND: + //printf("WM_SYSCOMMAND, wpar=%x, lpar=%x\n", wParam, lParam); fflush(stdout); + goto dflt; case WM_SYSKEYUP: + case WM_KEYUP: +/* 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; */ +/* } */ + + 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; + } + if (lParam >> 24 & 1) bit24 = TRUE; +/* { */ +/* BOOL vkmenu = FALSE; */ +/* BOOL vklmenu = FALSE; */ +/* BOOL vkrmenu = FALSE; */ +/* BOOL vklwin = FALSE; */ +/* BOOL vkrwin = FALSE; */ +/* BOOL vklwset = FALSE; */ +/* BOOL vkrwset = FALSE; */ +/* switch (wParam) { */ +/* case VK_MENU: */ +/* vkmenu = TRUE; */ +/* break; */ +/* case VK_RMENU: */ +/* vkrmenu = TRUE; */ +/* break; */ +/* case VK_LMENU: */ +/* vklmenu = TRUE; */ +/* break; */ +/* case VK_LWIN: */ +/* vklwin = TRUE; */ +/* break; */ +/* case VK_RWIN: */ +/* vkrwin = TRUE; */ +/* break; */ +/* } */ +/* vklwset = modifier_set(VK_LWIN); */ +/* vkrwset = modifier_set(VK_RWIN); */ +/* //if (91 == wParam) */ +/* //printf("WM_KUP, m=%d wp=%d lp=%x VK_M=%x VK_LM=%x VK_RM=%x VK_LW=%x 24=%x st=%d,%d\n", */ +/* printf(" WM_KUP, m=%d wp=%d lp=%8x VK_LW=%x,%x VK_RW=%x,%x 24=%x st=%d,%d\n", */ +/* //msg, wParam, lParam, vkmenu, vklmenu, vkrmenu, vklwin, */ +/* msg, wParam, lParam, vklwin, vklwset, vkrwin, vkrwset, */ +/* bit24, */ +/* GetKeyState(wParam), GetAsyncKeyState(wParam) */ +/* ); fflush(stdout); */ +/* if (wParam==8) { printf("\n"); fflush(stdout); } */ +/* } */ + + /* If StickyKeys is on we need to record VK_LWIN and VK_RWIN + when the system sends the special key up message when + pressing next key. */ + /* FIX-ME: Key state toggling works only with VK_LWIN! The code + below tries to make the use of LWIN and RWIN work in Emacs + both when using StickyKeys and not. When using StickyKeys + the keys should be "toggleable". Bit 24 seems to be useful + for toggling LWIN, but not for RWIN. For some reason the + messages sent in Windows are not the same for LWIN and RWIN. + I do not believe that the use of bit 24 this way is + documented so this part of the code might break. In that + case the version without bit 24 could be used. The only + thing that is lost is the possibility to toggle the state of + LWIN. From a user perspective this can always be done by + pressing C-g since M-C-g is never bound (I hope!). */ + //if (!((VK_LWIN == wParam || VK_RWIN ==wParam) && bStickyKeysOn)) + if (!(((VK_LWIN == wParam && 0 == bit24) || VK_RWIN == wParam) && bStickyKeysOn)) record_keyup (wParam, lParam); goto dflt; - case WM_KEYDOWN: case WM_SYSKEYDOWN: + case WM_KEYDOWN: + 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; + } + if (lParam >> 24 & 1) bit24 = TRUE; + +/* { */ +/* BOOL vkmenu = FALSE; */ +/* BOOL vklmenu = FALSE; */ +/* BOOL vkrmenu = FALSE; */ +/* BOOL vklwin = FALSE; */ +/* BOOL vkrwin = FALSE; */ +/* BOOL vklwset = FALSE; */ +/* BOOL vkrwset = FALSE; */ +/* switch (wParam) { */ +/* case VK_MENU: */ +/* vkmenu = TRUE; */ +/* break; */ +/* case VK_RMENU: */ +/* vkrmenu = TRUE; */ +/* break; */ +/* case VK_LMENU: */ +/* vklmenu = TRUE; */ +/* break; */ +/* case VK_LWIN: */ +/* vklwin = TRUE; */ +/* break; */ +/* case VK_RWIN: */ +/* vkrwin = TRUE; */ +/* break; */ +/* } */ +/* vklwset = modifier_set(VK_LWIN); */ +/* vkrwset = modifier_set(VK_RWIN); */ +/* if (lParam >> 24 & 1) bit24 = TRUE; */ +/* //if (91 == wParam) */ +/* //printf("WM_DWN m=%d w=%d lp=%x VK_M=%x VK_LM=%x VK_RM=%x VK_LW=%x B24=%x 29=%d BS=%x, s=%d,%d sy=%d\n", */ +/* printf("WM_DWN, m=%d wp=%d lp=%10x VK_LW=%x,%x VK_RW=%x,%x 24=%x st=%d,%d\n", */ +/* msg, wParam, lParam, vklwin, vklwset, vkrwin, vkrwset, */ +/* bit24, */ +/* GetKeyState(wParam), GetAsyncKeyState(wParam) */ +/* ); fflush(stdout); */ +/* } */ + /* Ignore keystrokes we fake ourself; see below. */ if (dpyinfo->faked_key == wParam) { @@ -2957,7 +3377,7 @@ they don't produce WM_CHAR messages). This ensures that indicator lights are toggled promptly on Windows 9x, for example. */ - if (wParam < 256 && lispy_function_keys[wParam]) + if (lispy_function_keys[wParam] != 0) { windows_translate = 1; goto translate; @@ -2966,6 +3386,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 +3397,13 @@ switch (wParam) { case VK_LWIN: + if (NULL == hLowKBhookW) { if (NILP (Vw32_pass_lwindow_to_system)) { /* Prevent system from acting on keyup (which opens the Start menu if no other key was pressed) by simulating a press of Space which we will ignore. */ + //printf("Sending 255 to prevent\n"); fflush(stdout); if (GetAsyncKeyState (wParam) & 1) { if (NUMBERP (Vw32_phantom_key_code)) @@ -2990,10 +3414,13 @@ keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0); } } - if (!NILP (Vw32_lwindow_modifier)) - return 0; + } else { + //printf("Avoided sending 255 to prevent\n"); fflush(stdout); + } + if (!NILP (Vw32_lwindow_modifier)) return 0; break; case VK_RWIN: + if (NULL == hLowKBhookW) { if (NILP (Vw32_pass_rwindow_to_system)) { if (GetAsyncKeyState (wParam) & 1) @@ -3006,8 +3433,8 @@ keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0); } } - if (!NILP (Vw32_rwindow_modifier)) - return 0; + } + if (!NILP (Vw32_rwindow_modifier)) return 0; break; case VK_APPS: if (!NILP (Vw32_apps_modifier)) @@ -3018,6 +3445,11 @@ /* Prevent DefWindowProc from activating the menu bar if an Alt key is pressed and released by itself. */ return 0; + /* By not testing for StickyKeysOn here 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. */ + b_menu_pending = TRUE; windows_translate = 1; break; case VK_CAPITAL: @@ -3078,8 +3510,26 @@ wParam = VK_NUMLOCK; break; default: + if (b_was_menu_pending) { + /* FIX-ME: Where should this go? Should it go to the + WM_CHAR section where the translated WM_KEY... returns? + (Remember to move b_was_menu_pending too!) */ + 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 (wParam > 255 || !lispy_function_keys[wParam]) + if (lispy_function_keys[wParam] == 0) { DWORD modifiers = construct_console_modifiers (); @@ -3441,6 +3891,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 @@ -3478,9 +3931,25 @@ if (find_deferred_msg (hwnd, msg) != NULL) abort (); + my_post_msg (&wmsg, hwnd, msg, wParam, lParam); + { + MSG msg; + /* 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". */ + // FIX-ME: maybe check for C-g in the loop! + int i; + for (i = 1; i < 50; i++) { + if (PeekMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE, PM_REMOVE)) break; + Sleep(40); + } + } menubar_in_use = 1; - return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam); + //return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam); + + return 0; } case WM_EXITMENULOOP: @@ -3669,10 +4138,21 @@ return 0; case WM_CLOSE: + //printf("w32_wnd_proc WM_CLOSE\n"); fflush(stdout); wmsg.dwModifiers = w32_get_modifiers (); my_post_msg (&wmsg, hwnd, msg, wParam, lParam); return 0; + case WM_QUERYENDSESSION: + //case WM_ENDSESSION: + // I do not think this should happen but I am not sure. + { + W32Msg wmsg; + //printf("w32_wnd_proc: WM_QUERYENDSESSION\n"); fflush(stdout); + my_post_msg (&wmsg, 0, WM_EMACS_KILL, 0, 0); + } + return 0; + case WM_WINDOWPOSCHANGING: /* Don't restrict the sizing of tip frames. */ if (hwnd == tip_window) @@ -3726,15 +4206,17 @@ However for top/left sizing we will need to fix the X and Y positions as well. */ + + if (wp.showCmd != SW_SHOWMAXIMIZED + && (lppos->flags & SWP_NOMOVE) == 0) + { +/* lppos->cx -= wdiff; */ +/* lppos->cy -= hdiff; */ int cx_mintrack = GetSystemMetrics (SM_CXMINTRACK); int cy_mintrack = GetSystemMetrics (SM_CYMINTRACK); lppos->cx = max (lppos->cx - wdiff, cx_mintrack); lppos->cy = max (lppos->cy - hdiff, cy_mintrack); - - if (wp.showCmd != SW_SHOWMAXIMIZED - && (lppos->flags & SWP_NOMOVE) == 0) - { if (lppos->x != wr.left || lppos->y != wr.top) { lppos->x += wdiff; @@ -3810,9 +4292,15 @@ case WM_EMACS_SETWINDOWPOS: { WINDOWPOS * pos = (WINDOWPOS *) wParam; + if (IsZoomed(hwnd)) { + return SetWindowPos (hwnd, pos->hwndInsertAfter, + pos->x, pos->y, pos->cx, pos->cy, + pos->flags | SWP_NOMOVE | SWP_NOSIZE); + } else { return SetWindowPos (hwnd, pos->hwndInsertAfter, pos->x, pos->y, pos->cx, pos->cy, pos->flags); } + } case WM_EMACS_DESTROYWINDOW: DragAcceptFiles ((HWND) wParam, FALSE); @@ -8242,6 +8730,42 @@ return HOTKEY (vk_code, w32_modifiers); } +DEFUN ("w32-wh-keyboard-ll", Fw32_wh_keyboard_ll, + Sw32_wh_keyboard_ll, 1, 1, 0, + doc: /* Activate/deactivate Emacs low level keyboard hook. +A low level Windows keyboard hook must be used to trap keys that other +applications have registered as hot 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. Beware that these are not present on all keyboards. If +`w32-pass-lwindow-to-system' and `w32-pass-rwindow-to-system' are nil +these keys will not be sent to the application that has registered +them as hot keys if Emacs low level keyboard hook as active. + +You should normally not call this function directly. Use +`w32-meta-style' instead. */) + (on) + Lisp_Object on; +{ +/* if (EQ (Vwindow_system, intern ("w32"))) */ +/* if (EQ (Vwindow_system_version, intern ("w32"))) */ +/* { */ + DWORD wp = 1; + MSG msg; + if (NILP(on)) wp = 0; + if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_KBD_LL, (WPARAM) wp, 0)) + abort(); + GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE); + if (msg.wParam == 0) return Qnil; + return Qt; +/* } */ +/* else */ +/* { */ +/* return Qnil; */ +/* } */ +} + DEFUN ("w32-register-hot-key", Fw32_register_hot_key, Sw32_register_hot_key, 1, 1, 0, doc: /* Register KEY as a hot-key combination. @@ -9050,6 +9574,7 @@ defsubr (&Sw32_load_color_file); defsubr (&Sw32_send_sys_command); defsubr (&Sw32_shell_execute); + defsubr (&Sw32_wh_keyboard_ll); defsubr (&Sw32_register_hot_key); defsubr (&Sw32_unregister_hot_key); defsubr (&Sw32_registered_hot_keys); Index: src/w32menu.c =================================================================== RCS file: /sources/emacs/emacs/src/w32menu.c,v retrieving revision 1.94 diff -u -b -r1.94 w32menu.c --- src/w32menu.c 17 Oct 2007 23:43:50 -0000 1.94 +++ src/w32menu.c 4 Jan 2008 23:56:04 -0000 @@ -2291,8 +2291,7 @@ /* With UTF-8, & cannot be part of a multibyte character. */ for (p = out_string; *p; p++) { - if (*p == '&') - nlen++; + // if (*p == '&') nlen++; } } else Index: src/w32term.h =================================================================== RCS file: /sources/emacs/emacs/src/w32term.h,v retrieving revision 1.75 diff -u -b -r1.75 w32term.h --- src/w32term.h 30 Nov 2007 13:57:46 -0000 1.75 +++ src/w32term.h 5 Jan 2008 19:59:46 -0000 @@ -641,7 +641,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_KBD_LL (WM_EMACS_START + 20) +#define WM_EMACS_END (WM_EMACS_START + 21) #define WND_FONTWIDTH_INDEX (0) #define WND_LINEHEIGHT_INDEX (4) --------------010001070509000101060004 Content-Type: text/plain; name="w32-meta.el" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="w32-meta.el" ;;; w32-meta.el --- Handling of Alt and Windows keys ;; Copyright (C) 2005, 2006, 2007 by Lennart Borgman ;; Author: Lennart Borgman ;; Created: 2005-07-30 ;; Version: 0.50 ;; Last-Updated: Tue Oct 30 18:29:33 2007 (3600 +0100) ;; Keywords: w32 keyboard ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Commentary: ;; ;; This files requires that Emacs has the function ;; `w32-wh-keyboard-ll'. This is not yet part of Emacs but is included ;; in the patched Emacs available on EmacsW32 home page. ;; ;; This file makes it simple to setup the left and right windows keys ;; for use as meta and the Alt key for use by the menus. ;; For more info see `w32-meta-style'. ;; ;; Usage: ;; ;; (require 'w32-meta) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; History: ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; This file is not part of Emacs ;; ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation; either version 2, or (at ;; your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; ;; To find out more about the GNU General Public License you can visit ;; Free Software Foundation's website http://www.fsf.org/. Or, write ;; to the Free Software Foundation, Inc., 51 Franklin Street, Fifth ;; Floor, Boston, MA 02110-1301, USA. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Code: (defun w32-meta-set-w32-style (lwindow-meta rwindow-meta) "Setup Emacs to feel more familiar to an MS Windows user. Alt will be used for the menus. If LWINDOW-META is non-nil then the left Windows keyboard key will not be passed to MS Windows. Instead it will be used as Meta in Emacs. The same applies to RWINDOW-META. You can set this through custom with the variable `w32-meta-style'. See also `w32-meta-set-emacs-style'. This is an high level interface to `w32-wh-keyboard-ll', `w32-pass-lwindow-to-system', `w32-pass-rwindow-to-system', `w32-pass-alt-to-system' and `w32-alt-is-meta'. The `w32-wh-keyboard-ll' is not called unless `window-system' is 'w32." (interactive (list (y-or-n-p "Use left Windows key (lwindow) as Meta? ") (y-or-n-p "Use right Windows key (rwindow) as Meta? "))) (and (eq window-system 'w32) (or lwindow-meta rwindow-meta) (unless (w32-wh-keyboard-ll t) (error "w32-wh-keyboard-ll failed add"))) (when lwindow-meta ;;(global-set-key [(lwindow)] 'ESC-prefix) (setq w32-lwindow-modifier 'meta) (setq w32-pass-lwindow-to-system nil)) (when rwindow-meta ;;(global-set-key [(rwindow)] 'ESC-prefix) (setq w32-rwindow-modifier 'meta) (setq w32-pass-rwindow-to-system nil)) (setq w32-pass-alt-to-system t) (setq w32-alt-is-meta nil)) (defun w32-meta-set-emacs-style () "Setup Emacs to be more familiar to a non MS Windows user. Alt will be used for Emacs Meta. and will be passed to MS Windows. See also `w32-meta-set-w32-style'." (interactive) (when (eq window-system 'w32) (unless (w32-wh-keyboard-ll nil) (error "w32-wh-keyboard-ll failed remove"))) (global-set-key [(lwindow)] 'ignore) (global-set-key [(rwindow)] 'ignore) (setq w32-pass-lwindow-to-system t) (setq w32-pass-rwindow-to-system t) (setq w32-lwindow-modifier nil) (setq w32-rwindow-modifier nil) (setq w32-pass-alt-to-system nil) (setq w32-alt-is-meta t)) (defcustom w32-meta-style 'emacs "Defines how Emacs treats Alt, left and right Windows keys. For more info see function `w32-meta-set-w32-style'." :group 'w32 :type '(choice (const :tag "Emacs default Alt handling+Windows keys default handling" emacs) (const :tag "MS Windows default Alt handling+left and right Windows key as Meta" w32-lr) (const :tag "MS Windows default Alt handling+left Windows key as Meta" w32-l) (const :tag "MS Windows default Alt handling+right Windows key as Meta" w32-r) (const :tag "MS Windows default Alt handling" w32)) :set (lambda (symbol value) (unless (memq value '(emacs w32-lr w32-l w32-r w32)) (error "Bad value to w32-meta-style")) (set-default symbol value) (cond ((eq value 'emacs) (w32-meta-set-emacs-style)) ((eq value 'w32-lr) (w32-meta-set-w32-style t t)) ((eq value 'w32-l) (w32-meta-set-w32-style t nil)) ((eq value 'w32-r) (w32-meta-set-w32-style nil t)) ((eq value 'w32) (w32-meta-set-w32-style nil nil))))) ;;(w32-meta-set-w32-style t nil) (provide 'w32-meta) ;;; w32-meta.el ends here --------------010001070509000101060004 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-devel --------------010001070509000101060004--