KeyDown with Select/case?

BlitzMax Forums/BlitzMax Beginners Area/KeyDown with Select/case?

Galdy(Posted 2015) [#1]
Is there some way to use keydown with select/Case ?
Select KeyDown()
Case Key_num1
endselect

...which doesn't work.


Casaber(Posted 2015) [#2]
Yup, this is a nice trick to know, you assume true in the Select.


Select True 
Case KeyDown(Key_num1)
Case KeyDown(Key_num2)
EndSelect




Galdy(Posted 2015) [#3]
Perfect. Thank you.


Ian Caio(Posted 2016) [#4]
Isn't it easier (and faster) to use GetChar()?

Like:
Select GetChar()
Case Asc("1")
...


I might be wrong but I think if you put KeyDown() on each Case it will run the KeyDown() function several times, maybe making the program a little slower.
Using GetChar(), you would run the function only once and then compare its results with the ASCII codes.

I might be wrong though, still a beginner with BlitzMax!

PS: As I was writing it, it came to me that Select/Case could work as a cascate If/ElseIf/ElseIf block. That way, when a KeyDown() was found true, none of the ones below it would be tested. However the function KeyDown() would still be called repeatedly until the one that returns True was found. I believe GetChar() could do the work in a better fashioned way there.


dw817(Posted 2016) [#5]
Hi Ian. Yes, it is easier. But you get different results.

GetChar() retrieves a keystroke and you must hold the key down for a moment before it repeats. With KeyDown() you can scan any key from the keyboard and it returns if the key is DOWN.

Here's a little sample code to explain. Tweak it if you like if it'll help you to see what's going on.
Graphics 768,576

x=384

' Typ=0 for RAW keypress
' Typ=1 for standard keypress
Typ=0

Repeat
  Cls
  DrawOval x-16,272,32,32
  If typ=0
    If KeyDown(Asc("1"))Then x:-2
    If KeyDown(Asc("2"))Then x:+3
  Else
    Select GetChar()
      Case Asc("1") x:-2
      Case Asc("2") x:+3
    EndSelect
  EndIf
  Flip
Until KeyDown(27)
Notice how if you hold BOTH keys down with Typ=0 that the circle STILL moves a little to the right. What's happening here ?

With KeyDown() you can register MULTIPLE keys being held down at the same time. With GetChar(), you do not. Try it and see !


Ian Caio(Posted 2016) [#6]
Thanks dw817!
You're right, what a rookie mistake I did!
Was thinking so much about making the code faster I didn't realize the whole point of each command.

Guess the only way to make it a little more efficient would be list the KeyDown() checks in order of the Key most likely to be pressed to the less likely to be pressed (for example, WASD in the top on a FPS game). That way it would run the KeyDown() checks less times.

But thinking about it, it's too much trouble for something that probably just consume a tiny processing time!


Brucey(Posted 2016) [#7]
Or you could attach yourself to the Event system, and process keydown/keyup events yourself.
Polling lots of KeyDowns() is expensive, as internally it does an actual system poll on each call (With the standard BlitzMax modules there's no way to disable the polling, so it does much more work than is necessary)

If you have a look at the PolledInput module, you will see how the standard BlitzMax event system catches key and mouse events, and stores the values in arrays.
You can add your own event hook and process them more efficiently than making lots and lots of keydown/keyup function calls.

There are many ways to skin a cat...


Bobysait(Posted 2016) [#8]
With this kind of structur, you can track keys without the needs for multiple system poll

graphics 800,600,0,0

global _keysD:Int[] = new int[256]; ' KeyDown
global _keysH:int[] = new int[256]; ' KeyHit
global _keysR:int[] = new int[256]; ' KeyReleased

local kd:int = 0;
local MyKey:int = KEY_SCAPE;

function kDown:byte(k:int)
   return _keysD[k]>0;
End function

function kHit:int(k:int)
   local n:int = _keysH[k]; _keysH[k]=0; return n;
End function

function kRel:int(k:int)
   local n:int = _keysR[k]; _keysR[k]=0; return n;
End function

Local x:Float = 400, y:Float=300;

repeat
   
   while pollevent()
      select eventId()
         case EVENT_KEYDOWN ;
            if _keysD[eventData()]=0 then _keysH[eventData()]:+1;
            _keysD[eventData()]=1;
         case EVENT_KEYUP ; If eventData() = Mykey Then kd=1;
            if _keysD[eventData()]=1 then _keysR[eventData()]:+1;
            _keysD[eventData()]=0;
      end select;
   wend;
   
   x:+ kdown(KEY_RIGHT)-kdown(KEY_LEFT);
   y:- kdown(KEY_UP)-kdown(KEY_DOWN);
   
   cls;
   drawrect x-2,y-2,5,5
   flip (true);
   
until kdown(KEY_ESCAPE);




dw817(Posted 2016) [#9]
No problem, Ian. Glad to help ! :) Usage of GetChar() really is the easiest way to retrieve a standard keystroke.

If you want to WAIT for the keystroke, you can use the command WaitChar() instead. Also GetChar() will recognize NUM-LOCK, CAPS-LOCK, Shift Key, and Ctrl Key strokes.

KeyDown() can only scan the single key in question.

Here are the raw keystrokes from BlitzMAX HELP source:



So instead of KeyDown(27) to look for the ESCAPE key, you can use any of the Global Constants values provided above and make your code more legible - with KeyDown(KEY_ESCAPE).


Ian Caio(Posted 2016) [#10]
Always good to learn better ways to do the same thing!

Bobysait,
I guess I understood your code: You check every event on the poll list using PollEvent() function, that returns an TEvent object to a global (CurrentEvent). Using EventID(), you identify if the event stored on CurrentEvent is a KeyDown or KeyUp and do whatever changes you need to do on your states arrays.

I just have a few questions:
-I just looked recently about the underline usage on variables names. Is it used just to reserve this name for this particular variable? Since it is a global variable, it would avoid any name conflicts if you had a local variable with the same name somewhere else. The compiler would then alert you about any place using the reserved name?

-I didn't understand the usage of the MyKey and Kd on this code. It just seems like if you release the Escape key Kd will be 1. By the way, KEY_UP event only happen when you release a key that was previously pressed right?

But I get the whole idea, a much more efficient way of doing key states checks!

I liked how a simple Select question turned into this more profound analysis


Bobysait(Posted 2016) [#11]
The underline is just a basic convention to mark a variable as "private" wether or not it is accessible. It actually doesn't affect anything and the compiler don't care of it and treat it as a usual variable.
It's just a convenience to remember the variable should not be used and is reserved to internal stuff.


-I didn't understand the usage of the MyKey and Kd on this code.



If eventData() = Mykey Then kd=1;

Sorry about this, it's just a mistake. I didn't compile the code and coded it directly in the codebox from the forum ...
I wa thinking about making a small sample with usage of "MyKey" but totally forgot about it :)


By the way, KEY_UP event only happen when you release a key that was previously pressed right?


Exactly ! ... well ... if you mean "EVENT_KEYUP"
because "KEY_UP" is a constant storing the code of the "Up arrow" key.