rodskagg
rodskagg

Reputation: 3937

Listen to all touch events in an iOS app

Is it possible to somehow listen to, and catch, all the touch events occurring in an app?

The app I'm currently developing will be used in showrooms and information kiosks and I would therefore like to revert to the start section of the app if no touches has been received for a given couple of minutes. A sort of screensaver functionality, if you will. I'm planning to implement this by having a timer running in the background, which should be reset and restarted every time a touch event occurs somewhere in the app. But how can I listen to the touch events? Any ideas or suggestions?

Upvotes: 24

Views: 16910

Answers (6)

Sulthan
Sulthan

Reputation: 130172

You need a subclass of UIApplication (let's call it MyApplication).

You modify your main.m to use it:


return UIApplicationMain(argc, argv, @"MyApplication", @"MyApplicationDelegate");

And you override the method [MyApplication sendEvent:]:


- (void)sendEvent:(UIEvent*)event {
    //handle the event (you will probably just reset a timer)

    [super sendEvent:event];
}

Upvotes: 39

Avijit Nagare
Avijit Nagare

Reputation: 8802

In Swift 4.2 1. Create subclass of UIApplication object and print user action:

    import UIKit
    class ANUIApplication: UIApplication {

        override func sendAction(_ action: Selector, to target: Any?, from sender: Any?, for event: UIEvent?) -> Bool {
            print("FILE= \(NSStringFromSelector(action)) METHOD=\(String(describing: target!)) SENDER=\(String(describing: sender))")
            return super.sendAction(action, to: target, from: sender, for: event)
        }   
    }
  1. In AppDelegate.swift file you will find application entry point @UIApplicationMain Comment that and Add new swift file main.swift and add following code to main.swift file

import UIKit

UIApplicationMain( CommandLine.argc, CommandLine.unsafeArgv, NSStringFromClass(ANUIApplication.self), NSStringFromClass(AppDelegate.self))

ANUIApplication is class where we added action logs. AppDelegate is default app delegate where we wrote application delegate methods.(Helpful for tracking action and file name in big project)

Upvotes: 0

Vicky
Vicky

Reputation: 1095

Create a Class "VApplication" that extends from UIApplication and paste these code to corresponding class

VApplication.h

#import <Foundation/Foundation.h>

// # of minutes before application times out
#define kApplicationTimeoutInMinutes 10

// Notification that gets sent when the timeout occurs
#define kApplicationDidTimeoutNotification @"ApplicationDidTimeout"

/**
 * This is a subclass of UIApplication with the sendEvent: method 
 * overridden in order to catch all touch events.
 */

@interface VApplication : UIApplication
{
    NSTimer *_idleTimer;
}

/**
 * Resets the idle timer to its initial state. This method gets called
 * every time there is a touch on the screen.  It should also be called
 * when the user correctly enters their pin to access the application.
 */
- (void)resetIdleTimer;

@end

VApplication.m

#import "VApplication.h"
#import "AppDelegate.h"

@implementation VApplication

- (void)sendEvent:(UIEvent *)event
{
    [super sendEvent:event];
    // Fire up the timer upon first event
    if(!_idleTimer) {
        [self resetIdleTimer];
    }

    // Check to see if there was a touch event
    NSSet *allTouches       = [event allTouches];

    if  ([allTouches count] > 0)
        {
        UITouchPhase phase  = ((UITouch *)[allTouches anyObject]).phase;
        if  (phase == UITouchPhaseBegan)
            {
            [self resetIdleTimer];         
            }
        }
}

- (void)resetIdleTimer 
{
    if  (_idleTimer)
        {
        [_idleTimer invalidate];
        }

    // Schedule a timer to fire in kApplicationTimeoutInMinutes * 60


//  int timeout =   [AppDelegate getInstance].m_iInactivityTime;
    int timeout =   3;
    _idleTimer = [NSTimer scheduledTimerWithTimeInterval:timeout
                                                  target:self 
                                                selector:@selector(idleTimerExceeded) 
                                                userInfo:nil 
                                                 repeats:NO];

}

- (void)idleTimerExceeded
{
    /* Post a notification so anyone who subscribes to it can be notified when
     * the application times out */


    [[NSNotificationCenter defaultCenter]
     postNotificationName:kApplicationDidTimeoutNotification object:nil];
}


@end

Replace the Class name "VApplication" to our

Main.m

file like this

int main(int argc, char * argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, @"VApplication", NSStringFromClass([AppDelegate class]));

    }
}

Register a notification for your corresponding view controller

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidTimeout:) name:kApplicationDidTimeoutNotification object:nil];

And once the timeout occur the notification will fire and handle the event like this

- (void) applicationDidTimeout:(NSNotification *) notif //inactivity lead to any progress
{


}

Upvotes: 3

bcattle
bcattle

Reputation: 12839

You can use a tap gesture recognizer for this. Subclass UITapGestureRecognizer and import <UIKit/UIGestureRecognizerSubclass.h>. This defines touchesBegan:, touchesMoved:, touchesEnded: and touchesCancelled:. Put your touch-handling code in the appropriate methods.

Instantiate the gesture recognizer in application:didFinishLaunchingWithOptions: and add it to UIWindow. Set cancelsTouchesInView to NO and it'll pass all touches through transparently.

Credit: this post.

Upvotes: 3

DarkDust
DarkDust

Reputation: 92384

A subclass of UIWindow could be used to do this, by overriding hitTest:. Then in the XIB of your main window, there is an object usually simply called Window. Click that, then on the right in the Utilities pane go to the Identities (Alt-Command-3). In the Class text field, enter the name of your UIWindow subclass.

MyWindow.h

@interface MyWindow : UIWindow
@end

MyWindow.m

@implementation MyWindow

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *res;

    res = [super hitTest:point withEvent:event];

    // Setup/reset your timer or whatever your want to do.
    // This method will be called for every touch down,
    // but not for subsequent events like swiping/dragging.
    // Still, might be good enough if you want to measure
    // in minutes.

    return res;
}   

@end

Upvotes: 7

user23743
user23743

Reputation:

You could put a transparent view at the top of the view hierarchy, and choose in that view whether to handle the touch events it receives or pass them through to lower views.

Upvotes: 1

Related Questions