/* Copyright (c) 1992, 1999, 2001, 2002, 2003 John E. Davis * This file is part of the S-Lang library. * * You may distribute under the terms of either the GNU General Public * License or the Perl Artistic License. */ #include "slinclud.h" #include #include #include "slang.h" #include "_slang.h" #ifdef __cplusplus # define _DOTS_ ... #else # define _DOTS_ void #endif static int Process_Mouse_Events; /*----------------------------------------------------------------------*\ * Function: static void set_ctrl_break (int state); * * set the control-break setting \*----------------------------------------------------------------------*/ static void set_ctrl_break (int state) { } /*----------------------------------------------------------------------*\ * Function: int SLang_init_tty (int abort_char, int no_flow_control, * int opost); * * initialize the keyboard interface and attempt to set-up the interrupt 9 * handler if ABORT_CHAR is non-zero. * NO_FLOW_CONTROL and OPOST are only for compatiblity and are ignored. \*----------------------------------------------------------------------*/ HANDLE _SLw32_Hstdin = INVALID_HANDLE_VALUE; int SLang_init_tty (int abort_char, int no_flow_control, int opost) { (void) opost; (void) no_flow_control; if (_SLw32_Hstdin != INVALID_HANDLE_VALUE) return 0; #if 1 /* stdin may have been redirected. So try this */ _SLw32_Hstdin = CreateFile ("CONIN$", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (_SLw32_Hstdin == INVALID_HANDLE_VALUE) return -1; #else if (INVALID_HANDLE_VALUE == (_SLw32_Hstdin = GetStdHandle(STD_INPUT_HANDLE))) return -1; #endif if (FALSE == SetConsoleMode(_SLw32_Hstdin, ENABLE_WINDOW_INPUT|ENABLE_MOUSE_INPUT)) { _SLw32_Hstdin = INVALID_HANDLE_VALUE; return -1; } if (abort_char > 0) SLang_Abort_Char = abort_char; return 0; } /* SLang_init_tty */ /*----------------------------------------------------------------------*\ * Function: void SLang_reset_tty (void); * * reset the tty before exiting \*----------------------------------------------------------------------*/ void SLang_reset_tty (void) { _SLw32_Hstdin = INVALID_HANDLE_VALUE; set_ctrl_break (1); } static int process_mouse_event (MOUSE_EVENT_RECORD *m) { char buf [8]; if (Process_Mouse_Events == 0) return -1; if (m->dwEventFlags) return -1; /* double click or movement event */ /* A button was either pressed or released. Now make sure that * the shift keys were not also pressed. */ if (m->dwControlKeyState & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED |LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED |SHIFT_PRESSED)) return -1; /* We have a simple press or release. Encode it as an escape sequence * and buffer the result. The encoding is: * 'ESC [ M b x y' * where b represents the button state, and x,y represent the coordinates. * The ESC is handled by the calling routine. */ if (m->dwButtonState & 1) buf[3] = ' '; else if (m->dwButtonState & 2) buf[3] = ' ' + 2; else if (m->dwButtonState & 4) buf[3] = ' ' + 1; else return -1; buf[0] = 27; buf[1] = '['; buf[2] = 'M'; buf[4] = 1 + ' ' + m->dwMousePosition.X; buf[5] = 1 + ' ' + m->dwMousePosition.Y; return SLang_buffer_keystring ((unsigned char *)buf, 6); } static int process_key_event (KEY_EVENT_RECORD *key) { unsigned int key_state = 0; unsigned int scan; char c1; DWORD d = key->dwControlKeyState; unsigned char buf[4]; if (!key->bKeyDown) return 0; if (d & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) key_state |= _SLTT_KEY_ALT; if (d & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) key_state |= _SLTT_KEY_CTRL; if (d & SHIFT_PRESSED) key_state |= _SLTT_KEY_SHIFT; scan = key->wVirtualScanCode; switch (scan) { case 0x00E: /* backspace */ return SLang_buffer_keystring ((unsigned char *)"\x7F", 1); case 0x003: /* 2 key */ if (key_state & _SLTT_KEY_ALT) break; /* Drop */ case 0x039: /* space */ if (key_state & _SLTT_KEY_CTRL) return SLang_buffer_keystring ((unsigned char *)"\x00\x03", 2); break; case 0x007: /* 6 key */ if (_SLTT_KEY_CTRL == (key_state & (_SLTT_KEY_ALT|_SLTT_KEY_CTRL))) return SLang_buffer_keystring ((unsigned char *)"\x1E", 1); /* Ctrl-^ */ break; case 0x00C: /* -/_ key */ if (_SLTT_KEY_CTRL == (key_state & (_SLTT_KEY_ALT|_SLTT_KEY_CTRL))) return SLang_buffer_keystring ((unsigned char *)"\x1F", 1); break; case 0x00F: /* TAB */ if (_SLTT_KEY_SHIFT == key_state) return SLang_buffer_keystring ((unsigned char *)"\x00\x09", 2); break; case 0xE02F: /* KEYPAD SLASH */ case 0x037: /* KEYPAD STAR */ case 0x04A: /* KEYPAD MINUS */ case 0x04E: /* KEYPAD PLUS */ if (d & NUMLOCK_ON) break; case 0x047: /* KEYPAD HOME */ case 0x048: /* KEYPAD UP */ case 0x049: /* KEYPAD PGUP */ case 0x04B: /* KEYPAD LEFT */ case 0x04C: /* KEYPAD 5 */ case 0x04D: /* KEYPAD RIGHT */ case 0x04F: /* KEYPAD END */ case 0x050: /* KEYPAD DOWN */ case 0x051: /* KEYPAD PGDN */ case 0x052: /* KEYPAD INSERT */ case 0x053: /* KEYPAD DEL */ if (d & ENHANCED_KEY) scan |= 0xE000; else { if (d & NUMLOCK_ON) break; } (void) _SLpc_convert_scancode (scan, key_state, 0); return 0; case 0x3b: /* F1 */ case 0x3c: case 0x3d: case 0x3e: case 0x3f: case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x57: case 0x58: /* F12 */ (void) _SLpc_convert_scancode (scan, key_state, 0); } c1 = key->uChar.AsciiChar; if (c1 != 0) { if (_SLTT_KEY_ALT == (key_state & (_SLTT_KEY_ALT|_SLTT_KEY_CTRL))) { buf[0] = 27; buf[1] = c1; return SLang_buffer_keystring (buf, 2); } if (c1 == SLang_Abort_Char) { if (SLang_Ignore_User_Abort == 0) SLang_Error = USER_BREAK; SLKeyBoard_Quit = 1; } buf[0] = c1; return SLang_buffer_keystring (buf, 1); } return 0; } static void process_console_records(void) { INPUT_RECORD record; DWORD bytesRead; DWORD n = 0; if (FALSE == GetNumberOfConsoleInputEvents(_SLw32_Hstdin, &n)) return; while (n > 0) { ReadConsoleInput(_SLw32_Hstdin, &record, 1, &bytesRead); switch (record.EventType) { case KEY_EVENT: (void) process_key_event(&record.Event.KeyEvent); break; case MOUSE_EVENT: process_mouse_event(&record.Event.MouseEvent); break; case WINDOW_BUFFER_SIZE_EVENT: /* process_resize_records(&record.Event.WindowBufferSizeEvent); */ break; } n--; } } /*----------------------------------------------------------------------*\ * Function: int _SLsys_input_pending (int tsecs); * * sleep for *tsecs tenths of a sec waiting for input \*----------------------------------------------------------------------*/ int _SLsys_input_pending (int tsecs) { long ms; if (_SLw32_Hstdin == INVALID_HANDLE_VALUE) return -1; if (tsecs < 0) ms = -tsecs; /* specifies 1/1000 */ else ms = tsecs * 100L; /* convert 1/10 to 1/1000 secs */ process_console_records (); while ((ms > 0) && (SLang_Input_Buffer_Len == 0)) { long t; t = GetTickCount (); (void) WaitForSingleObject (_SLw32_Hstdin, ms); process_console_records (); ms -= GetTickCount () - t; } return SLang_Input_Buffer_Len; } /*----------------------------------------------------------------------*\ * Function: unsigned int _SLsys_getkey (void); * * wait for and get the next available keystroke. * Also re-maps some useful keystrokes. * * Backspace (^H) => Del (127) * Ctrl-Space => ^@ (^@^3 - a pc NUL char) * extended keys are prefixed by a null character \*----------------------------------------------------------------------*/ unsigned int _SLsys_getkey (void) { /* Check the input buffer because _SLsys_input_pending may have been * called prior to this to stuff the input buffer. */ if (SLang_Input_Buffer_Len) return SLang_getkey (); if (_SLw32_Hstdin == INVALID_HANDLE_VALUE) return SLANG_GETKEY_ERROR; while (1) { int status; if (SLKeyBoard_Quit) return SLang_Abort_Char; status = _SLsys_input_pending (600); if (status == -1) return SLANG_GETKEY_ERROR; if (status > 0) return SLang_getkey (); } } /*----------------------------------------------------------------------*\ * Function: int SLang_set_abort_signal (void (*handler)(int)); \*----------------------------------------------------------------------*/ int SLang_set_abort_signal (void (*handler)(int)) { if (_SLw32_Hstdin == INVALID_HANDLE_VALUE) return -1; return 0; } int SLtt_set_mouse_mode (int mode, int force) { (void) force; Process_Mouse_Events = mode; return 0; }