INKEY$ is one of several methods to communicate with the keyboard. Others are _KEYHIT, _KEYDOWN, INP(), PEEK and POKE, and for Windows users, the function GetAsyncKeyState%.
So why is INKEY$ so much better than those other choices, why because I code with it, of course!
Well, my comedy bit aside, INKEY$ is comfortable for me because it has easily recognized key associations, by string representation of ASCII values.
Terminate loop with the Esc key example...
Since INKEY$ functions as a string, unlike the other alternatives, we need recognize a string is true or false by being either filled or null.
Terminate loop with press almost any key...
I find the best way to set up a keyboard poll routine is by assigning a variable to INKEY$...
"...press almost any key." WTH is that???
Well, INKEY$ does not register for certain keys like...
Shift
Ctrl
Alt
Fn
Windows key
PrtScr
NumLock
Capslock
These keys need to be referenced in some other either supportive method or via a different key recognition keyword like _KEYDOWN.
An "old school" method I love, and successfully lobbied for 15+ years ago, is the supportive method of using PEEK addresses.
This routine identifies if Alt, Ctrl, or Shift keys are held down while other keys are pressed...
Cool, right? Well, not so fast there Sparky, there is a drawback. We can only read 3 key inputs at a time. Hold Shift + Ctrl + Alt then press "A" and just like I stated, the 4th input, "A" won't get printed. INP() won't help here either, and interestingly enough, although _KEYHIT and _KEYDOWN can handle most 3 key combinations, I noted some arrow combos and others were not registered when trying to get that technique to work. WinAPI can recognize some but not all 4+ multiple key presses. Fool around with some keys in this example if you have a Windows System. Hold Shift+Ctrl+Alt and try some arrow keys etc to see which ones show up for INKEY$. Some will, some won't, but those are all 4 key press events with this INKEY$ helper.
The only key I set to register in the alphabet is "A" so try Shift+Ctrl+Alt+A to see them all register. Oh, if you fooled with the code to try and get A+B+C+D to register, it would only register A+B+C.
So what else can we say about INKEY$? Well, it can be used in combination with other keyboard keywords. Maybe not good practice, but just saying it's workable.
INKEY$ stores key presses in a buffer. You can use _KEYCLEAR to clear that buffer. Some programs need this to stop users who press keys during a program pause from being used in the routine. SLEEP is actually a very simple example...
A bit more involved example of the buffer uses a delay to slow the typing output to the screen. With the buffer, Demo 1, the output catches up after you are done fast typing. In demo 2, _KEYCLEAR clears the buffer and the utput stops the moment the user stops fast typing.
On a final note, my beloved INKEY$, as stated previously, can't do everything. For instance say you want to use Ctrl + and Ctrl - to resize text, just like browsers. Well, we can't do that with INKEY$, but we can use _KEYHIT or Win32 API. An example of each is provided here: https://qb64phoenix.com/forum/showthread.php?tid=1230
Pete
So why is INKEY$ so much better than those other choices, why because I code with it, of course!
Well, my comedy bit aside, INKEY$ is comfortable for me because it has easily recognized key associations, by string representation of ASCII values.
Terminate loop with the Esc key example...
Code: (Select All)
DO
_LIMIT 30
LOOP UNTIL INKEY$ = CHR$(27) ' The string character for ASCII code 27.
Since INKEY$ functions as a string, unlike the other alternatives, we need recognize a string is true or false by being either filled or null.
Terminate loop with press almost any key...
Code: (Select All)
DO
_LIMIT 30
LOOP UNTIL LEN(INKEY$) ' Loop exits when INKEY$ is no longer null, (e.g. INKEY$ = "").
I find the best way to set up a keyboard poll routine is by assigning a variable to INKEY$...
Code: (Select All)
DO
_LIMIT 30
mykey$ = INKEY$
IF LEN(mykey$) THEN
SELECT CASE mykey$
CASE CHR$(27)
PRINT " INKEY$ CODE: CHR$(27)"
EXIT DO ' Escape loop to end program snippet.
CASE ELSE
show_Values (mykey$)
END SELECT
END IF
LOOP
SUB show_Values (mykey$)
SELECT CASE LEN(mykey$)
CASE 1
b = ASC(mykey$) ' ASC() converts a string character to a numeric value.
a$ = ""
CASE 2
b = ASC(MID$(mykey$, 2, 1))
a$ = "CHR$(0)" ' This is the nul character INKEY$ reports for 2 byte length key representation like the F1 - F12 keys.
END SELECT
b$ = LTRIM$(STR$(b)) ' This is how you convert a numeric variable to a string variable.
PRINT " INKEY$ CODE: ";
IF LEN(a$) THEN PRINT a$; " + ";
PRINT "CHR$("; b$; ") "; "AKA: " + CHR$(34) + CHR$(b) + CHR$(34) + " ";
END SUB
"...press almost any key." WTH is that???
Well, INKEY$ does not register for certain keys like...
Shift
Ctrl
Alt
Fn
Windows key
PrtScr
NumLock
Capslock
These keys need to be referenced in some other either supportive method or via a different key recognition keyword like _KEYDOWN.
An "old school" method I love, and successfully lobbied for 15+ years ago, is the supportive method of using PEEK addresses.
This routine identifies if Alt, Ctrl, or Shift keys are held down while other keys are pressed...
Code: (Select All)
_CONTROLCHR OFF ' Allows us to key input combinations that would otherwise adversely affect screen output.
DO
_LIMIT 30
DEF SEG = 0
IF PEEK(1047) MOD 16 = 1 OR PEEK(1047) MOD 16 = 2 THEN
KeyCombos = 1 ' Shift
ELSEIF PEEK(1047) MOD 16 = 3 OR PEEK(1047) MOD 16 = 4 THEN
KeyCombos = 2 ' Ctrl
ELSEIF PEEK(1047) MOD 16 = 5 OR PEEK(1047) MOD 16 = 6 THEN
KeyCombos = 3 ' Ctrl+Shift
ELSEIF PEEK(1047) MOD 16 = 7 OR PEEK(1047) MOD 16 = 8 THEN
KeyCombos = 4 ' Alt
ELSEIF PEEK(1047) MOD 16 = 9 OR PEEK(1047) MOD 16 = 10 THEN
KeyCombos = 5 ' Shift+Alt
ELSEIF PEEK(1047) MOD 16 = 12 THEN
KeyCombos = 6 ' Ctrl+Alt
ELSEIF PEEK(1047) MOD 16 = 14 THEN
KeyCombos = 7 ' Shift+Ctrl+Alt
ELSE
KeyCombos = 0
END IF
DEF SEG
mykey$ = INKEY$
IF LEN(mykey$) OR KeyCombos THEN
SELECT CASE mykey$
CASE CHR$(27)
PRINT " INKEY$ CODE: CHR$(27)"
EXIT DO ' Escape loop to end program snippet.
END SELECT
show_Values mykey$, KeyCombos
END IF
LOOP
SUB show_Values (mykey$, KeyCombos)
STATIC OldKeyCombos
IF KeyCombos = OldKeyCombos AND LEN(mykey$) = 0 THEN EXIT SUB ' Neat trick to only print once to screen while PEEK discovered keys are held down.
DO ' Falx loop to avoid printing INKEY printing if only a non-INKEY$ is held down.
SELECT CASE LEN(mykey$)
CASE 0
EXIT DO
CASE 1
b = ASC(mykey$) ' ASC() converts a string character to a numeric value.
a$ = ""
CASE 2
b = ASC(MID$(mykey$, 2, 1))
a$ = "CHR$(0)" ' This is the nul character INKEY$ reports for 2 byte length key representation like the F1 - F12 keys.
END SELECT
b$ = LTRIM$(STR$(b)) ' This is how you convert a numeric variable to a string variable.
PRINT " INKEY$ CODE: ";
IF LEN(a$) THEN PRINT a$; " + ";
PRINT "CHR$("; b$; ") "; "AKA: " + CHR$(34) + CHR$(b) + CHR$(34) + " ";
EXIT DO
LOOP
IF KeyCombos THEN
SELECT CASE KeyCombos
CASE 1
PRINT " Shift Down";
CASE 2
PRINT " Crtl Down";
CASE 3
PRINT " Shift + Ctrl Down";
CASE 4
PRINT " Alt Down";
CASE 5
PRINT " Shift + Alt Down";
CASE 6
PRINT " Ctrl + Alt Down";
CASE 7
PRINT " Shift + Ctrl + Alt Down";
END SELECT
OldKeyCombos = KeyCombos
END IF
PRINT
END SUB
Cool, right? Well, not so fast there Sparky, there is a drawback. We can only read 3 key inputs at a time. Hold Shift + Ctrl + Alt then press "A" and just like I stated, the 4th input, "A" won't get printed. INP() won't help here either, and interestingly enough, although _KEYHIT and _KEYDOWN can handle most 3 key combinations, I noted some arrow combos and others were not registered when trying to get that technique to work. WinAPI can recognize some but not all 4+ multiple key presses. Fool around with some keys in this example if you have a Windows System. Hold Shift+Ctrl+Alt and try some arrow keys etc to see which ones show up for INKEY$. Some will, some won't, but those are all 4 key press events with this INKEY$ helper.
The only key I set to register in the alphabet is "A" so try Shift+Ctrl+Alt+A to see them all register. Oh, if you fooled with the code to try and get A+B+C+D to register, it would only register A+B+C.
Code: (Select All)
CONST VK_SHIFT = &H10 'SHIFT key
CONST VK_CONTROL = &H11 'CTRL key
CONST VK_MENU = &H12 'ALT key
DECLARE DYNAMIC LIBRARY "User32"
FUNCTION GetAsyncKeyState% (BYVAL vkey AS LONG)
END DECLARE
DO
_LIMIT 30
a% = GetAsyncKeyState%(VK_SHIFT)
b% = GetAsyncKeyState%(VK_CONTROL)
c% = GetAsyncKeyState%(VK_MENU)
d% = GetAsyncKeyState%(&H41)
SELECT CASE a%
CASE 0
CASE ELSE
PRINT a%
END SELECT
PRINT a%, b%, c%, d%, INKEY$
LOOP
So what else can we say about INKEY$? Well, it can be used in combination with other keyboard keywords. Maybe not good practice, but just saying it's workable.
INKEY$ stores key presses in a buffer. You can use _KEYCLEAR to clear that buffer. Some programs need this to stop users who press keys during a program pause from being used in the routine. SLEEP is actually a very simple example...
Code: (Select All)
SLEEP
IF LEN(INKEY$) THEN BEEP ' Will Beep
SLEEP
_KEYCLEAR
IF LEN(INKEY$) THEN BEEP ' Won't beep.
A bit more involved example of the buffer uses a delay to slow the typing output to the screen. With the buffer, Demo 1, the output catches up after you are done fast typing. In demo 2, _KEYCLEAR clears the buffer and the utput stops the moment the user stops fast typing.
Code: (Select All)
PRINT "Demo 1: Buffer will catch up to your typing. Press Es when ready for demo 2..": PRINT
LOCATE , , 1 ' Let's show the cursor for these typing demos...
' That third LOCATE parameter of 1 gives us the underline stype cursor.
' See the LOCATE Keyword of the Day for other cursor appearance options).
DO
_LIMIT 30
mykey$ = INKEY$
IF LEN(mykey$) OR KeyCombos THEN
SELECT CASE mykey$
CASE CHR$(27)
EXIT DO
CASE ELSE
IF LEN(mykey$) = 1 THEN
PRINT mykey$;
_DELAY .25
END IF
END SELECT
END IF
LOOP
PRINT: PRINT: PRINT "Okay, demo two. The printing to the screen stops the moment you stop typing.": PRINT
DO
_LIMIT 30
mykey$ = INKEY$
IF LEN(mykey$) OR KeyCombos THEN
SELECT CASE mykey$
CASE CHR$(27)
EXIT DO
CASE ELSE
IF LEN(mykey$) = 1 THEN
PRINT mykey$;
_KEYCLEAR
_DELAY .25
END IF
END SELECT
END IF
LOOP
On a final note, my beloved INKEY$, as stated previously, can't do everything. For instance say you want to use Ctrl + and Ctrl - to resize text, just like browsers. Well, we can't do that with INKEY$, but we can use _KEYHIT or Win32 API. An example of each is provided here: https://qb64phoenix.com/forum/showthread.php?tid=1230
Pete