Dark Bit Factory & Gravity
PROGRAMMING => Freebasic => Topic started by: Clyde on April 18, 2009
-
Im trying to get a keyboard library similar to the style of Blitz Basic, with using GetAsyncKeyState(Keycode) And 32768. And will try and put into words what should be happening.
Im using flushkeys to stop you being able to repeatedly hold whatever key is being pressed, so that once you've pressed that key it resets as if no key has been pressed, even if you are holding it down; aka Keyhit()
I would also like to add in, KeyDown() which lets you hold that key to your hearts desire.
Maybe there are other commands similar to GetASyncKeyState.
'
' Lib - Keyboard
' Version 1.0.0
'
Const KEYS_ON=0
Const KEYS_OFF=1
Dim Shared As Integer Keys=KEYS_ON, KeyDelay=450
Dim Shared As Single KeyboardTimer=0, RunningTime
Sub FlushKeys()
If ( KeyboardTimer + KeyDelay ) <= Millisecs( RunningTime ) Then
Keys=KEYS_ON
Else
Keys=KEYS_OFF
End if
End Sub
Function KeyHit( ByVal KeyChar As Integer ) As Integer
If Keys=KEYS_ON Then
If (GetAsyncKeyState(KeyChar) And -32768) Then
KeyboardTimer=Millisecs( RunningTime )
Return True
Else
Return False
End If
End If
End Function
Little example of how im calling stuff:
KeyboardTimer=millisecs( Timer )' i use a function to return timezed 1000, KeyboardTimer=Timer*1000'
While Keyhit(VK_Escape)<>True
ClearScreen()
RunningTime=Timer()
If Keyhit(VK_LButton)=True Then Show=Not Show
If Show Then
Print"Booooooooooo!!!!!!!!!!!!"
End if
FlushKeys()
Wend
Have a re-giggle, small favour please keep the time methods to being in millisecs just that its something im used to. Blame Blitz for that :D
Cheers and hope you can sort me out of my misery,
Clyde.
-
You need to set Keys=KEYS_OFF the moment you've read a key.
If Keys=KEYS_ON Then
If (GetAsyncKeyState(KeyChar) And -32768) Then
KeyboardTimer=Millisecs( RunningTime )
...
Keys = KEYS_OFF
...
Return True
Else
-
Thanks Jim, added that but It still wants to continue with the key being pressed. what it does, for example hold the leftmousebutton ( VK_LBUTTON ), and you'll witness it toggling between the state of when to print "Booo" ( or if you use it to do something else ) or not.
-
Take a look at the ScreenEvent function. It will tell you the current state of the keys, i.e. the current key values and the state of the mouse. In the case you mentioned, it will return EVENT_KEY_REPEAT when a key is repeated.
-
Cool dude, what inc is that in?
-
It is in fbgfx.bi in the namespace fb.
-
Cheers mate, Im hoping to avoid having to include the fbgfx stuff as it makes for bigger executable files. Perhaps this will give more of an insight into the key problem.
-
Ok, still no joys with this and i'd love to get it sorted, so I can move on to other things.
There must be something to empty out the keyboard buffer / poll events for Keyhit(), so somone cant hold the key down ;) you must of witnessed using (GetAsyncKeyState(KeyChar) And -32768) that it carries on regardless with the action applied to the the keys task.
Ive looked through the winuser.bi but havent seen anything to accomplish this; well anything that sticks out like a sore thumb. I know Jim did a readkeyboard sub in his Sidtest2, and that had a time delay before calling readkeyboard(); but that worked by not allowing if the song was allready selected.
I am using Freebasic and tinyptc_ext, so no gfxlib stuff please.
This is the key function stripped of any timer stuff; and just return true or false if a keyshit
Function KeyHit( ByVal KeyChar As Integer ) As Integer
If (GetAsyncKeyState(KeyChar) And -32768) Then
Return True
Else
Return False
End If
End Function
Thanks for your time and assistance,
Clyde.
-
There really aren't any more Windows functions for the keyboard, unless you go to use DirectInput, which I always found to be flakey.
The reason is that GetAsyncKeyState isn't what anyone uses for keyboard input in real applications. In Windows you would sit and wait for WM_KEYUP and WM_KEYDOWN messages in your Windows proc.
How I deal with it then is:
For each WM_KEYDOWN, set a value in an array for, ie. keys[pressed_key]=1
For each WM_KEYUP, clear a value in the array for, ie. keys[pressed_key]=0
Then when I want to know about keys I look in the array.
Of course, you can't do this with GetAsyncKeyState because it only reads one key at a time...
You want a key that won't repeat, right?
X_currently_pressed = false;
X_was_pressed = false;
...
Sub ReadKeyboard()
if GetAsyncKeyState('X') & -32768 then
if X_currently_pressed == true then
X_was_pressed = false
else
X_was_pressed = true
end if
X_currently_pressed = true;
else
X_currently_pressed = false;
X_was_pressed = false;
end if
End Sub
Now you call ReadKeyboard very regularly (each frame). If you want to know about X, then look at X_was_pressed to see if the key has gone down since the last time, and X_currently_pressed to see if it is down now.
Jim
-
Thanks Jim, I will make a test program to go with that.
What your recommending is that I'd be best of using something like inkey? I was avoiding this incase it pulled in and included the fbgfx lib stuff into tinyptc programs. Am I safe of this not happening, does anybody know?
Cheers once again,
Clyde.
-
A bit more background for you. The reason that Windows doesn't do this for you is because it's a multitasking OS. There's only one keyboard but lots of running applications. If they all flushed the keyboard no-one would see anything get pressed.
I doubt using Inkey is going to be any better or worse than GetAsyncKeyState. They do the same thing.
Jim
PS, I just edited my pseudo code above.
-
Here it is implemented in Blitz using KeyDown(45) instead of GetAsyncKeyState('X')AND-32768
Global X_currently_pressed = False
Global X_was_pressed = False
Repeat
Flip
Cls
ReadKeyboard()
Locate 0,0
Print "Down="+X_was_pressed+" Held="+X_currently_pressed
If X_was_pressed Then z=z+1
Print z
Until KeyDown(1)
End
Function ReadKeyboard()
If KeyDown(45) Then
If X_currently_pressed = True Then
X_was_pressed = False
Else
X_was_pressed = True
End If
X_currently_pressed = True
Else
X_currently_pressed = False
X_was_pressed = False
End If
End Function
-
The correct way to do that is checking the value returned by GetAsyncKeyState function and you don't need to use "AND" operator. The correct value to check is -32767 and not -32768
Check out the example below, it works fine :)
'
' Lib - Keyboard
' Version 1.0.0
'
#Include Once "Windows.bi"
dim shared Show as integer
Function KeyHit( ByVal KeyChar As Integer ) As Integer
If (GetAsyncKeyState(KeyChar) = -32767) Then
Return True
Else
Return False
End If
End Function
While Keyhit(VK_Escape)<>True
If Keyhit(VK_LButton)=True Then
Show=True
else
Show=False
end if
If Show=True Then
Print"cracked by rbz :)"
End if
Wend
-
You're not supposed to use bit 1 of the result of GetAsyncKeyState under Win32. If two applications are using that function then who gets the 'has it changed since last time' bit is random.
http://msdn.microsoft.com/en-us/library/ms646293(VS.85).aspx (http://msdn.microsoft.com/en-us/library/ms646293(VS.85).aspx)
It'll probably work :). Then not work. :P Then work again :)
Jim
-
Thankyou both, really appreciate it. 8)