Clive Page has a small section about reading single keystrokes on Unix platforms (search for “Reading single keystrokes from Fortran” near the bottom of the page).
The approach used is to call functions in the header <termios.h> that provides a general terminal interface to control asynchronous communications ports.
Click for details
I do not hold the license to the following code, and have included it only for demonstration purposes. The code itself is a modified version of the file sys_keyin.c from Clive Page.
/* 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);
termattr.c_lflag&=~(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();
}
Use of the module from Fortran would look like:
module sys_key
use iso_c_binding, only: c_int
implicit none
public
integer(c_int), parameter :: SYS_KEYMODE_NORMAL = 0
integer(c_int), parameter :: SYS_KEYMODE_SINGLE = 1
interface
subroutine sys_keyset(mode) bind(c,name="sys_keyset_")
import c_int
integer(c_int), intent(in) :: mode
end subroutine
subroutine sys_keyin(nextch) bind(c,name="sys_keyin_")
import c_int
integer(c_int), intent(in) :: nextch
end subroutine
end interface
end module
program main
use sys_key
implicit none
integer(c_int), parameter :: ESC = 27_c_int
integer(c_int) :: nextch
write(*,*) "Press ESC to exit..."
call sys_keyset(SYS_KEYMODE_SINGLE)
do
call sys_keyin(nextch)
write(*,*) "The key pressed was: "//achar(nextch), nextch
if (nextch == ESC) exit
end do
!
! Don't forget to set the mode back to normal
! or your terminal will remain in the wrong mode
!
call sys_keyset(SYS_KEYMODE_NORMAL)
end program
Small demonstration:
~/fortran/sys_keyin$ gcc -c sys_keyin.c
~/fortran/sys_keyin$ gfortran sys_keyin.o sys_key.f90
~/fortran/sys_keyin$ ./a.out
Press ESC to exit...
The key pressed was: 1 49
The key pressed was: 2 50
The key pressed was: 3 51
The key pressed was: a 97
The key pressed was: b 98
The key pressed was: c 99
The key pressed was: > 62
The key pressed was: < 60
The key pressed was: = 61
The key pressed was: 32
The key pressed was:
10
The key pressed was: q 113
The key pressed was: e 27
For fun try pressing some control characters or localized (non-ASCII) letter characters on your keyboard (in my case I have čćšž).