X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/6cdfb6e60ddaa1486ae70374e13bb5deeb40c2f0..684d6f5bccb1f3f4e4935a5d9c95b2c5f6f5b8a1:/src/w32inevt.c diff --git a/src/w32inevt.c b/src/w32inevt.c dissimilarity index 64% index e41c57e5fe..fa2d34c299 100644 --- a/src/w32inevt.c +++ b/src/w32inevt.c @@ -1,459 +1,730 @@ -/* Input event support for Windows NT port of GNU Emacs. - Copyright (C) 1992, 1993 Free Software Foundation, Inc. - - This file is part of GNU Emacs. - - GNU Emacs 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. - - GNU Emacs 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. - - You should have received a copy of the GNU General Public License along - with GNU Emacs; see the file COPYING. If not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - Drew Bliss 01-Oct-93 - Adapted from ntkbd.c by Tim Fleehart -*/ - - -#include "config.h" - -#include -#include -#include - -#include "lisp.h" -#include "frame.h" -#include "blockinput.h" -#include "termhooks.h" - -/* stdin, from ntterm */ -extern HANDLE keyboard_handle; - -/* Indicate mouse motion, from keyboard.c */ -extern int mouse_moved; - -/* Info for last mouse motion */ -static COORD movement_pos; -static DWORD movement_time; - -/* from keyboard.c */ -extern void reinvoke_input_signal (void); - -/* from dispnew.c */ -extern int change_frame_size (FRAME_PTR, int, int, int, int); - -/* Event queue */ -#define EVENT_QUEUE_SIZE 50 -static INPUT_RECORD event_queue[EVENT_QUEUE_SIZE]; -static INPUT_RECORD *queue_ptr = event_queue, *queue_end = event_queue; - -static int -fill_queue (BOOL block) -{ - BOOL rc; - DWORD events_waiting; - - if (queue_ptr < queue_end) - return queue_end-queue_ptr; - - if (!block) - { - /* Check to see if there are some events to read before we try - because we can't block. */ - if (!GetNumberOfConsoleInputEvents (keyboard_handle, &events_waiting)) - return -1; - if (events_waiting == 0) - return 0; - } - - rc = ReadConsoleInput (keyboard_handle, event_queue, EVENT_QUEUE_SIZE, - &events_waiting); - if (!rc) - return -1; - queue_ptr = event_queue; - queue_end = event_queue + events_waiting; - return (int) events_waiting; -} - -/* In a generic, multi-frame world this should take a console handle - and return the frame for it - - Right now, there's only one frame so return it. */ -static FRAME_PTR -get_frame (void) -{ - return selected_frame; -} - -#ifdef MULTI_FRAME -#define SET_FRAME(o, f) XSET (o, Lisp_Frame, f) -#else -#define SET_FRAME(o, f) ((o) = Qnil) -#endif - -/* Translate console modifiers to emacs modifiers. */ -static int -nt_kbd_mods_to_emacs (DWORD mods) -{ - return ((mods & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) ? - meta_modifier : 0) | - ((mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) ? - ctrl_modifier : 0) | - ((mods & (SHIFT_PRESSED | CAPSLOCK_ON)) ? - shift_modifier : 0); -} - -/* Map virtual key codes into: - -1 - Ignore this key - -2 - ASCII char - Other - Map non-ASCII keys into X keysyms so that they are looked up - correctly in keyboard.c - - Return, escape and tab are mapped to ASCII rather than coming back - as non-ASCII to be more compatible with old-style keyboard support. */ - -static int map_virt_key[256] = -{ - -1, - -1, /* VK_LBUTTON */ - -1, /* VK_RBUTTON */ - 0x69, /* VK_CANCEL */ - -1, /* VK_MBUTTON */ - -1, -1, -1, - 8, /* VK_BACK */ - -2, /* VK_TAB */ - -1, -1, - 11, /* VK_CLEAR */ - -2, /* VK_RETURN */ - -1, -1, - -1, /* VK_SHIFT */ - -1, /* VK_CONTROL */ - -1, /* VK_MENU */ - 0x13, /* VK_PAUSE */ - -1, /* VK_CAPITAL */ - -1, -1, -1, -1, -1, -1, - -2, /* VK_ESCAPE */ - -1, -1, -1, -1, - -2, /* VK_SPACE */ - 0x55, /* VK_PRIOR */ - 0x56, /* VK_NEXT */ - 0x57, /* VK_END */ - 0x50, /* VK_HOME */ - 0x51, /* VK_LEFT */ - 0x52, /* VK_UP */ - 0x53, /* VK_RIGHT */ - 0x54, /* VK_DOWN */ - 0x60, /* VK_SELECT */ - 0x61, /* VK_PRINT */ - 0x62, /* VK_EXECUTE */ - -1, /* VK_SNAPSHOT */ - 0x63, /* VK_INSERT */ - 0xff, /* VK_DELETE */ - 0x6a, /* VK_HELP */ - -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, /* 0 - 9 */ - -1, -1, -1, -1, -1, -1, -1, - -2, -2, -2, -2, -2, -2, -2, -2, /* A - Z */ - -2, -2, -2, -2, -2, -2, -2, -2, - -2, -2, -2, -2, -2, -2, -2, -2, - -2, -2, - -1, -1, -1, -1, -1, - 0xb0, /* VK_NUMPAD0 */ - 0xb1, /* VK_NUMPAD1 */ - 0xb2, /* VK_NUMPAD2 */ - 0xb3, /* VK_NUMPAD3 */ - 0xb4, /* VK_NUMPAD4 */ - 0xb5, /* VK_NUMPAD5 */ - 0xb6, /* VK_NUMPAD6 */ - 0xb7, /* VK_NUMPAD7 */ - 0xb8, /* VK_NUMPAD8 */ - 0xb9, /* VK_NUMPAD9 */ - 0xaa, /* VK_MULTIPLY */ - 0xab, /* VK_ADD */ - 0xac, /* VK_SEPARATOR */ - 0xad, /* VK_SUBTRACT */ - 0xae, /* VK_DECIMAL */ - 0xaf, /* VK_DIVIDE */ - 0xbe, /* VK_F1 */ - 0xbf, /* VK_F2 */ - 0xc0, /* VK_F3 */ - 0xc1, /* VK_F4 */ - 0xc2, /* VK_F5 */ - 0xc3, /* VK_F6 */ - 0xc4, /* VK_F7 */ - 0xc5, /* VK_F8 */ - 0xc6, /* VK_F9 */ - 0xc7, /* VK_F10 */ - 0xc8, /* VK_F11 */ - 0xc9, /* VK_F12 */ - 0xca, /* VK_F13 */ - 0xcb, /* VK_F14 */ - 0xcc, /* VK_F15 */ - 0xcd, /* VK_F16 */ - 0xce, /* VK_F17 */ - 0xcf, /* VK_F18 */ - 0xd0, /* VK_F19 */ - 0xd1, /* VK_F20 */ - 0xd2, /* VK_F21 */ - 0xd3, /* VK_F22 */ - 0xd4, /* VK_F23 */ - 0xd5, /* VK_F24 */ - -1, -1, -1, -1, -1, -1, -1, -1, - 0x7f, /* VK_NUMLOCK */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x9f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xaf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb9 */ - -2, /* ; */ - -2, /* = */ - -2, /* , */ - -2, /* \ */ - -2, /* . */ - -2, /* / */ - -2, /* ` */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xcf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xda */ - -2, /* [ */ - -2, /* - */ - -2, /* ] */ - -2, /* ' */ - -1, /* 0xdf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xef */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xff */ -}; - -static int -key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev) -{ - int map; - - /* Skip key-up events. */ - if (event->bKeyDown == FALSE) - return 0; - - if (event->wVirtualKeyCode > 0xff) - { - printf ("Unknown key code %d\n", event->wVirtualKeyCode); - return 0; - } - - /* BUGBUG - Ignores the repeat count - It's questionable whether we want to obey the repeat count anyway - since keys usually aren't repeated unless key events back up in - the queue. If they're backing up then we don't generally want - to honor them later since that leads to significant slop in - cursor motion when the system is under heavy load. */ - - map = map_virt_key[event->wVirtualKeyCode]; - if (map == -1) - { - return 0; - } - else if (map == -2) - { - /* ASCII */ - emacs_ev->kind = ascii_keystroke; - XSET (emacs_ev->code, Lisp_Int, event->uChar.AsciiChar); - } - else - { - /* non-ASCII */ - emacs_ev->kind = non_ascii_keystroke; - /* - * make_lispy_event () now requires non-ascii codes to have - * the full X keysym values (2nd byte is 0xff). add it on. - */ - map |= 0xff00; - XSET (emacs_ev->code, Lisp_Int, map); - } - SET_FRAME (emacs_ev->frame_or_window, get_frame ()); - emacs_ev->modifiers = nt_kbd_mods_to_emacs (event->dwControlKeyState); - emacs_ev->timestamp = GetTickCount (); - return 1; -} - -/* Mouse position hook. */ -void -win32_mouse_position (FRAME_PTR *f, - Lisp_Object *bar_window, - enum scroll_bar_part *part, - Lisp_Object *x, - Lisp_Object *y, - unsigned long *time) -{ - BLOCK_INPUT; - - *f = get_frame (); - *bar_window = Qnil; - *part = 0; - mouse_moved = 0; - - *x = movement_pos.X; - *y = movement_pos.Y; - *time = movement_time; - - UNBLOCK_INPUT; -} - -/* Remember mouse motion and notify emacs. */ -static void -mouse_moved_to (int x, int y) -{ - /* If we're in the same place, ignore it */ - if (x != movement_pos.X || y != movement_pos.Y) - { - mouse_moved = 1; - movement_pos.X = x; - movement_pos.Y = y; - movement_time = GetTickCount (); - } -} - -/* Consoles return button bits in a strange order: - least significant - Leftmost button - next - Rightmost button - next - Leftmost+1 - next - Leftmost+2... - - Assume emacs likes three button mice, so - Left == 0 - Middle == 1 - Right == 2 - Others increase from there. */ - -static int emacs_button_translation[NUM_MOUSE_BUTTONS] = -{ - 0, 2, 1, 3, 4, -}; - -static int -do_mouse_event (MOUSE_EVENT_RECORD *event, - struct input_event *emacs_ev) -{ - static DWORD button_state = 0; - DWORD but_change, mask; - int i; - - if (event->dwEventFlags == MOUSE_MOVED) - { - /* For movement events we just note that the mouse has moved - so that emacs will generate drag events. */ - mouse_moved_to (event->dwMousePosition.X, event->dwMousePosition.Y); - return 0; - } - - /* It looks like the console code sends us a mouse event with - dwButtonState == 0 when a window is activated. Ignore this case. */ - if (event->dwButtonState == button_state) - return 0; - - emacs_ev->kind = mouse_click; - - /* Find out what button has changed state since the last button event. */ - but_change = button_state ^ event->dwButtonState; - mask = 1; - for (i = 0; i < NUM_MOUSE_BUTTONS; i++, mask <<= 1) - if (but_change & mask) - { - XSET (emacs_ev->code, Lisp_Int, emacs_button_translation[i]); - break; - } - - /* If the changed button is out of emacs' range (highly unlikely) - ignore this event. */ - if (i == NUM_MOUSE_BUTTONS) - return 0; - - button_state = event->dwButtonState; - emacs_ev->timestamp = GetTickCount (); - emacs_ev->modifiers = nt_kbd_mods_to_emacs (event->dwControlKeyState) | - ((event->dwButtonState & mask) ? down_modifier : up_modifier); - - XFASTINT (emacs_ev->x) = event->dwMousePosition.X; - XFASTINT (emacs_ev->y) = event->dwMousePosition.Y; - SET_FRAME (emacs_ev->frame_or_window, get_frame ()); - - return 1; -} - -static void -resize_event (WINDOW_BUFFER_SIZE_RECORD *event) -{ - FRAME_PTR f = get_frame (); - - change_frame_size (f, event->dwSize.Y, event->dwSize.X, 0, 1); - SET_FRAME_GARBAGED (f); -} - -int -win32_read_socket (int sd, struct input_event *bufp, int numchars, - int waitp, int expected) -{ - BOOL no_events = TRUE; - int nev, ret = 0, add; - - if (interrupt_input_blocked) - { - interrupt_input_pending = 1; - return -1; - } - - interrupt_input_pending = 0; - BLOCK_INPUT; - - for (;;) - { - nev = fill_queue (waitp != 0); - if (nev <= 0) - { - /* If nev == -1, there was some kind of error - If nev == 0 then waitp must be zero and no events were available - so return. */ - UNBLOCK_INPUT; - return nev; - } - - while (nev > 0 && numchars > 0) - { - switch (queue_ptr->EventType) - { - case KEY_EVENT: - add = key_event (&queue_ptr->Event.KeyEvent, bufp); - bufp += add; - ret += add; - numchars -= add; - break; - - case MOUSE_EVENT: - add = do_mouse_event (&queue_ptr->Event.MouseEvent, bufp); - bufp += add; - ret += add; - numchars -= add; - break; - - case WINDOW_BUFFER_SIZE_EVENT: - resize_event (&queue_ptr->Event.WindowBufferSizeEvent); - break; - - case MENU_EVENT: - case FOCUS_EVENT: - /* Internal event types, ignored. */ - break; - } - - queue_ptr++; - nev--; - } - - if (ret > 0 || expected == 0) - break; - } - - UNBLOCK_INPUT; - return ret; -} +/* Input event support for Emacs on the Microsoft W32 API. + Copyright (C) 1992, 1993, 1995, 2001, 2002, 2003, 2004, + 2005, 2006, 2007 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3, or (at your option) +any later version. + +GNU Emacs 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. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. + + Drew Bliss 01-Oct-93 + Adapted from ntkbd.c by Tim Fleehart +*/ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifndef MOUSE_MOVED +#define MOUSE_MOVED 1 +#endif + +#include "lisp.h" +#include "keyboard.h" +#include "frame.h" +#include "blockinput.h" +#include "termhooks.h" +#include "w32heap.h" +#include "w32term.h" + +/* stdin, from ntterm */ +extern HANDLE keyboard_handle; + +/* Info for last mouse motion */ +static COORD movement_pos; +static DWORD movement_time; + +/* from keyboard.c */ +extern void reinvoke_input_signal (void); + +/* from dispnew.c */ +extern int change_frame_size (FRAME_PTR, int, int, int, int); + +/* from w32console.c */ +extern int w32_use_full_screen_buffer; + +/* from w32fns.c */ +extern Lisp_Object Vw32_alt_is_meta; +extern unsigned int map_keypad_keys (unsigned int, unsigned int); + +/* from w32term */ +extern Lisp_Object Vw32_capslock_is_shiftlock; +extern Lisp_Object Vw32_enable_caps_lock; +extern Lisp_Object Vw32_enable_num_lock; +extern Lisp_Object Vw32_recognize_altgr; +extern Lisp_Object Vw32_pass_lwindow_to_system; +extern Lisp_Object Vw32_pass_rwindow_to_system; +extern Lisp_Object Vw32_phantom_key_code; +extern Lisp_Object Vw32_lwindow_modifier; +extern Lisp_Object Vw32_rwindow_modifier; +extern Lisp_Object Vw32_apps_modifier; +extern Lisp_Object Vw32_scroll_lock_modifier; +extern unsigned int w32_key_to_modifier (int key); + +/* Event queue */ +#define EVENT_QUEUE_SIZE 50 +static INPUT_RECORD event_queue[EVENT_QUEUE_SIZE]; +static INPUT_RECORD *queue_ptr = event_queue, *queue_end = event_queue; + +static int +fill_queue (BOOL block) +{ + BOOL rc; + DWORD events_waiting; + + if (queue_ptr < queue_end) + return queue_end-queue_ptr; + + if (!block) + { + /* Check to see if there are some events to read before we try + because we can't block. */ + if (!GetNumberOfConsoleInputEvents (keyboard_handle, &events_waiting)) + return -1; + if (events_waiting == 0) + return 0; + } + + rc = ReadConsoleInput (keyboard_handle, event_queue, EVENT_QUEUE_SIZE, + &events_waiting); + if (!rc) + return -1; + queue_ptr = event_queue; + queue_end = event_queue + events_waiting; + return (int) events_waiting; +} + +/* In a generic, multi-frame world this should take a console handle + and return the frame for it + + Right now, there's only one frame so return it. */ +static FRAME_PTR +get_frame (void) +{ + return SELECTED_FRAME (); +} + +/* Translate console modifiers to emacs modifiers. + German keyboard support (Kai Morgan Zeise 2/18/95). */ +int +w32_kbd_mods_to_emacs (DWORD mods, WORD key) +{ + int retval = 0; + + /* If we recognize right-alt and left-ctrl as AltGr, and it has been + pressed, first remove those modifiers. */ + if (!NILP (Vw32_recognize_altgr) + && (mods & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)) + == (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)) + mods &= ~ (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED); + + if (mods & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) + retval = ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier); + + if (mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) + { + retval |= ctrl_modifier; + if ((mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) + == (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) + retval |= meta_modifier; + } + + if (mods & LEFT_WIN_PRESSED) + retval |= w32_key_to_modifier (VK_LWIN); + if (mods & RIGHT_WIN_PRESSED) + retval |= w32_key_to_modifier (VK_RWIN); + if (mods & APPS_PRESSED) + retval |= w32_key_to_modifier (VK_APPS); + if (mods & SCROLLLOCK_ON) + retval |= w32_key_to_modifier (VK_SCROLL); + + /* Just in case someone wanted the original behaviour, make it + optional by setting w32-capslock-is-shiftlock to t. */ + if (NILP (Vw32_capslock_is_shiftlock) + /* Keys that should _not_ be affected by CapsLock. */ + && ( (key == VK_BACK) + || (key == VK_TAB) + || (key == VK_CLEAR) + || (key == VK_RETURN) + || (key == VK_ESCAPE) + || ((key >= VK_SPACE) && (key <= VK_HELP)) + || ((key >= VK_NUMPAD0) && (key <= VK_F24)) + || ((key >= VK_NUMPAD_CLEAR) && (key <= VK_NUMPAD_DELETE)) + )) + { + /* Only consider shift state. */ + if ((mods & SHIFT_PRESSED) != 0) + retval |= shift_modifier; + } + else + { + /* Ignore CapsLock state if not enabled. */ + if (NILP (Vw32_enable_caps_lock)) + mods &= ~CAPSLOCK_ON; + if ((mods & (SHIFT_PRESSED | CAPSLOCK_ON)) != 0) + retval |= shift_modifier; + } + + return retval; +} + +#if 0 +/* Return nonzero if the virtual key is a dead key. */ +static int +is_dead_key (int wparam) +{ + unsigned int code = MapVirtualKey (wparam, 2); + + /* Windows 95 returns 0x8000, NT returns 0x80000000. */ + return (code & 0x80008000) ? 1 : 0; +} +#endif + +/* The return code indicates key code size. */ +int +w32_kbd_patch_key (KEY_EVENT_RECORD *event) +{ + unsigned int key_code = event->wVirtualKeyCode; + unsigned int mods = event->dwControlKeyState; + BYTE keystate[256]; + static BYTE ansi_code[4]; + static int isdead = 0; + + if (isdead == 2) + { + event->uChar.AsciiChar = ansi_code[2]; + isdead = 0; + return 1; + } + if (event->uChar.AsciiChar != 0) + return 1; + + memset (keystate, 0, sizeof (keystate)); + keystate[key_code] = 0x80; + if (mods & SHIFT_PRESSED) + keystate[VK_SHIFT] = 0x80; + if (mods & CAPSLOCK_ON) + keystate[VK_CAPITAL] = 1; + /* If we recognize right-alt and left-ctrl as AltGr, set the key + states accordingly before invoking ToAscii. */ + if (!NILP (Vw32_recognize_altgr) + && (mods & LEFT_CTRL_PRESSED) && (mods & RIGHT_ALT_PRESSED)) + { + keystate[VK_CONTROL] = 0x80; + keystate[VK_LCONTROL] = 0x80; + keystate[VK_MENU] = 0x80; + keystate[VK_RMENU] = 0x80; + } + +#if 0 + /* Because of an OS bug, ToAscii corrupts the stack when called to + convert a dead key in console mode on NT4. Unfortunately, trying + to check for dead keys using MapVirtualKey doesn't work either - + these functions apparently use internal information about keyboard + layout which doesn't get properly updated in console programs when + changing layout (though apparently it gets partly updated, + otherwise ToAscii wouldn't crash). */ + if (is_dead_key (event->wVirtualKeyCode)) + return 0; +#endif + + /* On NT, call ToUnicode instead and then convert to the current + locale's default codepage. */ + if (os_subtype == OS_NT) + { + WCHAR buf[128]; + + isdead = ToUnicode (event->wVirtualKeyCode, event->wVirtualScanCode, + keystate, buf, 128, 0); + if (isdead > 0) + { + char cp[20]; + int cpId; + + GetLocaleInfo (GetThreadLocale (), + LOCALE_IDEFAULTANSICODEPAGE, cp, 20); + cpId = atoi (cp); + isdead = WideCharToMultiByte (cpId, 0, buf, isdead, + ansi_code, 4, NULL, NULL); + } + else + isdead = 0; + } + else + { + isdead = ToAscii (event->wVirtualKeyCode, event->wVirtualScanCode, + keystate, (LPWORD) ansi_code, 0); + } + + if (isdead == 0) + return 0; + event->uChar.AsciiChar = ansi_code[0]; + return isdead; +} + + +extern char *lispy_function_keys[]; + +static int faked_key = 0; + +/* return code -1 means that event_queue_ptr won't be incremented. + In other word, this event makes two key codes. (by himi) */ +int +key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead) +{ + static int mod_key_state = 0; + int wParam; + + *isdead = 0; + + /* Skip key-up events. */ + if (!event->bKeyDown) + { + switch (event->wVirtualKeyCode) + { + case VK_LWIN: + mod_key_state &= ~LEFT_WIN_PRESSED; + break; + case VK_RWIN: + mod_key_state &= ~RIGHT_WIN_PRESSED; + break; + case VK_APPS: + mod_key_state &= ~APPS_PRESSED; + break; + } + return 0; + } + + /* Ignore keystrokes we fake ourself; see below. */ + if (faked_key == event->wVirtualKeyCode) + { + faked_key = 0; + return 0; + } + + /* To make it easier to debug this code, ignore modifier keys! */ + switch (event->wVirtualKeyCode) + { + case VK_LWIN: + 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. */ + if ((mod_key_state & LEFT_WIN_PRESSED) == 0) + { + if (NUMBERP (Vw32_phantom_key_code)) + faked_key = XUINT (Vw32_phantom_key_code) & 255; + else + faked_key = VK_SPACE; + keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0); + } + } + mod_key_state |= LEFT_WIN_PRESSED; + if (!NILP (Vw32_lwindow_modifier)) + return 0; + break; + case VK_RWIN: + if (NILP (Vw32_pass_rwindow_to_system)) + { + if ((mod_key_state & RIGHT_WIN_PRESSED) == 0) + { + if (NUMBERP (Vw32_phantom_key_code)) + faked_key = XUINT (Vw32_phantom_key_code) & 255; + else + faked_key = VK_SPACE; + keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0); + } + } + mod_key_state |= RIGHT_WIN_PRESSED; + if (!NILP (Vw32_rwindow_modifier)) + return 0; + break; + case VK_APPS: + mod_key_state |= APPS_PRESSED; + if (!NILP (Vw32_apps_modifier)) + return 0; + break; + case VK_CAPITAL: + /* Decide whether to treat as modifier or function key. */ + if (NILP (Vw32_enable_caps_lock)) + goto disable_lock_key; + return 0; + case VK_NUMLOCK: + /* Decide whether to treat as modifier or function key. */ + if (NILP (Vw32_enable_num_lock)) + goto disable_lock_key; + return 0; + case VK_SCROLL: + /* Decide whether to treat as modifier or function key. */ + if (NILP (Vw32_scroll_lock_modifier)) + goto disable_lock_key; + return 0; + disable_lock_key: + /* Ensure the appropriate lock key state is off (and the + indicator light as well). */ + wParam = event->wVirtualKeyCode; + if (GetAsyncKeyState (wParam) & 0x8000) + { + /* Fake another press of the relevant key. Apparently, this + really is the only way to turn off the indicator. */ + faked_key = wParam; + keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0), + KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); + keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0), + KEYEVENTF_EXTENDEDKEY | 0, 0); + keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0), + KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); + } + break; + case VK_MENU: + case VK_CONTROL: + case VK_SHIFT: + return 0; + case VK_CANCEL: + /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL, + which is confusing for purposes of key binding; convert + VK_CANCEL events into VK_PAUSE events. */ + event->wVirtualKeyCode = 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.) */ + if (NILP (Vw32_enable_num_lock) + && (event->dwControlKeyState + & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0) + event->wVirtualKeyCode = VK_NUMLOCK; + break; + } + + /* Recognize state of Windows and Apps keys. */ + event->dwControlKeyState |= mod_key_state; + + /* Distinguish numeric keypad keys from extended keys. */ + event->wVirtualKeyCode = + map_keypad_keys (event->wVirtualKeyCode, + (event->dwControlKeyState & ENHANCED_KEY)); + + if (lispy_function_keys[event->wVirtualKeyCode] == 0) + { + emacs_ev->kind = ASCII_KEYSTROKE_EVENT; + + if (!NILP (Vw32_recognize_altgr) + && (event->dwControlKeyState & LEFT_CTRL_PRESSED) + && (event->dwControlKeyState & RIGHT_ALT_PRESSED)) + { + /* Don't try to interpret AltGr key chords; ToAscii seems not + to process them correctly. */ + } + /* Handle key chords including any modifiers other than shift + directly, in order to preserve as much modifier information as + possible. */ + else if (event->dwControlKeyState + & ( RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED + | RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED + | (!NILP (Vw32_lwindow_modifier) ? LEFT_WIN_PRESSED : 0) + | (!NILP (Vw32_rwindow_modifier) ? RIGHT_WIN_PRESSED : 0) + | (!NILP (Vw32_apps_modifier) ? APPS_PRESSED : 0) + | (!NILP (Vw32_scroll_lock_modifier) ? SCROLLLOCK_ON : 0))) + { + /* Don't translate modified alphabetic keystrokes, so the user + doesn't need to constantly switch layout to type control or + meta keystrokes when the normal layout translates + alphabetic characters to non-ascii characters. */ + if ('A' <= event->wVirtualKeyCode && event->wVirtualKeyCode <= 'Z') + { + event->uChar.AsciiChar = event->wVirtualKeyCode; + if ((event->dwControlKeyState & SHIFT_PRESSED) == 0) + event->uChar.AsciiChar += ('a' - 'A'); + } + /* Try to handle unrecognized keystrokes by determining the + base character (ie. translating the base key plus shift + modifier). */ + else if (event->uChar.AsciiChar == 0) + w32_kbd_patch_key (event); + } + if (event->uChar.AsciiChar == 0) + return 0; + emacs_ev->code = event->uChar.AsciiChar; + } + else + { + emacs_ev->kind = NON_ASCII_KEYSTROKE_EVENT; + emacs_ev->code = event->wVirtualKeyCode; + } + + XSETFRAME (emacs_ev->frame_or_window, get_frame ()); + emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState, + event->wVirtualKeyCode); + emacs_ev->timestamp = GetTickCount (); + return 1; +} + +int +w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state) +{ + int cur_state = (GetKeyState (vk_code) & 1); + + if (NILP (new_state) + || (NUMBERP (new_state) + && ((XUINT (new_state)) & 1) != cur_state)) + { + faked_key = vk_code; + + keybd_event ((BYTE) vk_code, + (BYTE) MapVirtualKey (vk_code, 0), + KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); + keybd_event ((BYTE) vk_code, + (BYTE) MapVirtualKey (vk_code, 0), + KEYEVENTF_EXTENDEDKEY | 0, 0); + keybd_event ((BYTE) vk_code, + (BYTE) MapVirtualKey (vk_code, 0), + KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); + cur_state = !cur_state; + } + + return cur_state; +} + +/* Mouse position hook. */ +void +w32_console_mouse_position (FRAME_PTR *f, + int insist, + Lisp_Object *bar_window, + enum scroll_bar_part *part, + Lisp_Object *x, + Lisp_Object *y, + unsigned long *time) +{ + BLOCK_INPUT; + + insist = insist; + + *f = get_frame (); + *bar_window = Qnil; + *part = 0; + SELECTED_FRAME ()->mouse_moved = 0; + + XSETINT(*x, movement_pos.X); + XSETINT(*y, movement_pos.Y); + *time = movement_time; + + UNBLOCK_INPUT; +} + +/* Remember mouse motion and notify emacs. */ +static void +mouse_moved_to (int x, int y) +{ + /* If we're in the same place, ignore it */ + if (x != movement_pos.X || y != movement_pos.Y) + { + SELECTED_FRAME ()->mouse_moved = 1; + movement_pos.X = x; + movement_pos.Y = y; + movement_time = GetTickCount (); + } +} + +/* Consoles return button bits in a strange order: + least significant - Leftmost button + next - Rightmost button + next - Leftmost+1 + next - Leftmost+2... + + Assume emacs likes three button mice, so + Left == 0 + Middle == 1 + Right == 2 + Others increase from there. */ + +#define NUM_TRANSLATED_MOUSE_BUTTONS 3 +static int emacs_button_translation[NUM_TRANSLATED_MOUSE_BUTTONS] = +{ + 0, 2, 1 +}; + +static int +do_mouse_event (MOUSE_EVENT_RECORD *event, + struct input_event *emacs_ev) +{ + static DWORD button_state = 0; + DWORD but_change, mask; + int i; + + if (event->dwEventFlags == MOUSE_MOVED) + { + /* For movement events we just note that the mouse has moved + so that emacs will generate drag events. */ + mouse_moved_to (event->dwMousePosition.X, event->dwMousePosition.Y); + return 0; + } + + /* It looks like the console code sends us a mouse event with + dwButtonState == 0 when a window is activated. Ignore this case. */ + if (event->dwButtonState == button_state) + return 0; + + emacs_ev->kind = MOUSE_CLICK_EVENT; + + /* Find out what button has changed state since the last button event. */ + but_change = button_state ^ event->dwButtonState; + mask = 1; + for (i = 0; mask; i++, mask <<= 1) + if (but_change & mask) + { + if (i < NUM_TRANSLATED_MOUSE_BUTTONS) + emacs_ev->code = emacs_button_translation[i]; + else + emacs_ev->code = i; + break; + } + + button_state = event->dwButtonState; + emacs_ev->timestamp = GetTickCount (); + emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState, 0) | + ((event->dwButtonState & mask) ? down_modifier : up_modifier); + + XSETFASTINT (emacs_ev->x, event->dwMousePosition.X); + XSETFASTINT (emacs_ev->y, event->dwMousePosition.Y); +/* for Mule 2.2 (Based on Emacs 19.28 */ +#ifdef MULE + XSET (emacs_ev->frame_or_window, Lisp_Frame, get_frame ()); +#else + XSETFRAME (emacs_ev->frame_or_window, get_frame ()); +#endif + + return 1; +} + +static void +resize_event (WINDOW_BUFFER_SIZE_RECORD *event) +{ + FRAME_PTR f = get_frame (); + + change_frame_size (f, event->dwSize.Y, event->dwSize.X, 0, 1); + SET_FRAME_GARBAGED (f); +} + +static void +maybe_generate_resize_event () +{ + CONSOLE_SCREEN_BUFFER_INFO info; + FRAME_PTR f = get_frame (); + + GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info); + + /* It is okay to call this unconditionally, since it will do nothing + if the size hasn't actually changed. */ + change_frame_size (f, + 1 + info.srWindow.Bottom - info.srWindow.Top, + 1 + info.srWindow.Right - info.srWindow.Left, + 0, 0); +} + +int +w32_console_read_socket (int sd, int expected, struct input_event *hold_quit) +{ + BOOL no_events = TRUE; + int nev, ret = 0, add; + int isdead; + + if (interrupt_input_blocked) + { + interrupt_input_pending = 1; + return -1; + } + + interrupt_input_pending = 0; + BLOCK_INPUT; + + for (;;) + { + nev = fill_queue (0); + if (nev <= 0) + { + /* If nev == -1, there was some kind of error + If nev == 0 then waitp must be zero and no events were available + so return. */ + UNBLOCK_INPUT; + return nev; + } + + while (nev > 0) + { + struct input_event inev; + + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; + + switch (queue_ptr->EventType) + { + case KEY_EVENT: + add = key_event (&queue_ptr->Event.KeyEvent, &inev, &isdead); + if (add == -1) /* 95.7.25 by himi */ + { + queue_ptr--; + add = 1; + } + if (add) + kbd_buffer_store_event_hold (&inev, hold_quit); + break; + + case MOUSE_EVENT: + add = do_mouse_event (&queue_ptr->Event.MouseEvent, &inev); + if (add) + kbd_buffer_store_event_hold (&inev, hold_quit); + break; + + case WINDOW_BUFFER_SIZE_EVENT: + if (w32_use_full_screen_buffer) + resize_event (&queue_ptr->Event.WindowBufferSizeEvent); + break; + + case MENU_EVENT: + case FOCUS_EVENT: + /* Internal event types, ignored. */ + break; + } + + queue_ptr++; + nev--; + } + + if (ret > 0 || expected == 0) + break; + } + + /* We don't get told about changes in the window size (only the buffer + size, which we no longer care about), so we have to check it + periodically. */ + if (!w32_use_full_screen_buffer) + maybe_generate_resize_event (); + + UNBLOCK_INPUT; + return ret; +} + +/* arch-tag: 0bcb39b7-d085-4b85-9070-6750e8c03047 + (do not change this comment) */