Project

General

Profile

Waiting for key press (not so easy)

Added by Runar Tenfjord 18 days ago

It turns out that waiting for a single key press on Linux or Windows is surprisingly difficult to do without resorting to 3rd part libraries.
I need this for some testing and had to do quite a lot of research to find a solution.

I thought I might share the solutions I found and this should perhaps be added to the libraries as it is very basic and common functionality.

Linux :

IMPORT API := Linux IN API, SYSTEM;

(* Read single key from console without echo. *)
PROCEDURE ConsoleReadKey*(): CHAR;
CONST
    TCGETS = 00005401H;
    TCSETSW = 00005403H;
    STDIN_FILENO = 0;
    ICANON = 1;
    ECHO = 3;
TYPE
    Termios = RECORD-
        c_iflag: INTEGER;
        c_oflag: INTEGER;
        c_cflag: INTEGER;
        c_lflag: INTEGER;
        c_cc: ARRAY 64 OF SYSTEM.BYTE;
    END;
VAR
    termios : Termios;
    saved : INTEGER;
    s : SET;
    ret : CHAR;
BEGIN
    IGNORE(API.IOCtl(STDIN_FILENO, TCGETS, SYSTEM.ADR(termios)));
    saved := termios.c_lflag;
    s := SET(termios.c_lflag);
    s := s - {ICANON} - {ECHO};
    termios.c_lflag := SYSTEM.VAL(INTEGER, s);
    IGNORE(API.IOCtl(STDIN_FILENO, TCSETSW, SYSTEM.ADR(termios)));
    IF API.Read(STDIN_FILENO, SYSTEM.ADR(ret), 1) # 1 THEN
        ret := 00X;
    END;
    termios.c_lflag := saved;
    IGNORE(API.IOCtl(STDIN_FILENO, TCSETSW, SYSTEM.ADR(termios)));
    RETURN ret;
END ConsoleReadKey;

I added the IOCtl syscall for this to work.

Windows :

IMPORT API := Windows IN API, SYSTEM;

(* Read single key from console without echo. *)
PROCEDURE ConsoleReadKey*(): CHAR;
VAR
    handle : API.HANDLE;
    mode : API.DWORD;
    ch : CHAR;
BEGIN
    ch := 00X;
    handle := API.GetStdHandle(API.STD_INPUT_HANDLE);
    IF handle = API.INVALID_HANDLE_VALUE THEN RETURN 00X END;
    IGNORE(API.GetConsoleMode(handle, SYSTEM.ADR(mode)));
    IGNORE(API.SetConsoleMode(handle, 0));
    IGNORE(API.WaitForSingleObject(handle, API.INFINITE));
    IGNORE(API.ReadFile(handle, SYSTEM.ADR(ch), 1, 0, NIL));
    IGNORE(API.SetConsoleMode(handle, mode));
    RETURN ch
END ConsoleReadKey;


Replies (1)

    (1-1/1)