Omnimaga
Calculator Community => TI Calculators => Lua => Topic started by: hoffa on October 01, 2011, 06:59:39 pm
-
(http://webgel.net/bf/1/key.png)
I was trying to find a way to know if a key is held down or not (for a Lua CHIP-8 emulator I'm writing, more as a proof of concept than anything else), but as you probably already knew if you've programmed in Lua on the TI-Nspire, there is no way of knowing anything except when a key is first pressed. That is because of the way the TI-Nspire has been made; while most of the keys only send one event signal each time the key is pressed, the tab and arrow keys continuously keep sending those signals after a short delay while holding the key down. What you first want to do is to somewhat be able to know when one of those special keys is pressed down. It won't be as accurate as you might want it to be, but using some timer tricks (to tackle that annoying delay gap before it starts bombarding with events among others) it is possible to implement something of an isDown() function. Here's some fairly simple code that displays "true" when the tab key is held down, it should be pretty self-explanatory (and as you will notice, it isn't that accurate. It might be made slightly more accurate by tuning those interval values):
Key = class()
function Key:init(eventInterval, firstEventInterval)
self.keyDown = false
self.eventInterval = eventInterval or 150
self.firstEventInterval = firstEventInterval or 750
self.time = {firstEvent = 0, lastEvent = 0}
end
function Key:keyEvent(timeNow)
local timeNow = timeNow or timer.getMilliSecCounter()
if not self.keyDown then
self.time.firstEvent = timeNow
end
self.time.lastEvent = timeNow
self.keyDown = true
end
function Key:isDown(timeNow)
local timeNow = timeNow or timer.getMilliSecCounter()
self.keyDown = timeNow - self.time.firstEvent < self.firstEventInterval
or timeNow - self.time.lastEvent < self.eventInterval
return self.keyDown
end
function on.tabKey()
tab:keyEvent()
end
function on.timer()
platform.window:invalidate()
end
function on.create()
timer.start(0.01)
end
tab = Key()
function on.paint(gc)
gc:drawString("Tab key down: " .. tostring(tab:isDown()), 0, 0, "top")
end
Now to know if a number or character key is pressed down, well, there is no way to do that. But one workaround would be to use the tab key. For example, if you wanted to make it possible for the program to know when a certain key is held down, you'd first have to press that key and then quickly press and hold the tab button. After some coding, we have this:
MasterKey = class()
function MasterKey:init(eventInterval, firstEventInterval)
self.keyDown = false
self.eventInterval = eventInterval or 200
self.firstEventInterval = firstEventInterval or 750
self.time = {firstEvent = 0, lastEvent = 0}
end
function MasterKey:keyEvent(timeNow)
local timeNow = timeNow or timer.getMilliSecCounter()
if not self.keyDown then
self.time.firstEvent = timeNow
end
self.time.lastEvent = timeNow
self.keyDown = true
end
function MasterKey:updateStatus(timeNow)
local timeNow = timeNow or timer.getMilliSecCounter()
self.keyDown = timeNow - self.time.firstEvent < self.firstEventInterval
or timeNow - self.time.lastEvent < self.eventInterval
end
function MasterKey:isDown()
return self.keyDown
end
Keys = class()
function Keys:init(keys, eventInterval)
self.keys = {}
for i = 1, #keys do
self.keys[keys[i]] = {keyDown = false, timeLastEvent = 0}
end
self.eventInterval = eventInterval or 200
end
function Keys:keyEvent(key, timeNow)
self.keys[nobbc].timeLastEvent = timeNow or timer.getMilliSecCounter()
end
function Keys:updateStatus(key, masterKey)
if masterKey.keyDown then
if not self.keys[nobbc].keyDown
and masterKey.time.lastEvent - self.keys[nobbc].timeLastEvent
< self.eventInterval then
for key, value in pairs(self.keys) do
self.keys[nobbc].keyDown = false
end
self.keys[nobbc].keyDown = true
end
else
self.keys[nobbc].keyDown = false
end
end
function Keys:isDown(key)
return self.keys[nobbc].keyDown
end
function on.tabKey()
tab:keyEvent()
end
function on.charIn(c)
if c == "x" then
keys:keyEvent("x")
elseif c == "y" then
keys:keyEvent("y")
elseif c == "z" then
keys:keyEvent("z")
end
end
function on.timer()
platform.window:invalidate()
end
function on.create()
timer.start(0.01)
end
tab = MasterKey()
keys = Keys({"x", "y", "z"})
function on.paint(gc)
tab:updateStatus()
keys:updateStatus("x", tab)
keys:updateStatus("y", tab)
keys:updateStatus("z", tab)
gc:drawString("'x' key down: " .. tostring(keys:isDown("x")), 0, 0, "top")
gc:drawString("'y' key down: " .. tostring(keys:isDown("y")), 0, 20, "top")
gc:drawString("'z' key down: " .. tostring(keys:isDown("z")), 0, 40, "top")
end
The "master key" in that case is the tab key, which tells the program how long a certain key should be held down. Try it out yourself, press tab + [x/y/z] quickly and hold on to tab, you'll see how the values change. It's not perfect but it's as far as I know the best you can do with TI-Nspire Lua.
Well that was it, going to bed now!
-
I haven't tested it but
tip :
function on.timer()
timer.stop()
platform.window:invalidate()
end
tab = Key()
function on.paint(gc)
gc:drawString("Tab key down: " .. tostring(tab:isDown()), 0, 0, "top")
timer.start(0.01)
end
Can be replace to
function on.timer()
platform.window:invalidate()
end
tab = Key()
function on.create()
timer.start(0.01)
end
function on.paint(gc)
gc:drawString("Tab key down: " .. tostring(tab:isDown()), 0, 0, "top")
end
There is no need to stop and restart the timer as you did =)
-
It would be cool if TI implemented a feature that signals when a key has been released, then this would simple to implement, and more user friendly :(
-
@Levak: thanks, didn't know about that. Changed it.
-
it doesn't work.:-(
-
What are you trying to do ?
If you post some code we could help you more :)
-
I got the message im nspire: 54:attempt tp index field '?' (a nil value)
-
Excuse me. This is the code which i have tested.
MasterKey = class()
function MasterKey:init(eventInterval, firstEventInterval)
self.keyDown = false
self.eventInterval = eventInterval or 200
self.firstEventInterval = firstEventInterval or 750
self.time = {firstEvent = 0, lastEvent = 0}
end
function MasterKey:keyEvent(timeNow)
local timeNow = timeNow or timer.getMilliSecCounter()
if not self.keyDown then
self.time.firstEvent = timeNow
end
self.time.lastEvent = timeNow
self.keyDown = true
end
function MasterKey:updateStatus(timeNow)
local timeNow = timeNow or timer.getMilliSecCounter()
self.keyDown = timeNow - self.time.firstEvent < self.firstEventInterval
or timeNow - self.time.lastEvent < self.eventInterval
end
function MasterKey:isDown()
return self.keyDown
end
Keys = class()
function Keys:init(keys, eventInterval)
self.keys = {}
for i = 1, #keys do
self.keys[keys] = {keyDown = false, timeLastEvent = 0}
end
self.eventInterval = eventInterval or 200
end
function Keys:keyEvent(key, timeNow)
self.keys[nobbc].timeLastEvent = timeNow or timer.getMilliSecCounter()
end
function Keys:updateStatus(key, masterKey)
if masterKey.keyDown then
if not self.keys[nobbc].keyDown
and masterKey.time.lastEvent - self.keys[nobbc].timeLastEvent
< self.eventInterval then
for key, value in pairs(self.keys) do
self.keys[nobbc].keyDown = false
end
self.keys[nobbc].keyDown = true
end
else
self.keys[nobbc].keyDown = false
end
end
function Keys:isDown(key)
return self.keys[nobbc].keyDown
end
function on.tabKey()
tab:keyEvent()
end
function on.charIn(c)
if c == "x" then
keys:keyEvent("x")
elseif c == "y" then
keys:keyEvent("y")
elseif c == "z" then
keys:keyEvent("z")
end
end
function on.timer()
platform.window:invalidate()
end
function on.create()
timer.start(0.01)
end
tab = MasterKey()
keys = Keys({"x", "y", "z"})
function on.paint(gc)
tab:updateStatus()
keys:updateStatus("x", tab)
keys:updateStatus("y", tab)
keys:updateStatus("z", tab)
gc:drawString("'x' key down: " .. tostring(keys:isDown("x")), 0, 0, "top")
gc:drawString("'y' key down: " .. tostring(keys:isDown("y")), 0, 20, "top")
gc:drawString("'z' key down: " .. tostring(keys:isDown("z")), 0, 40, "top")
end
-
Hi, please don't try to double post and next time put code in a bb code tag ;)
Try replacing "nobbc" with "key" (in the entire code).
-
@blauemauritius: It's been quite a long time since I did this, but seems like I still have an example of how to use it here: hoffa.franceserv.com/key_example.zip (http://hoffa.franceserv.com/key_example.zip)
Also, what's nobbc?
-
You got that in your original code. I suspect because [ key] acted like a bb code or something.
-
The only downside with this is that one can't use quick taps in addition to long presses.
Would it be possible to create a ndless extension to test if a key is held down? Because that would be really helpful I think. :D
-
jim i tried it with changing all the nobbc's into key's (with the replace function, so i did not forget one ) and it gave exactly the same result, which is quite logical i think
-
At line 34 it should be keys{i} (replace curly brackets by square ones) and not keys. Should work then.