Log In  

Cart #20709 | 2016-05-17 | Code ▽ | Embed ▽ | No License
22

Perhaps this is going to be useful for someone. This is a little keyboard handler I'm using in my code. It extends the functionality of the standard btn(k) function with detection of the onset of the key and its release. Sometimes it's useful to have those two and avoid btnp(k) repetition.

-- is_held(k) is true if the key k is held down
-- is_pressed(k) is true if the key has just been pressed by the user
-- is_released(k) is true if the key has just been released by the user

keys={}

function is_held(k) return band(keys[k], 1) == 1 end
function is_pressed(k) return band(keys[k], 2) == 2 end
function is_released(k) return band(keys[k], 4) == 4 end

function upd_key(k)
    if keys[k] == 0 then
        if btn(k) then keys[k] = 3 end
    elseif keys[k] == 1 then
        if btn(k) == false then keys[k] = 4 end
    elseif keys[k] == 3 then
        if btn(k) then keys[k] = 1
        else keys[k] = 4 end
    elseif keys[k] == 4 then
        if btn(k) then keys[k] = 3
        else keys[k] = 0 end
    end
end

function init_keys()
    for a = 0,5 do keys[a] = 0 end
end

function upd_keys()
    for a = 0,5 do upd_key(a) end
end

You need to call these in your _init() and _update() functions:

function _init()
    init_keys()
end

function _update()
    upd_keys()
end
P#20710 2016-05-17 14:46 ( Edited 2016-05-31 00:02)

Very cool, thanks for sharing. This will come in handy in places like where I want single shot type of things. When I use btnp() to fire a bullet, it still fires after it's held down too.

P#20712 2016-05-17 14:54 ( Edited 2016-05-17 18:54)

Thank you. Exactly! I used that in my game to make sure the user wouldn't accidentally confirm a screen.

P#20713 2016-05-17 14:57 ( Edited 2016-05-17 18:57)

That's by design, I suspect, to make it hard to do RSI-as-balance game design.

P#20720 2016-05-17 16:45 ( Edited 2016-05-17 20:45)

Can anyone confirm if Pico-8 imposes the 5-key rollover limit? My keyboard supposedly has six-key USB rollover, but I don't have a better app to test it at the moment, and I'm only getting 5 in Pico-8.

Not an issue, just curious.

P#20732 2016-05-17 18:56 ( Edited 2016-05-17 22:56)

Thanks Adam J! These functions ended up being far more elegant than the kludges I have thrown into my past pico8 programs to get key_up functionality.

P#21091 2016-05-22 15:31 ( Edited 2016-05-22 19:31)

Thank you! :-)

P#21336 2016-05-25 11:38 ( Edited 2016-05-25 15:38)

AdamJ, I have used your demo as the basis for an extended keyboard handler that supports buttons for 2 players and provides a "pulse" mechanism in addition to the held, pressed, and released functionality. I've utilized your display code for the same kind of demo effect.

Would you be ok with me posting it?

P#21523 2016-05-27 21:28 ( Edited 2016-05-28 01:28)

Oh wow! Sure, go for it, thanks!

P#21778 2016-05-30 10:19 ( Edited 2016-05-30 14:19)
1

Cart #21813 | 2016-05-30 | Code ▽ | Embed ▽ | No License
1

This is a modified version of AdamJ's keyboard handler. Some of the bit setting is handled a little differently, but it is pretty much exactly the same idea of using a couple of bits to track the current state of the buttons. I also encapsulated everything within the "keys" table/object.

I use the btn() function (as opposed to btn(b) which returns a single button status) to get a binary-encoded status of all of the buttons for players 1 and 2.

I also included a "pulse" function. keys:pulse(k,r) returns true every r frames while key k is held down. So, keys:pulse(0,6) will be true every six frames while the left arrow is held down. This is similar to the built-in btnp() function, except that btnp() is locked at every four frames.

When using pulse, I have an arbitrary limit/count of 30 frames. Any value of r that is a divisor of 30 should work smoothly, while numbers that are not factors for 30 will produce non-regular pulses. So, 1,2, 3, 5, 6, 10, 15, and 30 will all produce smooth results.

If you need some other smooth interval, modify the line that reads:

keys.ct[i]=(keys.ct[i]+1) % 30

And change the 30 to a multiple of the frequency you desire.

Pulses are tracked separately for each key, so if I press and hold button 0, and then three frames later press and hold button 3, and am looking for pulses of 6 on each button, I will get a pulse for button 0 on frame 6, and a pulse for button 3 on frame 9. Pulse counters are reset each time a key is pressed.

Here is the code for the keys object. It actually comes out slightly lighter on the tokens count than the original handler, even with the second player and pulse command added.

keys={btns={},ct={}}

function keys:update()
 for i=0,13 do
  if band(btn(),shl(1,i))==shl(1,i) then
   if keys:held(i) then
    keys.btns[i]=2
    keys.ct[i]=(keys.ct[i]+1) % 30
   else
    keys.btns[i]=3
   end
  else
   if keys:held(i) then 
    keys.btns[i]=4
   else
    keys.btns[i]=0
    keys.ct[i]=0
   end
  end
 end
end

function keys:held(b) return band(keys.btns[b],2) == 2 end
function keys:down(b) return band(keys.btns[b],1) == 1 end
function keys:up(b) return band(keys.btns[b],4) == 4 end
function keys:pulse(b,r) return (keys:held(b) and keys.ct[b]%r==0) end

You will need to call "keys:update()" in your _update function to update the keyboard state.

P#21816 2016-05-30 14:42 ( Edited 2016-05-30 18:49)

Sweet!

P#21842 2016-05-30 20:02 ( Edited 2016-05-31 00:02)

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2024-03-19 03:16:31 | 0.015s | Q:27