Have there been any recent developments (or tricks) that would allow
for input that doesn't require pressing the return key? If it helps,
I'm using g95.
Thanks!
Coincidentally, I was reading Clive Page's Fortran page this morning and
it mentions reading single keystrokes. Unfortunately, it says there
isn't a portable way to do this in Fortran, but he offers a C function
with some instructions on how to call it from Fortran:
http://www.star.le.ac.uk/~cgp/fortran.html
http://www.star.le.ac.uk/~cgp/sys_keyin.c
I would imagine there is a way to do this in Fortran 2003 using
stream input from stdin, but I couldn't get anything working.
Maybe someone else knows...
If you don't mind using something non-standard, I know that
GFortran has an FGET extension for this. It's likely that
G95 has a similar extension.
http://gcc.gnu.org/onlinedocs/gcc-4.4.0/gfortran/FGET.html
Jason
It is not standard C either, but it is a more common extension
in C libraries than Fortran libraries.
-- glen
My mistake. I just realized that FGET doesn't quite do what
you want. It just reads in stream mode, it won't get the
input for you immediately after a key press.
Jason
Now I see that Clive's code only works on "most Unix systems"
as it uses termios.h.
So, if I understand, the problem is that the terminal usually
buffers the input and so you have to specifically ask it to send
the input character-for-character, but you have to do so in a
platform-dependent way.
Jason
What I do in WATCOM FOrtran 77 (www.openwatcom.org)
is have a little "pragma" (short assembler program embedded
in the source) which looks at the keyboard strobe and gets
the keycode if there was a strobe. If it's a key I don't want,
I clear the strobe and return "no key".
But other fortrans don't have this ability. Too bad.
Chris
Yes, the routine that I link to only works on "some" Unix systems,
mostly the older ones. I haven't got it to work on Windows with g95 or
gfortran, nor do I know of any other way of doing this, unfortunately.
--
Clive Page
On Windows, you ought to be able to use an API function of some sort or
another (though what with the stdcall cf, you probably have to do a
C/C++ wrapper in order to have a cdecl function to bind(C) to in Win32).
No, those declarations are all provided for you, no muss no fuss.
--
Gary Scott
mailto:garylscott@sbcglobal dot net
Fortran Library: http://www.fortranlib.com
Support the Original G95 Project: http://www.g95.org
-OR-
Support the GNU GFortran Project: http://gcc.gnu.org/fortran/index.html
If you want to do the impossible, don't hire an expert because he knows
it can't be done.
-- Henry Ford
>http://www.star.le.ac.uk/~cgp/sys_keyin.c
As noted earlier, this works on some Unix-like systems including Linux,
but not on Windows.
>I would imagine there is a way to do this in Fortran 2003 using
>stream input from stdin, but I couldn't get anything working.
>Maybe someone else knows...
>
>If you don't mind using something non-standard, I know that
>GFortran has an FGET extension for this. It's likely that
>G95 has a similar extension.
>
>http://gcc.gnu.org/onlinedocs/gcc-4.4.0/gfortran/FGET.html
I've tried this too, but can't get it to read single keystrokes - the
keystroke read still needs a RETURN at the end.
On Windows the nearest I've been able to find uses a function in the
GrWin library, which can be downloaded from:
http://spdg1.sci.shizuoka.ac.jp/grwinlib/english/
This contains a function kbgetch(n) which returns the integer code of
the next single keystroke. Normally n=0 but if n=1 then the character
is echoed to stdout.
This can be linked using g95 or gfortran on Windows-XP using a command
like this:
>g95 testkbd.f90 -Wl,--subsystem,console -lGrWin -mwindows -lg2c
I have no idea what the switch "-Wl,--subsystem,console" is doing, it is
just a bit of magic I found in the GrWin files. If anyone understands
it, please post.
It is, as you say, a pity that this cannot be done in a way that is
portable across operating systems.
--
Clive Page
I'd wager that "-Wl,--subsystem,console" ensures that a console window
will be created when the executable loads. I think I read somewhere that
whether or not a console window is created when a Windows app loads
boils down to the value of a singe byte somewhere in the exe header.
What is more interesting above is that you are compiling with g95 and
linking with the g77 runtime ( -lg2c ), so it seems that you would need
both compilers (g95 and g77) installed to use GrWin with g95.
That's sounds a good explanation. But I still don't quite know why this
is needed for the single keystroke routine to work.
>What is more interesting above is that you are compiling with g95 and
>linking with the g77 runtime ( -lg2c ), so it seems that you would need
>both compilers (g95 and g77) installed to use GrWin with g95.
I'm doing that deliberately because the GrWin library was built using
g77, so some of its low-level routines need things not in the
g95/gfortran libraries. Adding -lg2c seems to solve this. g77 seems to
come with the MinGW installation, so it needed no extra effort (for me
at least).
I can't claim this is a good way of getting a single keystroke, just
that it works. Presumably somewhere hidden in the GrWin source code is
the C code to do just that, which could be extracted. I haven't had
time to delve deeply enough and do that.
--
Clive Page
--
In ifort/CVF, sure, but I doubt that's true of either g95 or gfortran.
And gfortran at least (and I suspect g95 as well) has serious issues
dealing with the cdecl/stdcall divide in win32.
The "-Wl," part is telling it to pass an option through to the linker.
The "--subsystem,console" part is the the linker option, it's telling
the linker to build a console application, i.e. one that gets its own
console when the program starts (and, on the C side, starts with "int
main"). The alternative, I believe, is Win32, which does not start out
with a console and also has a different entry point (WinMain).
In which case you would check for a WM_CHAR message in your message
processing loop ...
But a console app doesn't have a message processing loop (in the Windows
sense, the app may be written to be input driven, but that's not the
same thing, of course)--and the keystrokes would be sent to the active
window, not a console.
The result would be that a "standard" Fortran app using stdio and
READ(*,... wouldn't ever "see" the keystroke unless processing the
console connected to the app. The making of which console is the point
of the system linker switch.
I've never tried to see if could hack around it, but a quick perusal
doesn't indicate any (at least straightforward) way for the Win32 user
input keyboard APIs to connect to an open console handle.
--
Not recent, but the curses library reads the terminfo database to find
out how to do this for your terminal and OS. There is an old shareware
library (Fortran 77) fcurses, which among other things includes a
demonstration popup calculator (reads function keys, numeric keypad
etc). The curses library has:
getch(3NCURSES)
NAME
getch, wgetch, mvgetch, mvwgetch, ungetch, has_key - get (or push back)
characters from curses terminal
so this could probably be called directly using the Fortran 2003 FFI.
Cheers, David Duffy.
Actually it does have a normal message processing loop, its just
hidden from you. But you can snoop on it. A console app isn't really
any different, it's just a special "window" (made ugly) with some
"convenience features". You can even have hybrid console/"win32" apps
if you want.
> snip
> --
Not that I know of <way of snooping into it>, short of writing a
kernel-mode application. As far as I know (and I claim to be
well-versed on the subject of Windows inner workings), it's buried
somewhere deep into the system innards, to the point of
inaccessibility.
--
Jugoslav
www.xeffort.com
Please reply to the newsgroup.
You can find my real e-mail on my home page above.
I have a C routine similar in limitations to some of the ones
mentioned; but it is different enough
to mention; plus I have used it over the years on at least 20 Unix and
GNU/Linux systems, including
CygWin on MSWindows platforms. It used to need tweeked a lot; put I
don't think I've had to change
it since the mid-90s (put except for via CygWin, I have never tried
this on an MSWindows machine -- if anyone
has one and tries the routine, I'd be interested in knowing the
results -- is ioctl(3c) supported? ).
The routine is at
http://home.comcast.net/~urbanjost/CLONE/GETKEY/getkey.html
Here is code for the INKEY routine. Not sure where I got this exactly,
probably
from the CVF forum or this newgroup:
subroutine inkey(a,ii)
use dflib
character*1 a(2)
logical pressed
pressed = PEEKCHARQQ()
if(pressed) then
ii = 1
a(1) = getcharqq()
kk = ichar(a(1))
if(kk.eq.0 .or. kk.eq.14*16) then
a(1) = char(0)
a(2) = getcharqq()
end if
else
ii = 0
end if
return
end
The subroutine returns ii = 0 if there is no keystroke in the queue, 1
if something is available.
When something is there, a(1) returns the ascii code of the
keystroke, if a(1) is 0, then
the keystroke is a special key (cursor key, end key, home key etc),
and the key code is returned
in a(2).
Here's some sample code where I used this:
C
C-----------
C
C GET A KEYSTROKE FROM THE USER
C
1000 CALL INKEY(KEY,II)
IF(II.EQ.0) GOTO 1000
C
C MAKE A <CR> ACT LIKE <CURSOR DOWN>
C
1500 IF(KEY(1).EQ.CHAR(13)) THEN
KEY(1)=CHAR(0)
KEY(2)=CHAR(80)
END IF
IF(KEY(1).NE.CHAR(0)) GOTO 3000
C
C-----------
C
C THE USER HIT A "SPECIAL" KEY
C
C IF USER HIT <F1> SET ALL ELEVATIONS TO DEFAULT
C
IF(KEY(2).EQ.CHAR(59)) THEN
DO 1050 I=1,19
EL(I)=EGUIDE(I,IW)
1050 CONTINUE
GOTO 5
END IF
C
C IF USER HIT <F2> SET CURRENTLY HIGHLIGHTED ELEVATION TO DEFAULT
C
IF(KEY(2).EQ.CHAR(60)) THEN
IF(IOLD.GT.19) GOTO 1000
EL(IOLD) = EGUIDE(IOLD,IW)
GOTO 2000
END IF
C
C CHECK FOR <END>
C
IF(KEY(2).EQ.CHAR(79)) THEN
WRITE(14,REC=IWEEK) EL,FLOW,PADEL
CLOSE(14)
RETURN
END IF
C
C CHECK FOR <CURSOR UP>
C
IF(KEY(2).EQ.CHAR(72)) THEN
INEW = IOLD - 1
IF(IFLOW.EQ.1) THEN
IF(IOLD.EQ.1) INEW = 10
IF(IOLD.EQ.11) INEW = 19
ELSE
IF(IOLD.EQ.62) INEW = 19
IF(IOLD.EQ.1) INEW = 62
IF(IOLD.EQ.20) INEW = 40
IF(IOLD.EQ.41) INEW = 61
END IF
GOTO 2000
END IF
It is quite easy to use the following to get the window handle:
handle = findwindowex(null,null,"ConsoleWindowClass"//char(0),null)
From there, you can inquire and manipulate console windows if you are
knowledgable and careful. If you open a console application, the
handle that it returns will be that of the current application. I
have used peekmessage to query such things as function key values in
the distant past.
>
> --
> Jugoslavwww.xeffort.com
> Please reply to the newsgroup.
> You can find my real e-mail on my home page above.- Hide quoted text -
>
> - Show quoted text -
Then, please, show me how. This does not work:
program Getch
use ifwin
implicit none
integer(HANDLE):: h
type(T_MSG):: msg
integer:: iret
h = FindWindowEx(null,null,"ConsoleWindowClass"//char(0),null)
iret = GetMessage(msg, h, 0, 0)
if (msg%message.eq.WM_KEYDOWN) &
write(*,*) "You pressed ", char(msg%wParam)
end program Getch
Window handle is returned indeed (as expected), but GetMessage does
not work for any combination of parameters (h or NULL; 0 or WM_KEYDOWN
for messsage filtering); the program only sits in there forever. That
suggests that a /subsystem:console application does not have a regular
message queue, and that you cannot peek into it like for a regular
/subsystem:windows application. I admit I haven't tried a message
hook (SetWindowsHookEx(WH_KEYBOARD or WH_KEYBOARD_LL)).
--
Jugoslav
> It is quite easy to use the following to get the window handle:
>
> handle = findwindowex(null,null,"ConsoleWindowClass"//char(0),null)
>
> From there, you can inquire and manipulate console windows if you are
> knowledgable and careful. If you open a console application, the
> handle that it returns will be that of the current application. I
> have used peekmessage to query such things as function key values in
> the distant past.
>
>
I've been tinkering a little. Google of "hwnd console" and first hit has
example code of how to get the handle to the console window. That part
was easy.
I haven't has much luck yet with PeekMessage. I guess I agree with
Jugoslav - it would be nice to see an example if you can dig one up.
I don't have time right now, as I have a 10AM meeting and aren't ready
but I think the appropriate routines to write a getch() routine for
console are
GetStdHandle()
and the low-level console routines
ReadConsoleInput
Reads and removes input records from an input buffer. The function
does not return until at least one record is available to be read. Then
all available records are transferred to the buffer of the calling
process until either no more records are available or the specified
number of records has been read. Unread records remain in the input
buffer for the next read operation. The function reports the total
number of records that have been read. For an example that uses
ReadConsoleInput, see Reading Input Buffer Events.
PeekConsoleInput
Reads without removing the pending input records in an input buffer.
All available records up to the specified number are copied into the
buffer of the calling process. If no records are available, the function
returns immediately. The function reports the total number of records
that have been read.
There _may_ be a way to get at the windows message queue that handles
the console window default menu functions but afaict it's not in the MS
scheme of things to do so; it's buried so deeply in the bowels that
unless the application is actually built as a Windows app it may as well
be said the windows message pump doesn't exist.
Again, imo, $0.02, etc., etc., ... and I'm willing like you to "be
showed somethin' different..." :)
--
Amen. Indeed they are, and I betcha that actual getch()/GETCHARQQ
end up calling them. Actually, how did this entire subthread
start, and what's its point, except that Gary and I try to outsmart
each other, and earn "Im-right-and-youre-wrong" scorepoints ? :P
:) I do indeed have a very old procedure that used peekmessage. It no
longer works. My more recent EZCONSOLE application uses
readconsoleinput as indicated by dpb. If you only need text
characters, you can do that with READCONSOLE (much easier than
readconsoleinput). setconsolemode(inputhandle,0) to disable return
key requirement if you want to read each keystroke.
>
> --
> Jugoslavwww.xeffort.com
> Please reply to the newsgroup.
[snip]
> Amen. Indeed they are, and I betcha that actual getch()/GETCHARQQ
> end up calling them. Actually, how did this entire subthread
> start, and what's its point, except that Gary and I try to outsmart
> each other, and earn "Im-right-and-youre-wrong" scorepoints ? :P
Thread drift ? Yeah, I guess I am partly responsible for that. I don't
think the OP ever actually said that he was using Windows.
Still, how to use the Windows API to get a single keystroke in a console
app, with out requiring user to hit return key, is something I find
potentially useful. The topic has come up here before, along with the
typical there-is-no-portable-way-to-do-it responses.
This still stalls if no character, though, right??? Or is there some
other place to set that characteristic or does ReadConsole() return
error if no character waiting? (The latter doesn't seem to be
documented afaict and again I'm dashing between other commitments w/ no
time to play...)
> SetConsoleMode
> ...
> Value
> ENABLE_LINE_INPUT
>
> The ReadFile or ReadConsole function returns only when a carriage
> return character is read. If this mode is disabled, the functions
> return when one or more characters are available.
The last phrase implies it waits???
(So still to wrap it w/ a PeekSomething or other query if want a
non-stalling getch() is my point/question/comment. Of course, maybe C
getch() does, too, I don't recall otomh????)
--
Yes, I'm a CVF devotee which is why I've never had do more than read the
SKD for this particular function... :)
--
Actually, the PDCurses library seems to work quite nicely with Fortran
(g95 and gfortran) on both Windows (in the console) and X11 (using their
XCurses library). Specifically, wgetch (since getch is implemented as a
macro "to avoid conflict with many DOS compiler's runtime libraries")
can be called to get and/or await a keypress. Writing to standard
output in the Windows console occurs at the location of cursor
after the move() command too.
Cheers, David Duffy.
--
| David Duffy (MBBS PhD) ,-_|\
| email: dav...@qimr.edu.au ph: INT+61+7+3362-0217 fax: -0101 / *
| Epidemiology Unit, Queensland Institute of Medical Research \_,-._/
| 300 Herston Rd, Brisbane, Queensland 4029, Australia GPG 4D0B994A v
I've played around with the GETCHARQQ() and PEEKCHARQQ() functions in
CVF that I have at work, and they work perfectly for what I'm doing,
but I'm using G95 at home, where I need to compile this program.
I'm not an expert with Fortran by any means, so I'm sorry if I've
confused some of what's been said here previously, but it seems like
all I need is something like the aforementioned READCONSOLE command.
Is this something I can do using g95?
nuclear.wing...@gmail.com wrote:
> I've been searching around the message board for information on a "Get
> Key" function for Fortran - the ability to have a program read input
> from a keyboard without having to push enter - and I've found a few
> posts that explain the difficulty of this. However, the posts I could
> find were at least a decade old, some older than that.
>
> Have there been any recent developments (or tricks) that would allow
> for input that doesn't require pressing the return key? If it helps,
> I'm using g95.
>
> Thanks!
This is how I do it using DVF. It uses the non-standard PEEK function.
The function waits for a key if IWAIT equals zero, and tests for a key
if IWAIT is not zero.
A zero word return means no key had been pressed.
This is part of the freely-available TUI screen and keyboard controls
function set.
The use of integer*2 is to accomodate the two bytes returned; the high
order byte is the key number; the lower order byte is the value of the
key symbol.
If the low order byte is #00 or #E0, the high order byte indicates a
function or pad key.
All is as per the standard MSDOS key and symbol assigment...
INTEGER*2 FUNCTION SCR_INPUTC(IWAIT)
! tests or waits for any keystroke, returns key code or zero
USE DFWIN
! GETS OR WAITS NEXT INPUT CHARACTER
IMPLICIT NONE
INTEGER*2,INTENT(IN) :: IWAIT
! KERN32 FUNCTIONS ICHAR,PEEKCHARQQ,GETCHARQQ
INTEGER*2 :: ICHAR
LOGICAL*4 :: PEEKCHARQQ
CHARACTER*1 :: GETCHARQQ
IF (IWAIT.NE.0) THEN
! TEST KEY
SCR_INPUTC=0
IF (.NOT.PEEKCHARQQ()) RETURN
END IF
! WAIT ON KEY
SCR_INPUTC=ICHAR(GETCHARQQ())
IF (SCR_INPUTC.EQ.#E0) SCR_INPUTC=0
IF (SCR_INPUTC.EQ.0) SCR_INPUTC=ISHFT(ICHAR(GETCHARQQ()),8)
END FUNCTION SCR_INPUTC
There you're out of my cognizance but I'm sure somebody will chime in...
I've seen notes before that there may be "issues" w/ getting g95 to
generate proper calling sequence for the Win32 API so you'll need a way
around that.
--
In order to be safe, it's probably best to write a cdecl C wrapper
function that calls the Windows API function. You can use bind(c) on
the wrapper function without any issues, and C knows how to handle
stdcall at least semi-consistently.
> I've seen notes before that there may be "issues" w/ getting g95 to
> generate proper calling sequence for the Win32 API so you'll need a way
> around that.
The issue with g95 is that you have to change the calling convention
for the whole application to stdcall just to invoke one procedure
with that convention. The problem with gfortran is more acute in
that it doesn't even let you emit the correctly mangled name of the
procedure you want to call. These problems are only present in 32-
bit Windows but there are other difficulties in 64-bit Windows: g95
doesn't compile to 64-bit Windows and gfortran has difficulty building
a 64-bit Windows compiler. As a consequence there are classes of
bugs that exist on available builds of gfortran for 64-bit Waindows
that are not a problem on other platforms.
Maybe my information above is a little out of date but I haven't
seen any announcements to the contrary.
--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end
Actually, that's closer to what I got to thinking...assuming the
corresponding C runtime has getch(), just write the wrapper function to
link w/ it and let it handle the OS call automagically.
--
It is not quite finished -- I need to understand how to interface to the
curses equivalents of print and scan, fix up colours and mouse handling
-- but most of the "testcurs" program now works in Fortran.
You can find it at:
http://www.qimr.edu.au/davidD/index.html#misc