[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Using windows keys for Emacs META on w32
From: |
Lennart Borgman (gmail) |
Subject: |
Using windows keys for Emacs META on w32 |
Date: |
Sat, 05 Jan 2008 21:48:48 +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 |
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.
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)
;;; w32-meta.el --- Handling of Alt and Windows keys
;; Copyright (C) 2005, 2006, 2007 by Lennart Borgman
;; Author: Lennart Borgman <lennart DOT borgman DOT 073 AT student DOT lu
DOT se>
;; 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. <lwindow> and <rwindow> 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
- Using windows keys for Emacs META on w32,
Lennart Borgman (gmail) <=