My TouchEvent class

I’d been searching on the forum for a touch event handler that would allow me Long Presses, Double Taps, etc, but the solutions I’d found weren’t exactly what I was looking for, so I wrote my own based on some of them.

The ones I’d found were centered around the touched() method, so they only fired when something was touched. seems logical to do it that way, but I wanted my class to not be global, so I figured out a way to have it live exclusively in the draw() function.

The general premise is that it sends out a “NO_TOUCH_EVENT” message every frame, and when there’s a touch message, it figures out what kind to send. Possible types are:

NO_TOUCH_EVENT
BEGAN_EVENT
MOVING_EVENT
ENDED_EVENT
LONG_PRESS_EVENT
DOUBLE_TAP_EVENT
DOUBLE_TAP_AND_DRAG_EVENT

To use it, instead of sending the touch(t) to all of your classes so they can handle the touch, just pass them the singleton’s return value from its draw() and use CurrentTouch to get your x/y:

TouchEvent = class()
TouchEvent.NO_TOUCH_EVENT = 1
TouchEvent.BEGAN_EVENT = 2
TouchEvent.MOVING_EVENT = 3
TouchEvent.ENDED_EVENT = 4
TouchEvent.LONG_PRESS_EVENT = 5
TouchEvent.DOUBLE_TAP_EVENT = 6
TouchEvent.DOUBLE_TAP_AND_DRAG_EVENT = 7


function TouchEvent:init()
    self.x = 0  -- x of currentTouch.x when a BEGAN event occurs
    self.y = 0  -- y of CurrentTouch.y when a BEGAN event occurs
    self.t = 0  -- ElapsedTime for CurrentTouch when a Began event occurs
    self.LPStarted = false 
    self.LPDetected = false 
    self.screenTouched = false 
    self.LPThreshold = 0.5
    self.wiggleRoom = 10
end

function TouchEvent:draw()
    -- Codea does not automatically call this method
    if( self.screenTouched == false ) then 
        return TouchEvent.NO_TOUCH_EVENT 
    end
    --we have a TouchEvent!
    -- was LP started?
    -- was LP Threshold passed?
    -- was Touch XY within limits?
    if( self.LPStarted ) then   --yes, LP Started
        if( self:wasLPThresholdPassed() ) then -- yes, LP threshold passed
            if( self:wasTouchXYWithinWiggleRoom() ) then -- yes, Touch XY within limits
                return TouchEvent.LONG_PRESS_EVENT
            end
        end
    end
    --LP not started
    return self:processRegularTouchEvent()
end

function TouchEvent:touched(touch)
    -- Codea does not automatically call this method
    self.screenTouched = true
end

function TouchEvent:wasTouchXYWithinWiggleRoom()
    local result = false
    local dx = math.abs(self.x-CurrentTouch.x)
    local dy = math.abs(self.y-CurrentTouch.y)
    if dx <= self.LPThreshold then
        if dy <= self.LPThreshold then
            result = true
        end
    end
    return result
end

function TouchEvent:processRegularTouchEvent()
    if( CurrentTouch.state ~= BEGAN ) then  
        self.LPStarted = false
        self.LPDetected = false
        self.t = 0
        if( CurrentTouch.state ~= MOVING ) then
            --touchEnded
            self.screenTouched = false
            return TouchEvent.ENDED_EVENT
        else
            --it wasn't TouchBegan, or TouchEnded, so it's TouchMoving
            if( CurrentTouch.tapCount > 1 ) then
                return TouchEvent.DOUBLE_TAP_AND_DRAG_EVENT
            end
            return TouchEvent.MOVING_EVENT
        end
    else -- wasTouchBegan = true
        if( self.LPStarted == false ) then 
            --only update this stuff if a LongPress hasn't begun.
            --otherwise it would be updated every frame, and we'd never get a LP event, because of ElapsedTime reflecting the time change of every frame, not from when the BEGAN event started
            self.x = CurrentTouch.x
            self.y = CurrentTouch.y
            self.t = ElapsedTime
        end
        self.LPStarted = true
        --check for DoubleTap
        if( CurrentTouch.tapCount > 1 ) then
            return TouchEvent.DOUBLE_TAP_EVENT
        end
        return TouchEvent.BEGAN_EVENT
    end
end

function TouchEvent:wasLPThresholdPassed()
    return (ElapsedTime - self.t > self.LPThreshold )
end

function TouchEvent:turnOffLongPress()
    self.LPStarted = false
    self.LPDetected = false
end

and here’s the main i used to test it out:

function setup()
    te = TouchEvent()    
    touchTypes = {  "NO_TOUCH_EVENT", "BEGAN_EVENT", "MOVING_EVENT", "ENDED_EVENT", "LONG_PRESS_EVENT", "DOUBLE_TAP_EVENT", "DOUBLE_TAP_AND_DRAG_EVENT"}
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)
    print( touchTypes[ te:draw() ] )
end

function touched(t)
    te:touched(t)   -- this is the only thing that handles touches
    -- everything else will receive te:draw()'s return value and use that to process touches from within the main draw() function
end

I agree with LoopSpace, too, but not with respect to UI stuff. Since Codea was designed to produce such marvellous animations and help us learn 3D graphics, it seems a terrible waste that so much time has gone into creating UI libraries. It would be much better to have a single library for these things (as in most other languages) so we can get on with the fun stuff that Codea was built for.

I can’t speak for everyone else, but the fun stuff for me is creating buttons, windows, text input boxes, etc. They’re not all the same from program to program, so I don’t expect one to work for all of them. I’m not trying to write code for the App Store, so I’m in no hurry to complete and test code. I’ll write the same code over and over, because I think each time I do the routines get better and smaller.

partly agree with all of you. For Dave’s latest point, I agree. I have a ‘base’ button class, but in each of my new projects I always end up rewriting it to tweak little things or have it fit better with the theme.

that said, I think there are things that should not be written a thousand ways, such as Nats excellent video game controllers which found their way into lots of projects - why waste time recreating these when he already has an excellent set you can use?

It’s too bad there isn’t a standardized API, like the iOS SDK or JUCE SDK. but, then again, Codea isn’t meant for apps with GUIs. it’s meant for gaming and rendering 60FPS

Interesting.

For comparison, here’s my touch handler. It works by gathering all touches to itself, much as yours does. When each touch begins, it queries any registered objects to see if one will claim the touch. Then all the touches claimed by an object are passed to it in a “gesture”. There’s also a bit of gesture analysis to determine things like taps, long presses, and the like.

https://gist.github.com/loopspace/5611534#file-touch-lua

wow, that’s really complicated and hard to understand what it does. can you explain it a bit more?

yeah, definitely want to see your swipe solution

@SkyTheCoder

My code may look complicated, but it’s easy to use. In the main code, we need to load the touch handler and run the gathering and processing functions:

function setup()
    touches = Touches()
end

function draw()
    touches:draw() -- put this at the start of the draw function
end

function touched(t)
    touches:addTouch(t)
end

Any object that wants to use touches has to register itself with the touch handler:

function setup()
    touches = Touches()
    anobj = Stuff()
    touches:pushHandler(anobj)
end

The Stuff class needs to define two functions, one that says when it will claim a touch and one that processes the resulting gestures.

Every completely new touch event (ie one with state=BEGAN) is tested until claimed.

function Stuff:isTouchedBy(t) -- t is a new touch event
    if <something> then
        return true -- we claim this touch
    else
        return false -- not us
    end
end

All current touches are gathered into a gesture which is passed to the object. This is passed every draw cycle and all the currently active touches are contained in it, even if they didn’t get any new information this cycle (ie the touch didn’t move).

function Stuff:processGesture(g)
    -- do stuff with the gesture
    g:noted() -- marks that we've examined this gesture
end

Gestures are analysed a bit before being passed, so there are a variety of tests that can be run. The following are some of the fields in g.

num: the number of touches in the gesture.
 
updated: has there been new information since the gesture was last
looked at?
 
type.tap: this is true if none of the touches have moved
 
type.long: this is true if all of the touches waited a significant
length of time (currently .5s) between starting and ending or moving.
 
type.short: this is true if all of the touches were of short duration
(less that .5s). Note that "short" and "long" are not opposites.
 
type.ended: if all the touches have ended.
 
type.finished: if all the touches ended at least .5s ago. The
distinction between "ended" and "finished" is to allow for things like
multiple taps to be registered as a single gesture.
 
type.pinch: if the gesture consists of multiple movements, the gesture
tries to see if they are moving towards each other or parallel. It
does this by looking at the relative movement of the barycentre of the
touch compared to the average magnitude of the movements of the
individual touches.

@matkatmusic i dont want to sell you anything, but i assume you looked at my Buttons lib that provides all the touch states you describe. What was wrong with it for you? too much code and overhead? I’d be interested to know.

@jvm38 I never saw the library you’re describing. Can you link to it? I mainly borrowed concepts from the top result if you search the forum for “Long Press”.

Also, I come from a flash and arduino background, where events send “Event.EVENT_TYPE” messages or it’s all based around a state machine, so I wanted to implement something similar to that. Since I didn’t want to figure out how to have it only send messages when needed, i kept it like a low-level state machine with a single register (the output of the TouchEvent:draw() ) that is updated every clock cycle. To me, that was the easiest implementation to wrap my head around, even if it’s not the most robust.

@matkatmusic the most recent http://codea.io/talk/discussion/comment/47776#Comment_47776
and you can see a picture a few posts above http://codea.io/talk/discussion/comment/47083#Comment_47083.
but this is different of what you wanted to do (although the net result is the same: you want to make buttons that listen to events)

I don’t think any of us should be trying to “sell” anything here. It’s good to develop ones own code, even if it does replicate someone else’s, for hopefully obvious reasons. It’s also good to see how others have attacked the same problem to get ideas on how to improve ones own version.

Somethings then, I’ll grant you, there’s not much to be gained by not copying someone else’s code (for example, importing 3D models). But where there are many ways to do a task, and many subtleties involved in doing it, such as in handling touches, then we should welcome lots of different approaches.

@matkatmusix Here you go: http://codea.io/talk/discussion/5561/flickable-easy-touch-library-for-taps-swipes-and-long-presses#Item_1

@loopspace i certainly agree with the general principles of your point.
However i am not sure it is really usefull that everyone rewrite the basic tools we all need. Especially: buttons and windows. I am starting to think that these are really missing from Codea. It distract people from making real things not to have those utilities.
I know you are a teacher, and as such you consider good that students master the basics. But where is the limit between useful learning and time waste? You certainly dont suggest we all start back from assembly langage, but use the nice LUA langage and API developped by TLL…
Since i’ve made my buttons/windows/screens library, i’ve been able to build a nice app with it (codea showcase) and i think of finally working back again on my favorite program (ants), that i left aside 2 years ago, because there was no point making it more complex without the required assets (buttons/windows/screens).
Of course i dont mean to prevent people from re-building things their own way if they want to. For instance myself i didnt restart from you library for a variety of reasons, while i could have. However it never occured to me to rewrite built-in Codea functions. So i assume if TLL would provide a button/window library, with their brilliant api design choices as usual, i would just use it.
Mmmm… still thinking. This is not completely true. TLL has provided a parameter library, with buttons, but it clearly does not fufill our needs, so most of us rewrite the same functions…
I hope you take my point for what it is: just sharing my views and concerns, not criticizing your above post.
Thanks!

I agree with @LoopSpace. It nice to look at what someone else has written, but if new users just take what someone else has written, they’ll never learn how to do it themselves. Also, taking someone else’s code makes their code larger than it needs to be. You don’t always need everything someone else has written in a class. I like examples to learn by, but I’m not going to take what someone else wrote and just dump that into my code. If you’re just here to take code to create an app for the App Store, then by all means take existing code. If you’re here to learn, then look at someone else’s code, but write your own, even if it’s doing the same thing.

True, but access to native iOS ui would be awesome. Games need ui also :slight_smile: I think Simeon previously said he would love to bring a GUI functionality to Codea, so it might come some day

I added swipes, pinch zooms, and 3-finger swipes to my class. it works really well now. also refactored all the functions so they are of the ‘result = 0, do stuff, return result’ format.