Omnimaga: The Coders Of Tomorrow
Welcome, Guest. Please login or register.
 
Omnimaga: The Coders Of Tomorrow
21 May, 2013, 06:02:29 *
Welcome, Guest. Please login or register.

Login with username, password and session length
 
   home   news downloads projects tutorials misc forums rules new posts irc about Login Register  
+-OmnomIRC

You must Register, be logged in and have at least 40 posts to use this shout-box! If it still doesn't show up afterward, it might be that OmnomIRC is disabled for your group or under maintenance.

Note: You can also use an IRC client like mIRC, X-Chat or Mibbit to connect to an EFnet server and #omnimaga.

Pages: [1]   Go Down
  Print  
Author Topic: [Howto] Check if a key is pressed down (more or less) -  (Read 1478 times) Bookmark and Share
0 Members and 1 Guest are viewing this topic.
hoffa
LV6 Super Member (Next: 500)
******
Offline Offline

Gender: Male
Last Login: Yesterday at 15:54:50
Date Registered: 28 May, 2011, 20:26:32
Posts: 302


Topic starter
Total Post Ratings: +115

View Profile
« on: 02 October, 2011, 00:59:39 »
0



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):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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!
« Last Edit: 29 January, 2013, 17:58:49 by hoffa » Logged
Levak
LV8 Addict (Next: 1000)
********
Offline Offline

Gender: Male
Last Login: Today at 01:13:55
Date Registered: 04 April, 2010, 23:42:49
Location: France
Posts: 834


Total Post Ratings: +148

View Profile WWW
« Reply #1 on: 02 October, 2011, 01:13:11 »
0

I haven't tested it but

tip :


1
2
3
4
5
6
7
8
9
10
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


1
2
3
4
5
6
7
8
9
10
11
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 =)
« Last Edit: 02 October, 2011, 01:14:33 by Levak » Logged

Human always wants to survive and that's why he will fall one day.
My website - TI-Planet - iNspired-Lua
NecroBumpist
LV4 Regular (Next: 200)
****
Offline Offline

Gender: Male
Last Login: 04 November, 2012, 07:02:18
Date Registered: 18 August, 2011, 05:44:50
Location: In my IDE, programming shit
Posts: 129


Total Post Ratings: +9

View Profile
« Reply #2 on: 02 October, 2011, 01:14:40 »
0

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 Sad
Logged

Developing Lua scripts for the NSpire ?
Check out the Necrotorium
Need a few routines to run faster ? Checkout the MODS Lua Assembly Toolkit.
Need to save space for your scripts ? Checkout LuaSrcDiet
hoffa
LV6 Super Member (Next: 500)
******
Offline Offline

Gender: Male
Last Login: Yesterday at 15:54:50
Date Registered: 28 May, 2011, 20:26:32
Posts: 302


Topic starter
Total Post Ratings: +115

View Profile
« Reply #3 on: 02 October, 2011, 01:21:13 »
0

@Levak: thanks, didn't know about that. Changed it.
Logged
blauemauritius
LV1 Newcomer (Next: 20)
*
Offline Offline

Last Login: 09 May, 2013, 08:47:43
Date Registered: 03 June, 2012, 20:11:57
Posts: 12

Total Post Ratings: 0

View Profile
« Reply #4 on: 03 June, 2012, 20:22:31 »
0

it doesn't work.:-(
Logged
Jim Bauwens
Lua! Nspire! Linux!
Editor
LV10 31337 u53r (Next: 2000)
*
Offline Offline

Gender: Male
Last Login: Today at 00:39:35
Date Registered: 28 February, 2011, 22:32:12
Location: Belgium
Posts: 1733


Total Post Ratings: +180

View Profile WWW
« Reply #5 on: 03 June, 2012, 20:25:42 »
0

What are you trying to do ?
If you post some code we could help you more Smiley
Logged

blauemauritius
LV1 Newcomer (Next: 20)
*
Offline Offline

Last Login: 09 May, 2013, 08:47:43
Date Registered: 03 June, 2012, 20:11:57
Posts: 12

Total Post Ratings: 0

View Profile
« Reply #6 on: 03 June, 2012, 20:36:35 »
0

I got the message im nspire: 54:attempt tp index field '?' (a nil value)
Logged
blauemauritius
LV1 Newcomer (Next: 20)
*
Offline Offline

Last Login: 09 May, 2013, 08:47:43
Date Registered: 03 June, 2012, 20:11:57
Posts: 12

Total Post Ratings: 0

View Profile
« Reply #7 on: 03 June, 2012, 20:39:48 »
0

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
Logged
Jim Bauwens
Lua! Nspire! Linux!
Editor
LV10 31337 u53r (Next: 2000)
*
Offline Offline

Gender: Male
Last Login: Today at 00:39:35
Date Registered: 28 February, 2011, 22:32:12
Location: Belgium
Posts: 1733


Total Post Ratings: +180

View Profile WWW
« Reply #8 on: 03 June, 2012, 20:53:09 »
0

Hi, please don't try to double post and next time put code in a bb code tag Wink

Try replacing "nobbc" with "key" (in the entire code).
« Last Edit: 03 June, 2012, 20:54:39 by jimbauwens » Logged

hoffa
LV6 Super Member (Next: 500)
******
Offline Offline

Gender: Male
Last Login: Yesterday at 15:54:50
Date Registered: 28 May, 2011, 20:26:32
Posts: 302


Topic starter
Total Post Ratings: +115

View Profile
« Reply #9 on: 03 June, 2012, 20:56:06 »
0

@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
Also, what's nobbc?
« Last Edit: 03 June, 2012, 20:56:19 by hoffa » Logged
Jim Bauwens
Lua! Nspire! Linux!
Editor
LV10 31337 u53r (Next: 2000)
*
Offline Offline

Gender: Male
Last Login: Today at 00:39:35
Date Registered: 28 February, 2011, 22:32:12
Location: Belgium
Posts: 1733


Total Post Ratings: +180

View Profile WWW
« Reply #10 on: 03 June, 2012, 20:57:17 »
0

You got that in your original code. I suspect because [ key] acted like a bb code or something. 
Logged

cyanophycean314
LV6 Super Member (Next: 500)
******
Offline Offline

Gender: Male
Last Login: 03 May, 2013, 19:28:34
Date Registered: 07 December, 2011, 02:44:32
Location: Somewhere?
Posts: 363


Total Post Ratings: +42

View Profile
« Reply #11 on: 03 June, 2012, 21:09:11 »
0

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.  Cheesy
Logged

Nick
LV9 Veteran (Next: 1337)
*********
Offline Offline

Gender: Male
Last Login: Yesterday at 20:44:19
Date Registered: 05 June, 2011, 20:01:07
Location: 51° 12′ 34″ N, 3° 13′ 31″ E
Posts: 1178


Total Post Ratings: +158

View Profile WWW
« Reply #12 on: 03 June, 2012, 21:11:33 »
0

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
Logged

hoffa
LV6 Super Member (Next: 500)
******
Offline Offline

Gender: Male
Last Login: Yesterday at 15:54:50
Date Registered: 28 May, 2011, 20:26:32
Posts: 302


Topic starter
Total Post Ratings: +115

View Profile
« Reply #13 on: 03 June, 2012, 21:57:51 »
0

At line 34 it should be keys{i} (replace curly brackets by square ones) and not keys. Should work then.
Logged
Pages: [1]   Go Up
  Print  
 
Jump to:  

Powered by EzPortal
Powered by MySQL Powered by SMF 1.1.18 | SMF © 2013, Simple Machines Powered by PHP
Page created in 0.236 seconds with 32 queries.
Skin by DJ Omnimaga edited from SMF default theme with the help of tr1p1ea.
All programs, games and songs avaliable on this website are property of their respective owners.
Best viewed in Opera, Firefox, Chrome and Safari with a resolution of 1024x768 or above.