📄 console.c
字号:
/* * All video and keyboard functions were gathered into one file. * * In version 3.2, this file was split into 3 sections: 1) unix curses * made to look and feel like a PC, 2) our PC hardware specific stuff, * and 3) hardware independent stuff. * * This file contains the keyboard and video i/o stuff. Most of this stuff * is specific to the PC hardware, but it should be easily modified when * porting to other platforms. With a few key functions written in * assembly, we have fairly fast video performance and good keyboard control. * Incidentally, the commented C code in the functions perform the same * function as the assembly code. In earlier versions of TDE, I didn't * update the commented C code when I changed the assembly code. The * C and assembly should be equivalent in version 2.2. * * Although using a curses type package would be more portable, curses * can be slow on PCs. Let's keep our video and keyboard routines in * assembly. I feel the need for speed. * * Being that TDE 2.2 keeps an accurate count of characters in each line, we * can allow the user to enter any ASCII or Extended ASCII key. * * * New editor name: TDE, the Thomson-Davis Editor. * Author: Frank Davis * Date: June 5, 1991, version 1.0 * Date: July 29, 1991, version 1.1 * Date: October 5, 1991, version 1.2 * Date: January 20, 1992, version 1.3 * Date: February 17, 1992, version 1.4 * Date: April 1, 1992, version 1.5 * Date: June 5, 1992, version 2.0 * Date: October 31, 1992, version 2.1 * Date: April 1, 1993, version 2.2 * Date: June 5, 1993, version 3.0 * Date: August 29, 1993 version 3.1 * Date: November 13, version 3.2 * Date: June 5, 1994, version 4.0 * Date: December 5, 1998, version 5.0 (jmh) * * This code is released into the public domain, Frank Davis. * You may distribute it freely. */#include "tdestr.h"#include "common.h"#include "define.h"#include "tdefunc.h"#ifndef VK_A /* MinGW32 doesn't define these */# define VK_A 65# define VK_Z 90#endif HANDLE conin; /* console input */static HANDLE conout; /* console output (TDE's screen) */static HANDLE StdOut; /* standard output (user screen) */static HANDLE StdOutPut; /* for redirected shelling */static char title[256]; /* console window title */static DWORD conmode; /* original console input mode */static DWORD susmode; /* suspended console input mode */static int capslock_state; /* the current state of capslock */static int numlock_state; /* the current state of numlock */static int process_keypad( int ); /* read Alt+Keypad character entry */ int handle_mouse; /* recognise mouse input *//* * the USA character set, to determine if AltGr should be a character, * rather than a function key (Left\ is handled separately). */#define FIRST_CHAR _1#define LAST_CHAR _SLASHstatic const char usa_char[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 8, 9, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 13, 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/'};/* * Name: console_init * Purpose: initialise the console (video and keyboard) * Author: Jason Hood * Date: October 23, 2002 * Passed: cfg: pointer to hold video config data * Notes: initialises both video and keyboard hardware. * moved some stuff from main.c into here. * * 050729: always create output, since there's no distinction between * console and other character devices. */void console_init( struct vcfg *cfg ){SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, TRUE }; conout = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL ); StdOut = CreateFile( "CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, 0 ); conin = CreateFile( "CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, 0 ); GetConsoleMode( conin, &conmode ); SetConsoleMode( conin, ENABLE_EXTENDED_FLAGS | ENABLE_MOUSE_INPUT | (conmode & ENABLE_QUICK_EDIT) ); page( 1 ); video_config( cfg ); GetConsoleTitle( title, sizeof(title) ); SetConsoleCtrlHandler( (PHANDLER_ROUTINE)ctrl_break_handler, TRUE );}/* * Name: console_suspend * Purpose: temporarily shutdown the console * Author: Jason Hood * Date: October 23, 2002 * Notes: readies the console for a shell */void console_suspend( void ){ page( 0 ); StdOutPut = GetStdHandle( STD_OUTPUT_HANDLE ); SetStdHandle( STD_OUTPUT_HANDLE, StdOut ); GetConsoleMode( conin, &susmode ); SetConsoleMode( conin, conmode );}/* * Name: console_resume * Purpose: restore the console * Author: Jason Hood * Date: October 23, 2002 * Notes: restores the console for TDE */void console_resume( int pause ){ SetStdHandle( STD_OUTPUT_HANDLE, StdOutPut ); SetConsoleMode( conin, susmode ); if (pause) getkey( ); page( 1 );}/* * Name: console_exit * Purpose: resets the console * Author: Jason Hood * Date: October 23, 2002 * Notes: resets the console after TDE has finished */void console_exit( void ){ page( 0 ); /* back to the original screen */ SetConsoleMode( conin, conmode ); CloseHandle( conin ); CloseHandle( StdOut ); CloseHandle( conout );}/* * Name: video_config * Purpose: initialise console input and output * Date: August 13, 2002 * Passed: cfg: pointer to video parameters */void video_config( struct vcfg *cfg ){CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo( conout, &csbi ); cfg->cols = csbi.dwSize.X; cfg->rows = csbi.dwSize.Y; g_display.adapter = VGA; cfg->color = TRUE; g_display.cursor[SMALL_CURSOR] = 15; g_display.cursor[MEDIUM_CURSOR] = 50; g_display.cursor[LARGE_CURSOR] = 100; mode.enh_kbd = TRUE; g_display.shadow_width = 1;}/* * Name: getkey * Purpose: get keyboard input * Date: August 13, 2002 * Passed: None * Notes: map Windows keys to TDE keys. * handle Alt+keypad since Windows low-level console input doesn't. * * 020923: recognise the Menu key as the PullDown function. * 021012: better support for non-US keyboards, hopefully (AltGr characters). */long getkey( void ){static INPUT_RECORD key;static long kee;WORD vk;DWORD read;int scan, mod, ch;int state;TDE_WIN *wp;#define KEYEV key.Event.KeyEvent#define MOUSEEV key.Event.MouseEvent#define ALT_PRESSED (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)#define CTRL_PRESSED (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED) if (handle_mouse && key.EventType == MOUSE_EVENT) {do_move: if (MOUSEEV.dwMousePosition.X > 0) { --MOUSEEV.dwMousePosition.X; return( CharRight | _FUNCTION ); } if (MOUSEEV.dwMousePosition.X < 0) { ++MOUSEEV.dwMousePosition.X; return( CharLeft | _FUNCTION ); } if (MOUSEEV.dwMousePosition.Y > 0) { --MOUSEEV.dwMousePosition.Y; return( LineDown | _FUNCTION ); } if (MOUSEEV.dwMousePosition.Y < 0) { ++MOUSEEV.dwMousePosition.Y; return( LineUp | _FUNCTION ); } key.EventType = 0; if (MOUSEEV.dwControlKeyState & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) return( MarkBox | _FUNCTION ); if (MOUSEEV.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) return( MarkLine | _FUNCTION ); if (MOUSEEV.dwControlKeyState & SHIFT_PRESSED) return( MarkStream | _FUNCTION ); } if (key.EventType == KEY_EVENT && KEYEV.wRepeatCount > 1) { --KEYEV.wRepeatCount; return( kee ); } g_status.control_break = FALSE;go_again: ReadConsoleInput( conin, &key, 1, &read ); if (g_status.control_break) return( _CONTROL_BREAK ); if (handle_mouse && key.EventType == MOUSE_EVENT && MOUSEEV.dwButtonState && MOUSEEV.dwEventFlags == 0) { if (MOUSEEV.dwButtonState & RIGHTMOST_BUTTON_PRESSED) { key.EventType = 0; return( PasteFromClipboard | _FUNCTION ); } for (wp = g_status.window_list; wp != NULL; wp = wp->next) { if (wp->visible && MOUSEEV.dwMousePosition.X >= wp->start_col && MOUSEEV.dwMousePosition.X <= wp->end_col && MOUSEEV.dwMousePosition.Y >= wp->top_line && MOUSEEV.dwMousePosition.Y <= wp->bottom_line) { MOUSEEV.dwMousePosition.X -= wp->ccol; MOUSEEV.dwMousePosition.Y -= wp->cline; if (g_status.current_window != wp) { change_window( g_status.current_window, wp ); return( _FUNCTION ); } if (g_status.current_window->rline + MOUSEEV.dwMousePosition.Y > g_status.current_file->length + 1) goto go_again; if (MOUSEEV.dwControlKeyState & ALT_PRESSED) return( MarkBox | _FUNCTION ); if (MOUSEEV.dwControlKeyState & CTRL_PRESSED) return( MarkLine | _FUNCTION ); if (MOUSEEV.dwControlKeyState & SHIFT_PRESSED) return( MarkStream | _FUNCTION ); goto do_move; } } } if (key.EventType != KEY_EVENT || KEYEV.bKeyDown == FALSE) goto go_again; vk = KEYEV.wVirtualKeyCode; if (vk == VK_SHIFT || vk == VK_CONTROL || vk == VK_MENU || vk == VK_CAPITAL || vk == VK_NUMLOCK || vk == VK_SCROLL) goto go_again; if (vk == VK_APPS) return( PullDown | _FUNCTION ); state = KEYEV.dwControlKeyState; /* * Remember the lock states for their respective functions. */ capslock_state = state & CAPSLOCK_ON; numlock_state = state & NUMLOCK_ON; mod = 0; if (state & SHIFT_PRESSED) mod |= _SHIFT; if (state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) mod |= _CTRL; if (state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) mod |= _ALT; if (state & ENHANCED_KEY) mod |= _FUNCTION; scan = KEYEV.wVirtualScanCode + 255; if ((mod & _ALT) && !(mod & _FUNCTION) && scan >= _HOME && scan <= _INS && scan != _GREY_MINUS && scan != _GREY_PLUS) return( process_keypad( scan ) ); ch = KEYEV.uChar.AsciiChar; /* * If only AltGr has been pressed, see if the character is different to * my mapping of it - if so, assume an AltGr character. * -16 (240) seems to be generated for some non-alphanum keys. * jmh 021019: special case for Left\. * jmh 021104: it seems NT/2K/XP (or the keyboard itself) also generates * a left control press. */ if (ch != 0 && ch != -16 && (state & RIGHT_ALT_PRESSED) && !(mod & _SHIFT) && (!(mod & _CTRL) || !(state & RIGHT_CTRL_PRESSED))) { if (scan >= FIRST_CHAR && scan <= LAST_CHAR) { if (bj_tolower( ch ) != usa_char[scan - FIRST_CHAR]) return( ch ); } else if (scan == _LEFT_BACKSLASH && ch != '\\') return( ch ); } if (mod & _FUNCTION) { if (scan == _SLASH) scan = _GREY_SLASH; else { if (vk == VK_RETURN) scan = _GREY_ENTER; else if (vk == VK_MULTIPLY) scan = _PRTSC; ch = 0; } } kee = translate_key( scan, mod, (text_t)ch ); if (kee == ERROR) goto go_again; return( kee );}/* * Name: process_keypad * Purpose: allow Alt+Keypad character entry * Author: Jason Hood * Date: August 22, 2002 * Passed: first: the first key pressed * Returns: the character entered * Notes: assumes first is an actual keypad digit. * keeps processing (ignoring) keys until Alt is released, with * the exception of Alt+KP0 (same as DOS). */static int process_keypad( int first ){INPUT_RECORD key;int scan;int num;DWORD read;/* Translate keypad scancodes to digits. */static int key_digit[] = { 7, 8, 9, -1, 4, 5, 6, -1, 1, 2, 3, 0 }; num = key_digit[first - _HOME]; if (num == 0) return( 0 ); while (TRUE) { ReadConsoleInput( conin, &key, 1, &read ); if (key.EventType == KEY_EVENT) { scan = KEYEV.wVirtualKeyCode; if (KEYEV.bKeyDown == FALSE) { if (scan == VK_MENU) break; } else { scan = KEYEV.wVirtualScanCode + 255; if (!(KEYEV.dwControlKeyState & ENHANCED_KEY) && scan >= _HOME && scan <= _INS && scan != _GREY_MINUS && scan != _GREY_PLUS) num = num * 10 + key_digit[scan - _HOME]; } } } return( num & 255 );}/* * Name: waitkey * Purpose: call the BIOS keyboard status subfunction * Date: August 13, 2002 * Passed: enh_keyboard: boolean - TRUE if 101 keyboard, FALSE otherwise * Returns: 1 if no key ready, 0 if key is waiting * Notes: not needed in Win32. */int waitkey( int enh_keyboard ){ return( 0 );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -