Forums » Programming with the ECS » Oberon »
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;