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. Clive Page has written a sample C file for that purpose. After some slight modifications the code will be accepted by Clang:

/* sys_keyin.c  This version works on _most_ Unix platforms
  Fortran calls:
      call sys_keyset(1)   to set single-keystroke mode
      call sys_keyin(key)  to get integer ASCII code for next key-stroke
                           e.g. 32 for space, 97 for "a" etc.
                           (Integer rather than character to cope with
                           control characters etc.)
      call sys_keyset(0)   to restore normal input mode
  Author: Clive Page, cgp@le.ac.uk, 1994-JUL-13
*/

#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 iso_c_binding
            integer(kind=c_int) :: mode
        end subroutine sys_keyset

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

    call sys_keyset(1)

    do
        call sys_keyin(key)
        write (*, '(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 provided by Rosetta Code.