Mercurial > emacs
diff src/w32inevt.c @ 9907:2e5a14f7c44e
Initial revision
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Mon, 14 Nov 1994 01:32:24 +0000 |
parents | |
children | 10fc4417831d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/w32inevt.c Mon Nov 14 01:32:24 1994 +0000 @@ -0,0 +1,459 @@ +/* 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 <stdlib.h> +#include <stdio.h> +#include <windows.h> + +#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; +}