mc/nt/key.nt.c
1998-02-27 04:54:42 +00:00

470 lines
11 KiB
C

/* Keyboard support routines.
for Windows NT system.
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 of the License, 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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Bugs:
Have trouble with non-US keyboards, "Alt-gr"+keys (API tells CTRL-ALT is pressed)
*/
#ifndef _OS_NT
#error This file is for Win32 systems.
#else
#include <windows.h>
/* Linux and Win32 names are the same, but values are different */
const int win_shift_pressed = SHIFT_PRESSED;
#undef SHIFT_PRESSED
#include <config.h>
#include <stdio.h>
#include "mouse.h"
#include "global.h"
#include "main.h"
#include "key.h"
#include "../vfs/vfs.h"
#include "tty.h"
#include "util.debug.h"
/* Global variables */
int old_esc_mode = 0;
HANDLE hConsoleInput;
DWORD dwSaved_ControlState;
Gpm_Event evSaved_Event;
/* Unused variables */
int double_click_speed; /* they are here to keep linker happy */
int mou_auto_repeat;
int use_8th_bit_as_meta = 0;
/* Prototypes */
static int EscapeKey (char* seq);
static int ControlKey (char* seq);
static int AltKey (char *seq);
static int VKtoCurses (int vkcode);
static int correct_key_code (int c);
/* Static Tables */
struct {
int key_code;
int vkcode;
} key_table [] = {
{ KEY_F(1), VK_F1 },
{ KEY_F(2), VK_F2 },
{ KEY_F(3), VK_F3 },
{ KEY_F(4), VK_F4 },
{ KEY_F(5), VK_F5 },
{ KEY_F(6), VK_F6 },
{ KEY_F(7), VK_F7 },
{ KEY_F(8), VK_F8 },
{ KEY_F(9), VK_F9 },
{ KEY_F(10), VK_F10 },
{ KEY_F(11), VK_F11 },
{ KEY_F(12), VK_F12 },
{ KEY_F(13), VK_F13 },
{ KEY_F(14), VK_F14 },
{ KEY_F(15), VK_F15 },
{ KEY_F(16), VK_F16 },
{ KEY_F(17), VK_F17 },
{ KEY_F(18), VK_F18 },
{ KEY_F(19), VK_F19 },
{ KEY_F(20), VK_F20 },
{ KEY_IC, VK_INSERT },
{ KEY_DC, VK_DELETE },
{ KEY_BACKSPACE, VK_BACK },
{ '\t', VK_TAB },
// { KEY_ENTER, VK_RETURN },
// { KEY_ENTER, VK_EXECUTE },
{ '\n', VK_RETURN },
{ '\n', VK_EXECUTE },
{ ' ', VK_SPACE },
// { KEY_PRINT, VK_SNAPSHOT },
{ KEY_PPAGE, VK_PRIOR }, // Movement keys
{ KEY_NPAGE, VK_NEXT },
{ KEY_LEFT, VK_LEFT },
{ KEY_RIGHT, VK_RIGHT },
{ KEY_UP, VK_UP },
{ KEY_DOWN, VK_DOWN },
{ KEY_HOME, VK_HOME },
{ KEY_END, VK_END },
{ KEY_KP_MULTIPLY, VK_MULTIPLY }, // Numeric pad
{ KEY_KP_ADD, VK_ADD },
{ KEY_KP_SUBTRACT, VK_SUBTRACT },
/* Control key codes */
{ 0, VK_CONTROL }, /* Control */
{ 0, VK_MENU }, /* Alt */
// { 0, VK_ESCAPE }, /* ESC */
{ ESC_CHAR, VK_ESCAPE }, /* ESC */
/* Key codes to ignore */
{ -1, VK_SHIFT }, /* Shift when released generates a key event */
{ -1, VK_CAPITAL }, /* Caps-lock */
#if WINVER >= 0x400 /* new Chicago key codes (not in 3.x headers) */
{ -1, VK_APPS }, /* "Application key" */
{ -1, VK_LWIN }, /* Left "Windows" key */
{ -1, VK_RWIN }, /* Right "Windows" key */
#endif
{ 0, 0}
};
/* Special handlers for control key codes
Note that howmany must be less than seq_buffer len
*/
struct {
int vkcode;
int (*func_hdlr)(char *);
int howmany;
} key_control_table[] = {
{ VK_ESCAPE, EscapeKey, 1 },
{ VK_CONTROL, ControlKey, 1 },
{ VK_MENU, AltKey, 1 },
{ 0, NULL, 0},
};
/* init_key - Called in main.c to initialize ourselves
Get handle to console input
*/
void init_key (void)
{
win32APICALL_HANDLE (hConsoleInput, /* = */ GetStdHandle (STD_INPUT_HANDLE));
}
/* The maximum sequence length (32 + null terminator) */
static int seq_buffer[33];
static int *seq_append = 0;
static int push_char (int c)
{
if (!seq_append)
seq_append = seq_buffer;
if (seq_append == &(seq_buffer [sizeof (seq_buffer)-2]))
return 0;
*(seq_append++) = c;
*seq_append = 0;
return 1;
}
void define_sequence (int code, char* vkcode, int action)
{
}
static int *pending_keys;
int get_key_code (int no_delay)
{
INPUT_RECORD ir; /* Input record */
DWORD dw; /* number of records actually read */
int ch, vkcode, j;
if (no_delay) {
/* Check if any input pending, otherwise return */
nodelay (stdscr, TRUE);
win32APICALL(PeekConsoleInput(hConsoleInput, &ir, 1, &dw));
if (!dw)
return 0;
}
pend_send:
if (pending_keys) {
int d = *pending_keys++;
if (!*pending_keys){
pending_keys = 0;
seq_append = 0;
}
return correct_key_code (d);
}
do {
win32APICALL(ReadConsoleInput(hConsoleInput, &ir, 1, &dw));
switch (ir.EventType) {
case KEY_EVENT:
if (!ir.Event.KeyEvent.bKeyDown) /* Process key just once: when pressed */
break;
vkcode = ir.Event.KeyEvent.wVirtualKeyCode;
ch = ir.Event.KeyEvent.uChar.AsciiChar;
dwSaved_ControlState = ir.Event.KeyEvent.dwControlKeyState;
j = VKtoCurses(vkcode);
return correct_key_code (j ? j : ch);
case MOUSE_EVENT:
// Save event as a GPM-like event
evSaved_Event.x = ir.Event.MouseEvent.dwMousePosition.X;
evSaved_Event.y = ir.Event.MouseEvent.dwMousePosition.Y+1;
evSaved_Event.buttons = ir.Event.MouseEvent.dwButtonState;
switch (ir.Event.MouseEvent.dwEventFlags) {
case 0:
evSaved_Event.type = GPM_DOWN | GPM_SINGLE;
break;
case MOUSE_MOVED:
evSaved_Event.type = GPM_MOVE;
break;
case DOUBLE_CLICK:
evSaved_Event.type = GPM_DOWN | GPM_DOUBLE;
break;
};
return 0;
}
} while (!no_delay);
return 0;
}
static int VKtoCurses (int a_vkc)
{
int i;
// Replace key code with that in table
for (i=0; key_table[i].vkcode != 0 || key_table[i].key_code != 0; i++)
if (a_vkc == key_table[i].vkcode) {
if (key_table[i].key_code)
return correct_key_code (key_table[i].key_code);
}
return 0;
}
static int correct_key_code (int c)
{
static char AltGrPressed = 0;
/* Ugly hacks */
/* Make Ctrl-Tab same as reserved Alt-Tab */
if (c == '\t' && ctrl_pressed())
c = ALT('\t');
/* FIXME: Ignore Left-Ctrl+Right-Alt combination in non-US keyboards,
as it means Alt-Gr+key */
if (dwSaved_ControlState & RIGHT_ALT_PRESSED &&
dwSaved_ControlState & LEFT_CTRL_PRESSED)
return c;
/* No, AltGR Key is the combination with ENHANCED_KEY
and RIGHT_ALT_PRESSED .ado */
if (dwSaved_ControlState & RIGHT_ALT_PRESSED &&
dwSaved_ControlState & ENHANCED_KEY) {
/* AltGr Key pressed */
AltGrPressed = 1;
return c;
}
/* Other hacks */
/* Check Control State */
if (ctrl_pressed())
c = XCTRL(c);
if (!AltGrPressed &&
(dwSaved_ControlState & RIGHT_ALT_PRESSED ||
dwSaved_ControlState & LEFT_ALT_PRESSED))
c = ALT(c);
else
AltGrPressed = 0;
switch (c) {
case KEY_KP_ADD:
c = alternate_plus_minus ? ALT('+') : '+';
break;
case KEY_KP_SUBTRACT:
c = alternate_plus_minus ? ALT('-') : '-';
break;
case KEY_KP_MULTIPLY:
c = alternate_plus_minus ? ALT('*') : '*';
break;
case -1:
c = 0;
break;
default:
break;
}
return c;
}
static int getch_with_delay (void)
{
int c;
while (1) {
/* Try to get a character */
c = get_key_code (0);
if (c != ERR)
break;
}
/* Success -> return the character */
return c;
}
extern int max_dirt_limit;
/* Returns a character read from stdin with appropriate interpretation */
int get_event (Gpm_Event *event, int redo_event, int block)
{
int c;
static int flag; /* Return value from select */
static int dirty = 3;
if ((dirty == 1) || is_idle ()){
refresh ();
doupdate ();
dirty = 1;
} else
dirty++;
vfs_timeout_handler ();
/* Repeat if using mouse */
#ifdef HAVE_SLANG
while ((xmouse_flag) && !pending_keys)
{
// SLms_GetEvent (event);
*event = evSaved_Event;
}
#endif
c = block ? getch_with_delay () : get_key_code (1);
if (!c) { /* Code is 0, so this is a Control key or mouse event */
#ifdef HAVE_SLANG
// SLms_GetEvent (event);
*event = evSaved_Event;
#else
ms_GetEvent (event); /* my curses */
#endif
return EV_NONE; /* FIXME: when should we return EV_MOUSE ? */
}
return c;
}
/* Returns a key press, mouse events are discarded */
int mi_getch ()
{
Gpm_Event ev;
int key;
while ((key = get_event (&ev, 0, 1)) == 0)
;
return key;
}
/*
Special handling of ESC key when old_esc_mode:
ESC+ a-z,\n\t\v\r! = ALT(c)
ESC + ' '|ESC = ESC
ESC+0-9 = F(c-'0')
*/
static int EscapeKey (char* seq)
{
int c = *seq;
if (old_esc_mode) {
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|| (c == '\n') || (c == '\t') || (c == XCTRL('h'))
|| (c == KEY_BACKSPACE) || (c == '!') || (c == '\r')
|| c == 127 || c == '+' || c == '-' || c == '\\'
|| c == '?')
c = ALT(c);
else if (isdigit(c))
c = KEY_F (c-'0');
else if (c == ' ')
c = ESC_CHAR;
return c;
}
else
return 0; /* i.e. return esc then c */
}
/* Control and Alt
*/
static int ControlKey (char* seq)
{
return XCTRL(*seq);
}
static int AltKey (char *seq)
{
return ALT(*seq);
}
/*
is_idle - A function to check if we're idle.
It checks for any waiting event (that can be a Key, Mouse event,
and other internal events like focus or menu)
*/
int is_idle (void)
{
DWORD dw;
if (GetNumberOfConsoleInputEvents (hConsoleInput, &dw))
if (dw > 15)
return 0;
return 1;
}
extern long SLsys_GetLastkeyControlState ();
/* get_modifier */
int get_modifier()
{
int retval = 0;
if (dwSaved_ControlState & LEFT_ALT_PRESSED) /* code is not clean, because we return Linux-like bitcodes*/
retval |= ALTL_PRESSED;
if (dwSaved_ControlState & RIGHT_ALT_PRESSED)
retval |= ALTR_PRESSED;
if (dwSaved_ControlState & RIGHT_CTRL_PRESSED ||
dwSaved_ControlState & LEFT_CTRL_PRESSED)
retval |= CONTROL_PRESSED;
if (dwSaved_ControlState & win_shift_pressed)
retval |= SHIFT_PRESSED;
return retval;
}
int ctrl_pressed ()
{
if (dwSaved_ControlState & RIGHT_CTRL_PRESSED ||
dwSaved_ControlState & LEFT_CTRL_PRESSED)
return 1;
return 0;
}
/* void functions for UNIX copatibility */
void try_channels (int set_timeout)
{
}
void channels_up()
{
}
void channels_down()
{
}
void learn_keys()
{
message (1, "Learn Keys", "Sorry, no learn keys on Win32");
}
void init_key_input_fd (void)
{
}
#endif /* _OS_NT */