Events and Listeners

Events are dispatched to listeners. Event listeners can be either functions or objects (see Function vs Table Listeners below). In both cases, when an event occurs, the listener will be invoked and be supplied with a table representing the event. All events will have a property name that identifies the kind of event.

Registering for Events

Certain objects you create using Corona's libraries are event listeners. This includes both display objects and the global Runtime object. You can add and remove listeners for events using the following object methods:

In the example below, an image display object registers to receive Touch Events. Touch events are not broadcast globally. Only objects that register for the event and lie underneath it will be candidates for receiving the touch. See Touch Events for more information.

Function Listeners Table Listeners
local button = 
        display.newImage("button.png") 
 
local function listener(event) 
  print(event.name.."occurred") 
  return true 
end 
 
button:addEventListener( 
        "touch", listener )
                
local button = 
        display.newImage("button.png") 
 
function button:touch(event) 
  print(event.name.."occurred") 
  return true 
end 
 
button:addEventListener( 
        "touch", button )
                

In contrast, Runtime Events are dispatched by the system. They are broadcast to all listeners. Below is an example of registering for an enterFrame event:

Function Listeners Table Listeners
local function listener(event) 
  print(event.name.."occurred") 
end 
 
Runtime:addEventListener( 
        "enterFrame", listener )
                
local listener = {} 
 
function listener:enterFrame(event) 
  print(event.name.."occurred") 
end 
 
Runtime:addEventListener( 
        "enterFrame", listener )
                

Function vs Table Listeners

Listeners can be either functions or table/display objects.

When a function listener is invoked, it is passed a table representing the event:

1
2
3
4
5
local myListener = function( event ) 
        print( "Listener called with event of type " .. event.name ) 
end 
Runtime:addEventListener( "touch", myListener ) 
Runtime:addEventListener( "enterFrame", myListener )

Sometimes a function listener is not convenient because certain variables are not in scope when the listener is triggered (invoked). In these situations, object listeners should be used. Object listeners must have an instance method with a name corresponding to the event name:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- assume MyClass and MyClass:new() already exist 
 
function MyClass:enterFrame( event ) 
        print( "enterFrame called at time: " .. event.time ) 
end 
 
function MyClass:touch( event ) 
        print( "touch occurred at ("..event.x..","..event.y..")" ) 
end 
 
local myObject = MyClass:new() 
 
Runtime:addEventListener( "touch", myObject ) 
Runtime:addEventListener( "enterFrame", myObject )

Runtime Events

Since they have no specific target, Runtime Events are only sent to the global Runtime. Instead, they are broadcast to all registered listeners. The events all have string names:

enterFrame

enterFrame events occur at the frame interval of the application. They are only sent to the global Runtime object.

The following properties are available in this event:

  • event.name is the string "enterFrame".
  • event.time is the time in milliseconds since the start of the application.

system

System events are dispatched to notify the application of external events such as when the device needs to suspend the application because of an incoming phone call. These events are only sent to the global Runtime object.

The following properties are available in this event:

  • event.name is the string "system".
  • event.type is a string identifying the type of event. The string values could be:
    • "applicationStart" occurs when the application is launched and all code in main.lua is executed.
    • "applicationExit" occurs when the user quits the application.
    • "applicationSuspend" occurs when the device needs to suspend the application such as during a phone call or if the phone goes to sleep from inactivity. In the simulator, this corresponds to the simulator running in the background. During suspension, no events (not even enterFrame events) are sent to the application while suspended, so if you have code that depends on time, you should account for the time lost to an application being suspended.
    • "applicationResume" occurs when the application resumes after a suspend. On the phone, this occurs if the application was suspended because of a phone call. On the simulator, this occurs when the simulator was in the background and now is the foreground application.

orientation

Orientation events occur when the device orientation changes. They only occur on devices with accelerometer support. They are only sent to the global Runtime object.

The following properties are available in this event:

  • event.name is the string "orientation".
  • event.type is a string identifying the orientation:
    • "portrait"
    • "landscapeLeft"
    • "portraitUpsideDown"
    • "landscapeRight"
    • "faceUp"
    • "faceDown"
  • event.delta is the angular difference between the ending and starting orientation. 0 if the two orientations lie in different planes.

accelerometer

Accelerometer events let you detect sudden movements and determine the device's orientation relative to gravity. These events are only dispatched on devices that have support accelerometer. They are only sent to the global Runtime object.

The following properties are available in this event:

  • event.name is the string "accelerometer".
  • event.xGravity is the acceleration due to gravity in the x-direction
  • event.yGravity is the acceleration due to gravity in the y-direction
  • event.zGravity is the acceleration due to gravity in the z-direction
  • event.xInstant is the instantaneous acceleration in the x-direction
  • event.yInstant is the instantaneous acceleration in the y-direction
  • event.zInstant is the instantaneous acceleration in the z-direction
  • event.isShake is true when the user shakes the device

location (GPS)

These are location events generated by the GPS hardware. They are only sent to the global Runtime object.

  • event.name is the string "location".
  • event.latitude is the latitude in degrees.
  • event.longitude is the longitude in degrees.
  • event.altitude is the altitude in meters.
  • event.accuracy is the accuracy of the location in meters. If negative, then the latitude and longitude are not valid.
  • event.speed is the instantaneous speed of the device in meters per second.
  • event.direction is the direction the device is travelling in degrees clockwise from true North. If negative, the direction is invalid.
  • event.time is the UTC timestamp of the location event.

When an error occurs, the following properties will be non-nil:

  • event.errorMessage is a string with an error description. This property only exists when an error occurs. It may be localized so it may vary depending on the user's language setting.
  • event.errorCode is a platform-specific integer for the error which is not language dependent. This property only exists when an error occurs.

heading (compass)

These are heading events generated by the compass hardware, if available on the device. Note: the Android OS only supports event.magnetic, not event.geographic (see below). These events are only sent to the global Runtime object.

The following properties are available in this event:

  • event.name is the string "heading".
  • event.geographic represents a heading in degrees (clockwise) relative to the geographic North Pole, sometimes known as true North.
  • event.magnetic represents a heading in degrees (clockwise) relative to the magnetic North Pole.

memoryWarning (iOS)

The iOS low memory warning is exposed as a Corona event type named "memoryWarning", sent to the global Runtime object. This event has no fields.

When this event fires, the OS reserves the right to forcibly shut down the application in about five seconds (although it may or may not do so). Apple advises developers to listen for this warning, and to handle it by freeing as much memory as possible when it is received.

Here is an example of a listener for this event:

1
2
3
4
5
local function handleLowMemory( event ) 
  print( "memory warning received!" ) 
end
 
Runtime:addEventListener( "memoryWarning", handleLowMemory )

Note that Android has no equivalent of this event, so currently this is an iOS-only feature of Corona.

Targeted Events

Targeted events are not broadcast. They are sent to a single target (a function or table listener).

completion

Completion events signal the end of an interaction. Typically these are dispatched at the end of a modal interaction such as using the camera or throwing up a native alert.

The following are common properties of this event:

  • event.name is the string "completion".

Additional properties are given depending on the modal interaction (see media.playVideo, media.show, and native.showAlert).

timer

Timer events are used in conjunction with the timer library.

The following properties are available in this event:

  • event.name is the string "timer".
  • event.source corresponds to the timer registered to send the event.
  • event.count is the number of times that the timer has fired the listener. This is useful if you registered the timer to fire multiple times.
  • event.time is the time in milliseconds since the start of the application.

urlRequest

URL request events are dispatched to the listener registered with the native.webPopup() function. They are sent when the web popup is about to request a url and also when a url fails to load.

The following properties are available in this event:

  • event.name is the string "urlRequest".
  • event.url is the absolute URL of the request.
  • event.errorMessage is a string with an error description. This property only exists when an error occurs. It may be localized so it may vary depending on the user's language setting.
  • event.errorCode is a platform-specific integer for the error which is not language dependent. This property only exists when an error occurs.

Touch Events

For a tutorial on how to detect user touches, please see Detecting Touches in Corona.

When the user's finger touches the screen, a hit event is generated and dispatched to display objects in the display hierarchy. Only those objects that intersect the hit location (the location of the finger on the screen) will be candidates for receiving the event.

The events propagate through these objects in a particular order. The first object in the display hierarchy to receive the event is the top-most display object that intersects the hit location; the next object is the next top-most object intersecting the hit location; and so on.

Hit events propagate until they are handled. You can stop propagation to the next object (all listeners of the current object still get the event) by telling the system that the event was handled. This boils down to making a listener return true. If at least one of the listeners of the current object returns true, event propagation ends; the next object will not get the event. If the event is still unhandled at the end of this traversal, it is broadcast as a global event to the global Runtime object.

Hit events are a hybrid of local and global events. They are dispatched to a single display object at a time, but any listener registered with that display object will receive the event.

In some situations, it is convenient to have subsequent events target the same object that handled the initial touch event (a user's finger initially touching the screen). To accomplish this, you can use a special method display.getCurrentStage():setFocus( object ). When the user's finger is lifted, you can call the method again and pass nil to restore the default behavior.

touch (single touch)

Touch events are a special kind of hit event. When a user's finger touches the screen, they are starting a sequence of touch events, each with different phases.

  • event.name is the string "touch".
  • event.x is the x-position in screen coordinates of the touch.
  • event.y is the y-position in screen coordinates of the touch.
  • event.xStart is the x-position of the touch from the "began" phase of the touch sequence.
  • event.yStart is the y-position of the touch from the "began" phase of the touch sequence.
  • event.phase is a string identifying where in the touch sequence the event occurred:
    • "began" a finger touched the screen.
    • "moved" a finger moved on the screen.
    • "ended" a finger was lifted from the screen.
    • "cancelled" the system cancelled tracking of the touch.

touch (multitouch)

To illustrate the documentation below, we have provided two new sample projects:

  • "MultitouchFingers" (under "Interface")
  • "MultitouchButton" (under "Interface")

In addition, we have made minor revisions to ui.lua to support multitouch. If you activate multitouch and plan to use ui.lua, you should include this new version in your project. The new library should also be compatible with non-multitouch cases.

Multitouch in Corona

When multiple touch is enabled, multiple touches are sent as individual touch events, each of which will now behave like single touches even when happening simultaneously. We have also added a time property so that you can detect simultaneous touch events when writing gesture-recognition code. Finally, we have added an id property which allows you to track which touch events came from the same finger.

Note: Multitouch does not work correctly on some Android devices (e.g., NexusOne, HTC Incredible, etc.). This can be demonstrated in Drag Me Multitouch sample app. This is a limitation of the current Android platforms and not Corona.

Whether or not multitouch is enabled, touch events will have the following standard properties:

  • event.x is the x-position in screen coordinates of the touch.
  • event.y is the y-position in screen coordinates of the touch.
  • event.xStart is the x-position of the touch from the "began" phase of the touch sequence.
  • event.yStart is the y-position of the touch from the "began" phase of the touch sequence.
  • event.phase is a string identifying where in the touch sequence the event occurred:
    • "began" a finger touched the screen.
    • "moved" a finger moved on the screen.
    • "stationary" a finger is touching the screen but hasn't moved from the previous event.
    • "ended" a finger was lifted from the screen.
    • "cancelled" the system cancelled tracking of the touch.
  • event.id is a unique identifier of the chosen touch so that you can distinguish between multiple touches across events (i.e. the different events sent across multiple listener calls). The id uniquely identifies a given finger touching the screen as that touch changes state, generating new touch events.
  • event.time is a timestamp. It is in the same units as returned by system.getTimer().

Using multitouch

As before, you must explicitly activate multitouch before you will receive multiple touch events:

system.activate( "multitouch" )

Once this call is made, you will get multiple touch events delivered as individual single touch events. For example, if two fingers moved simultaneously, Corona will hit-test each touch separately, delivering them to the respective listeners; both events will have the same timestamp.

Multiple Focus, Buttons and Delivery Precedence

In the single-touch world, we provided the ability to have touch events target a particular object via the stage:setFocus(object) method, which caused all future touch events to be sent directly to the touch listener for that object. This made behaviors like button rollovers possible. The typical flow, as seen in the previous ui.lua library, was:

  • The initial touch hit-tests the object, so the touch event is dispatched to object's touch listener
  • Hit-testing for all future touches is (globally) disabled by the object's touch listener, which calls stage:setFocus(object). This causes future touch events to be forwarded to that object, rather than go through hit-testing against other objects.
  • When the touch ends (or is cancelled), normal hit-testing is restored via stage:setFocus( nil ).

In a multitouch world, this model breaks down, because it assumes there will only be one unique touch at a time. As a result, two buttons couldn't be pressed simultaneously.

Therefore, we had to add the ability to forward a touch event on a per-object basis. To do this, we extended the event with a parameter that uniquely identifies the event associated with a given finger touching the screen:

  • stage:setFocus( object [,touchID] )

Calling the above with only one parameter (the object) is the same as the old global focus behavior: all touches will be forwarded to the same object.

Calling the above method with the optional parameter (the touchID) means that the specified touch has focus on that object, but other touches do not. Using this API, it is possible to create an object that will “own” the first touch it gets, for the lifetime of that touch, and for multiple objects to obtain their own focused touches at the same time. See the “GettingStarted/FollowMeMultitouch” sample code for a demonstration of this behavior.

To turn off per-object focus, you specify the object and pass nil for the touchID:

  • stage:setFocus( object, nil )

Note: for backwards compatibility, stage:setFocus() reverts to the old setFocus behavior when multitouch is off:

  • stage:setFocus( obj, nil ) behaves like stage:setFocus( nil )
  • stage:setFocus( obj, id ) behaves like stage:setFocus( obj )

As a result, the latest ui.lua library code, distributed with Beta 6 or later, should work as expected in both multitouch and non-multitouch modes.

Gesture support

See the "Multitouch" sample code in the iPad sample code directory for an example of how to implement a pinch/zoom gesture.

We intend to provide additional framework libraries to make gesture recognition easier, but we encourage you to experiment with multitouch in the meantime.

Custom Events

In Corona, you can register custom events with both display objects and the global Runtime object. In both cases, you will have to manually dispatch the event yourself using the following object method:

object:dispatchEvent( event )

Dispatches event to object. The event parameter must be a table with a name property which is a string identifying the type of event. The object parameter must be either a display object or the global Runtime object. If object has a listener registered to receive name events. We recommend you also include a target property to the event so that your listener can know which object received the event.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- Create an object that listens to events 
local image = display.newImage( "image.png" ) 
 
-- Setup listener 
local myListener = function( event ) 
        print( "Event " .. event.name ) 
        print( "Target has width: " .. event.target.stageWidth ) 
end 
 
image:addEventListener( "myEventType", myListener ) 
 
-- Sometime later, create an event and dispatch it 
local event = { name="myEventType", target=image } 
image:dispatchEvent( event )

Replies

Viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
thegwill
User offline. Last seen 22 weeks 5 days ago. Offline
Joined: 21 Aug 2010

If an object has event listeners, is it necessary to remove them if the object is removed from a display group?

In other words, do event listeners NEED to be tidied up?

kellyreyw
User offline. Last seen 1 year 22 weeks ago. Offline
Joined: 21 Oct 2010

In creating a "touch" listener, is there anyway to determine which object is the focus of the event in the listener function? For example,

table =
{
{ value=10, image=display.newImage(group1, "file1.png") },
{ value=20, image=display.newImage(group1, "file2.png") }
}

for i, v in ipairs(table) do
v.image:addEventListener("touch", UpdateScore)
end

function UpdateScore(event)
if ( event.phase == "ended" ) then
score = score + object.value --somehow update the score based on which object is receiving the event
end
end

Gilbert
User offline. Last seen 2 years 14 weeks ago. Offline
Alumni
Joined: 5 Apr 2010

You can determine which object was touched by using event.target. If the target has properties associated with it, such as a value or id, then you can retrieve those using event.target.value or event.target.id. Here's a simplified example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
local score = 0
 
myObject1 = display.newImage("file1.png", 50, 50) 
myObject2 = display.newImage("file2.png", 150, 150)
 
myObject1.value = 10
myObject2.value = 20 
 
function UpdateScore(event)
        local t = event.target
 
        if ( event.phase == "ended" ) then
                score = score + t.value --update the score
                print("score: ".. score) --print the score to the terminal
        end
end
 
myObject1:addEventListener("touch", UpdateScore)
myObject2:addEventListener("touch", UpdateScore)

kellyreyw
User offline. Last seen 1 year 22 weeks ago. Offline
Joined: 21 Oct 2010

Thank you! That was what I needed to know.

-Kelly

jlandyr
User offline. Last seen 2 years 45 weeks ago. Offline
Joined: 22 Jan 2011

Thanks Gilbert... that code helped me a lot... thanks...

DavidBFox
User offline. Last seen 5 days 12 hours ago. Offline
Joined: 10 Oct 2010

Can someone explain the difference between a touch and tap event?

Also, is there any support or sample code for a double-tap event?

Thanks!

matt50
User offline. Last seen 3 years 2 weeks ago. Offline
Joined: 28 Mar 2011

initial sample code for a table listener gives a syntax error if the function on the table is declared as local:
should

1
2
3
4
local function button:touch(event) 
  print(event.name.."occurred") 
  return true 
end 

not be
1
2
3
4
function button:touch(event) 
  print(event.name.."occurred") 
  return true 
end

?

mortenft
User offline. Last seen 2 years 14 weeks ago. Offline
Joined: 12 Jul 2011

I am experiencing the same - is the sample code wrong ?

What is the impact of NOT making these event functions "local" ?

Tom
User offline. Last seen 11 hours 32 min ago. Offline
Staff
Joined: 13 Jul 2010

The table listeners samples on this page that are defined with "local" are wrong and shouldn't have "local". The objects have already been defined and the table listener is only adding the method to table/object. I fixed the samples.

drkeeling6
User offline. Last seen 24 weeks 2 days ago. Offline
Joined: 5 Apr 2011

Hi all,

I have question about using dispatchEvent to change screens using the viewController supplied with the tab bar example. I used that as my base because it fit my application ui that I envisioned quite well. However, now I am at a point where I need to automatically return to my last screen after having selected a different tab. For example: I am in screen 1 then I switch to screen 2 where I am presented with some choices and, once selected, I want to automatically return to screen 1 without having to touch the tab bar. When I try to dispatch the event my code looks like this:

local event = { name="touch", phase="ended", id=2, target = tabBar }
Runtime:dispatchEvent(event)

I thought that, perhaps I needed to pecify tabBar.tab[1] but that gives me an index error.

Admittedly, I am a noob at this but I have been programming for 30 years so I'm a little frustrated at not figuring this one out yet.

Any help would be immensely appreciated.

mhelgarc
User offline. Last seen 2 years 46 weeks ago. Offline
Joined: 8 Apr 2011

Hmm.. I think this documentation also include why and when a "return true" should be included on an event listener..

I have to go to a forum to have it answered. Instead of just looking on the documentation.
Cheers!

dennis00
User offline. Last seen 1 year 14 weeks ago. Offline
Joined: 24 Mar 2011

Third paragraph under "Touch Events" on this page:

"If at least one of the listeners of the current object returns true, event propagation ends; the next object will not get the event. If the event is still unhandled at the end of this traversal, it is broadcast as a global event to the global Runtime object."

mhelgarc
User offline. Last seen 2 years 46 weeks ago. Offline
Joined: 8 Apr 2011

I think, they were not there before. ^_^ That's why my comment. and after some weeks I saw the explanation. Its either I missed it... Or they have updated it.

anyway.. as long its there now.. its nice.

duneunit
User offline. Last seen 5 weeks 4 days ago. Offline
Joined: 31 Oct 2010

It says above in the docs that "Whether or not multitouch is enabled, touch events will have the following standard properties" and includes event.id as one of these properties... but is this really true when multitouch is not enabled? If so, why?

open768
User offline. Last seen 28 weeks 3 days ago. Offline
Joined: 6 Jul 2011

couldnt see anything about changing gravity with orientation.
I'm just starting out with Corona and thought I'd share this.

1
2
3
4
5
6
7
8
9
10
11
12
13
gaOrientationGravity = {
        portrait = {x=0,y=-1},
        portraitUpsideDown = {x=0,y=1},
        landscapeLeft= {x=1,y=0},
        landscapeRight = {x=-1,y=0}
}
local function onRotation( poEvent )
        local aVector
        
        aVector = gaOrientationGravity[poEvent.type]
        physics.setGravity( 10 * aVector.x, -10 * aVector.y )
end
Runtime:addEventListener( "orientation", onRotation )

Tons of Toons Apps
User offline. Last seen 1 year 11 weeks ago. Offline
Joined: 15 Jul 2011

Hi,
How often is a "touch" listener called if the user keeps pressing?
Is it once per frame?

BeyondtheTech
User offline. Last seen 2 days 13 hours ago. Offline
Joined: 14 Apr 2010

The "touch" listener only hits once per event. Once when you "began" the touch," as many times as the touch is "moved" (assume this will fire multiple times if the user's finger is big or not steady and the screen is sensitive, etc.) and once again when the touching has "ended."

Personally, I've never seen the "cancelled" event fired, so I'm curious as to when and how we can make that happen.

Tom
User offline. Last seen 11 hours 32 min ago. Offline
Staff
Joined: 13 Jul 2010

The "cancelled" event comes from Apple's documentation and according to their information would occur if your app was interrupted. I've never seen that event occur either.

The best way to learn about touch events is to run the DragMe or DragMeMultitouch sample apps and look at the print messages in the terminal as you touch the screen.

frankxyz
User offline. Last seen 24 weeks 1 day ago. Offline
Joined: 29 Jan 2011

Can't remember where I read it, but is it true that in a multi-touch mode, event.time is the same value for the different event.id's ?