Key Capture

For historical reasons, I/O operations in Fortran are record-based (even if some limited stream-based I/O is possible in modern language versions). Therefore, no intrinsic Fortran routine exists to capture single key-stroke events. The best way seems to be to call an external C function, which works on most Unix-like operating systems.

/* sys_keyin.c */
#include <stdio.h>
#include <termios.h>

void sys_keyset(int *mode)
    static struct termios termattr, saveattr;
    static tcflag_t save_flags;

    if (*mode != 0)
        tcgetattr(0, &termattr);
        saveattr = termattr;
        termattr.c_lflag &= ~(ICANON | ECHO);
        termattr.c_cc[VMIN] = 1;
        termattr.c_cc[VTIME] = 0;
        tcsetattr(0, TCSADRAIN, &termattr);
        tcsetattr(0, TCSADRAIN, &saveattr);

void sys_keyin(int *nextch)
    *nextch = getchar();

In order to use these routines, ISO C binding interfaces have to be written. See the example below, which prints the code of the pressed key.

! key.f90
program main
    use, intrinsic :: iso_c_binding
    implicit none
    integer :: key

        subroutine sys_keyset(mode) bind(c)
            import :: c_int
            integer(kind=c_int) :: mode
        end subroutine sys_keyset

        subroutine sys_keyin(nextch) bind(c)
            import :: c_int
            integer(kind=c_int) :: nextch
        end subroutine sys_keyin
    end interface

    call sys_keyset(1)

        call sys_keyin(key)
        print '(a, i0)', 'key pressed: ', key

        if (key == ichar('q')) &
    end do

    call sys_keyset(0)
end program main

Compile and run the example with:

$ gcc9 -c sys_keyin.c
$ gfortran9 -o key key.f90 sys_keyin.o
$ ./key

Or, if you prefer Flang:

$ clang -c sys_keyin.c
$ flang -o key key.f90 sys_keyin.o
$ ./key

For non-blocking keyboard input, one can use the C procedures listed on Rosetta Code.