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.
On May 1, 2009, at 10:51 AM, nuclear wingnut 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!
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:
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.
> 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:
It is not standard C either, but it is a more common extension in C libraries than Fortran libraries.
> On May 1, 2009, at 10:51 AM, nuclear wingnut 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.
> (snip)
> 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.
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.
On May 1, 2009, at 1:09 PM, glen herrmannsfeldt wrote:
> Jason Blevins <jrble...@sdf.lonestar.org> wrote: > (snip)
>> 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:
> It is not standard C either, but it is a more common extension > in C libraries than Fortran libraries.
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.
>On May 1, 2009, at 12:41 PM, Jason Blevins wrote: >> On May 1, 2009, at 10:51 AM, nuclear wingnut 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.
>> (snip)
>> 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.
>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
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
>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.
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 wrote: >> 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.
> 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.
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).
>>> 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.
>> 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.
> 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.
In message <87zldw6ajc....@roark.xbeta.org>, Jason Blevins <jrble...@sdf.lonestar.org> writes
>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/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.
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 wrote: > In message <87zldw6ajc....@roark.xbeta.org>, Jason Blevins > <jrble...@sdf.lonestar.org> writes >> 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:
> 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.
> 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.
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.
In message <gtk61k$6a...@news.motzarella.org>, user1 <us...@example.net> writes
>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.
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.
Gary Scott wrote: > Craig Powers wrote: >> Clive Page wrote:
>>>> 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.
>>> 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.
>> 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.
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.
> 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.
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).
dpb wrote: > Clive Page wrote: > ... >> That's sounds a good explanation. But I still don't quite know why >> this is needed for the single keystroke routine to work. > ... > Because w/o a console there's not a keyboard input only a Windows > messages queue created.
In which case you would check for a WM_CHAR message in your message processing loop ...
user1 wrote: > dpb wrote: >> Clive Page wrote: >> ... >>> That's sounds a good explanation. But I still don't quite know why >>> this is needed for the single keystroke routine to work. >> ... >> Because w/o a console there's not a keyboard input only a Windows >> messages queue created.
> 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.
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.
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.
> user1 wrote: > > dpb wrote: > >> Clive Page wrote: > >> ... > >>> That's sounds a good explanation. But I still don't quite know why > >>> this is needed for the single keystroke routine to work. > >> ... > >> Because w/o a console there's not a keyboard input only a Windows > >> messages queue created.
> > 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.
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.
GaryScott wrote: > On May 4, 1:49 pm, dpb <n...@non.net> wrote: >> user1 wrote: >>> dpb wrote: >>>> Clive Page wrote: >>>> ... >>>>> That's sounds a good explanation. But I still don't quite know why >>>>> this is needed for the single keystroke routine to work. >>>> ... >>>> Because w/o a console there's not a keyboard input only a Windows >>>> messages queue created. >>> 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.
> Actually it does have a normal message processing loop, its just > hidden from you. But you can snoop on it.
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.
> GaryScott wrote: > > On May 4, 1:49 pm, dpb <n...@non.net> wrote: > >> user1 wrote: > >>> dpb wrote: > >>>> Clive Page wrote: > >>>> ... > >>>>> That's sounds a good explanation. But I still don't quite know why > >>>>> this is needed for the single keystroke routine to work. > >>>> ... > >>>> Because w/o a console there's not a keyboard input only a Windows > >>>> messages queue created. > >>> 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.
> > Actually it does have a normal message processing loop, its just > > hidden from you. But you can snoop on it.
> 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.
> -- > Jugoslavwww.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? ).
On windows, CVF has some built-in functions that work for console mode applications. I would guess that IVF has something similar.
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
> GaryScott wrote: > > On May 4, 1:49 pm, dpb <n...@non.net> wrote: > >> user1 wrote: > >>> dpb wrote: > >>>> Clive Page wrote: > >>>> ... > >>>>> That's sounds a good explanation. But I still don't quite know why > >>>>> this is needed for the single keystroke routine to work. > >>>> ... > >>>> Because w/o a console there's not a keyboard input only a Windows > >>>> messages queue created. > >>> 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.
> > Actually it does have a normal message processing loop, its just > > hidden from you. But you can snoop on it.
> 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.
It is quite easy to use the following to get the window handle:
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.
GaryScott wrote: > On May 5, 2:51 am, Jugoslav Dujic <jdu...@yahoo.com> wrote: >> GaryScott wrote: >>> On May 4, 1:49 pm, dpb <n...@non.net> wrote: >>>> user1 wrote: >>>>> dpb wrote: >>>>>> Clive Page wrote: >>>>>> ... >>>>>>> That's sounds a good explanation. But I still don't quite know why >>>>>>> this is needed for the single keystroke routine to work. >>>>>> ... >>>>>> Because w/o a console there's not a keyboard input only a Windows >>>>>> messages queue created. >>>>> 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. >>> Actually it does have a normal message processing loop, its just >>> hidden from you. But you can snoop on it. >> 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.
> It is quite easy to use the following to get the window handle:
> 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.
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 www.xeffort.com Please reply to the newsgroup. You can find my real e-mail on my home page above.
> 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.