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:

#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);
    }
    else
    {
        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
    implicit none
    integer :: key

    interface
        subroutine sys_keyset(mode) bind(c)
            use, intrinsic :: iso_c_binding
            integer(kind=c_int) :: mode
        end subroutine sys_keyset

        subroutine sys_keyin(nextch) bind(c)
            use, intrinsic :: iso_c_binding
            integer(kind=c_int) :: nextch
        end subroutine sys_keyin
    end interface

    call sys_keyset(1)

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

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

    call sys_keyset(0)
end program main

Compile and run the example with:

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

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

References