Multikey Single Key Press

Post your FreeBASIC tips and tricks here. Please don’t post your code without including an explanation.
vdecampo
Posts: 2982
Joined: Aug 07, 2007 23:20
Location: Maryland, USA
Contact:

Multikey Single Key Press

Postby vdecampo » Jan 14, 2008 15:44

Many times in my games I want to act on a single key press. Multikey returns -1 constantly if a key is down and that isn't always what I want so I created this function which uses multikey but will only return -1 once for a particular key. The user must release and press the key again for it to fire.

Call it just like Multikey....

If KeyPress(SC_ESC)=-1 then .....

Code: Select all

Function KeyPress(Key As Integer) As Integer
Static LastKey(255) As Integer

   If MultiKey(Key) = -1 Then
      If Key = LastKey(Key) Then
         Return (0)
      Else
         LastKey(Key)=Key
         Return (-1)
      EndIf
   Else
      LastKey(Key)=0
      Return (0)
   End If

End Function


This saves you from having to create separate flags to remember if a key was pressed.

Hope someone finds this useful....

Cheers!
-Vince
Sisophon2001
Posts: 1704
Joined: May 27, 2005 6:34
Location: Cambodia, Thailand, Lao, Ireland etc.
Contact:

Postby Sisophon2001 » Jan 15, 2008 11:51

I like the simplicity.

Garvan
redcrab
Posts: 619
Joined: Feb 07, 2006 15:29
Location: France / Luxemburg
Contact:

Postby redcrab » Jan 15, 2008 12:12

May be a good complementary of this Tip http://www.freebasic.net/forum/viewtopic.php?t=4125

nice work
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:

Postby KristopherWindsor » Jun 10, 2009 7:03

Couldn't the code be shortened?

Code: Select all

Function KeyPress(Key As Integer) As Integer
  Static LastKey(255) As Integer
  function = (multikey(key) and not lastkey(key))
  lastkey(key) = multikey(key)
End Function
vdecampo
Posts: 2982
Joined: Aug 07, 2007 23:20
Location: Maryland, USA
Contact:

Postby vdecampo » Jun 10, 2009 13:31

I'm not sure if its me or my computer but your version doesn't seem as responsive. When I test them both, your version seems to miss presses if they come too fast. I really don't have a good non-subjective way to test the responsiveness.

**Maybe because you call MultiKey twice?

Here is the code I used...

Code: Select all

#Include "fbgfx.bi"

'Function KeyPress(Key As Integer) As Integer
'  Static LastKey(255) As Integer
'  Function = (multikey(Key) And Not lastkey(Key))
'  lastkey(Key) = multikey(Key)
'End Function
 
Function KeyPress(Key As Integer) As Integer
Static LastKey(255) As Integer

        If MultiKey(Key) = -1 Then
                If Key = LastKey(Key) Then
                        Return (0)
                Else
                        LastKey(Key)=Key
                        Return (-1)
                Endif
        Else
                LastKey(Key)=0
                Return (0)
        End If

End Function
 
Do
   If KeyPress(FB.SC_UP) Then
      Print "UP pressed..."
   EndIf
   
Loop Until InKey=Chr(27)


-Vince
BasicScience
Posts: 489
Joined: Apr 18, 2008 4:09
Location: Los Angeles, CA
Contact:

Postby BasicScience » Jun 11, 2009 0:18

One limitation of the MultiKey approach is that if the CPU is off doing something else when the key is struck/released, then multikey will not detect the event (missed events problem).

I tried writing a variant to "never miss a keyboard event" by using InKey to check the status of the keyboard buffer. It works fine... provided there is some delay in the loop (see SLEEP statement), but goofs up if the sleep is omitted in that a constantly pressed key is reported multiple times.

Thoughts???

Code: Select all

#Include "fbgfx.bi"

'Function KeyPress(Key As Integer) As Integer
'  Static LastKey(255) As Integer
'  Function = (multikey(Key) And Not lastkey(Key))
'  lastkey(Key) = multikey(Key)
'End Function
 
Function KeyPress(Key As Integer) As Integer
Static LastKey(255) As Integer

        If MultiKey(Key) = -1 Then
                If Key = LastKey(Key) Then
                        Return (0)
                Else
                        LastKey(Key)=Key
                        Return (-1)
                Endif
        Else
                LastKey(Key)=0
                Return (0)
        End If

End Function


Function KeyInput() as string
Static lastkey as string
Dim as string key
    Key = inkey
    IF Key <> "" then
        IF key = lastkey then
            Return ""
        else
            Lastkey = key
            Return Key
        end if
    else
        Lastkey = ""  'PROBLEM IS HERE!!!
        Return ""
    END IF
   
END Function


Dim as string Response

do until inkey = "" : loop

Do
   
   
 '  If KeyPress(FB.SC_UP) Then
 '    Print "UP pressed..."
 ' Endif
   
   Response = KeyInput
   if Response <> "" then
       IF Response = Chr(27) then
           exit do
        else
            print Response
        end if
   end if
   
   sleep (500,1) ' will you miss keypress?
   
Loop 'Until Inkey=Chr(27)
 
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:

Postby KristopherWindsor » Jun 11, 2009 2:04

@BasicScience

Don't you just want Inkey() instead of some custom function?

vdecampo wrote:**Maybe because you call MultiKey twice?


You could store the result from Multikey() to a variable, then read the variable twice. Aside from calling Multikey() twice, my function is logically equivalent to yours.
BasicScience
Posts: 489
Joined: Apr 18, 2008 4:09
Location: Los Angeles, CA
Contact:

Postby BasicScience » Jun 11, 2009 3:35

@KW You need to do something more sophisticated than Inkey() alone... if you want to avoid the problem of responding multiple times because a key was held down.
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:

Postby KristopherWindsor » Jun 11, 2009 5:43

Then why not just use this keypress function? You can't do that with Inkey. If you call the function frequently enough, it won't miss quick presses.
1000101
Posts: 2556
Joined: Jun 13, 2005 23:14
Location: SK, Canada

Postby 1000101 » Jun 11, 2009 5:47

Alternately, wait for the key release event.
BasicScience
Posts: 489
Joined: Apr 18, 2008 4:09
Location: Los Angeles, CA
Contact:

Postby BasicScience » Jun 11, 2009 6:21

@KW Well... the crucial feature here is the call KeyPress "frequently enough".

For my particular application, I have A/D data acquisition routines that may go off and sample at 20 KHz for 2 sec or even longer. The routine will loop-back and acquire another 2 sec of data... unless a key has been pressed. Polling with Keypress cannot be done during the 2 sec acquisition routine (CPU busy doing other timing-critical stuff). Instead, what you want is a failsafe way to determine if a key was struck while the CPU was off in the acquisition routine. Using the Keyboard Buffer is clearly the solution here.
VirusEcks
Posts: 9
Joined: Jun 08, 2009 20:41
Contact:

Postby VirusEcks » Jun 11, 2009 9:04

may i suggest a free thread (Createthread or threadcreate functions)
with a boolean or integer value

and during the loop of data

if DIE = true or if DIE = 1 then
exit function

simple but effective
tinram
Posts: 88
Joined: Nov 30, 2006 13:35
Location: UK

Postby tinram » Jun 16, 2009 18:53

This sorted a key press issue I had when using a constantly updated screen.
Thank you Vince.
kiyotewolf
Posts: 1009
Joined: Oct 11, 2008 7:42
Location: ABQ, NM
Contact:

idea

Postby kiyotewolf » Jun 17, 2009 6:39

Has anyone tried pointing the keyboard buffer to itself to erase it? Maybe that will help with the flags getting all confused like they are.

I haven't checked into how to convert this into FB yet.

DEF SEG=&H40
POKE &H1A,PEEK(&H1C)

Most multikey-press routines use this. Maybe if you put it in there somewheres..



Kiyote!
kiyotewolf
Posts: 1009
Joined: Oct 11, 2008 7:42
Location: ABQ, NM
Contact:

prying deep into windows

Postby kiyotewolf » Jul 11, 2009 11:58

I've been attempting what the compiler dubs, suspicious pointer assignments.

I managed to almost get the PEEK & POKE commands to aim their lazers at the POSSIBLE address of the keyboard buffer, but my results were inconclusive.

I have to do more testing, like running a 320x200x256 screen concurrently with this type of code operations to see if I can really tap into system memory at the lowest level this way.

I also know there is a byte shift when you address the memory by segment of 8 bits in one direction after you re-calculate the address, so I'm also fighting that unknown in the correct way to do it.

I'm having fun going nuts with this at the very least.

I'm so ""Doc Brown right now it's not even funny. I even have goggles I wear ALL THE TIME now.



Kiyote!

Return to “Tips and Tricks”

Who is online

Users browsing this forum: No registered users and 1 guest