1

I don't care about which key was pressed, or how long, or anything like that. All I need is a way to detect that the user has touched the screen, even if that happens to be on the part of the screen covered by a keyboard.

My goal here is to detect a lack of interaction to 'reset' the app to a default state if left along long enough -- think a 'kiosk mode' application. The issue is that I can't detect when the keyboard is touched, as the keyboard apparently intercepts all touch events, even before my customer window can handle them.

Edit:

Considered (and dismissed) is the use of just keyboard show and hide notifications -- we need to prolong screen display if the user is actively typing. Since we use UIWebViews to display certain things, we also can't use the delegate methods of UITextViews or UITextFields.

RonLugge
  • 5,086
  • 5
  • 33
  • 61
  • You say that you use web views to display things, but when the user types, where is that info going? It can't go directly into a web view can it (so I'm trying to figure out what object is handling the keyboard input)? – rdelmar Sep 11 '12 at 01:44

3 Answers3

3

It sounds like detecting all touches—on the keyboard and elsewhere—would suffice. We can do that by subclassing UIApplication to override sendEvent:.

We'll extend the UIApplicationDelegate protocol with a new message, application:willSendTouchEvent:, and we'll make our UIApplication subclass send the message to its delegate before handling any touch event.

MyApplication.h

@interface MyApplication : UIApplication
@end

@protocol MyApplicationDelegate <UIApplicationDelegate>
- (void)application:(MyApplication *)application willSendTouchEvent:(UIEvent *)event;
@end

MyApplication.m

@implementation MyApplication

- (void)sendEvent:(UIEvent *)event {
    if (event.type == UIEventTypeTouches) {
        id<MyApplicationDelegate> delegate = (id<MyApplicationDelegate>)self.delegate;
        [delegate application:self willSendTouchEvent:event];
    }
    [super sendEvent:event];
}

@end

We'll need to make our app delegate conform to the MyApplicationDelegate protocol:

AppDelegate.h

#import "MyApplication.h"

@interface AppDelegate : UIResponder <MyApplicationDelegate>
// ...

AppDelegate.m

@implementation AppDelegate

- (void)application:(MyApplication *)application willSendTouchEvent:(UIEvent *)event {
    NSLog(@"touch event: %@", event);
    // Reset your idle timer here.
}

Finally, we need to make the app use our new MyApplication class:

main.m

#import "AppDelegate.h"
#import "MyApplication.h"

int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv,
            NSStringFromClass([MyApplication class]),
            NSStringFromClass([AppDelegate class]));
    }
}
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • That... looks like it could very well work. I tried something similar with a custom UIWindow, but since this goes a step above window, maybe it'll work. I'll let you know what comes of it. Thank you! – RonLugge Sep 11 '12 at 01:44
  • The on-screen keyboard lives in its own `UIWindow`, separate from your app's normal `UIWindow`. That's why you have to do it in a `UIApplication` subclass. – rob mayoff Sep 11 '12 at 01:46
  • @rob mayoff Sounds like you know your stuff Rob. Any change you could take a look at my question? [link](http://stackoverflow.com/questions/12361439/forms-onsubmit-with-uiwebview#comment16601313_12361439) I'm getting some shuteye now. Hope you know an answer.. I'm pretty lost there! – Ron Sep 11 '12 at 01:47
  • @Ron Sorry, but I have very little experience with `UIWebView`. – rob mayoff Sep 11 '12 at 01:49
  • Thank you very, very, very, VERY much. This does, in fact, work! – RonLugge Sep 11 '12 at 02:01
2

How about using the keyboardShow and keyBoardHide Notifications to set a timer? After x seconds you return the app to your required state.

Could even reset the timer in scrollview delegates or textField delegates if you want to.

Take a look at:

[[NSNotificationCenter defaultCenter] addObserver:self 
                                  selector:@selector(keyboardDidShow:) 
                                      name:UIKeyboardDidShowNotification 
                                    object:nil];    

And a method like this:

- (void)keyboardDidShow:(NSNotification *)note {
    idleTimer = [NSTimer scheduledTimerWithTimeInterval:120 
                         target:nil 
                       selector:@selector(yourMethodHere) 
                       userInfo:nil 
                        repeats:NO]; 
}

Be sure to declare and @synthesize your timer in the .h and .m file.

Hope it helps.

Ron
  • 1,047
  • 13
  • 18
  • The issue is that we need to be able to prolong that interval if the user types something. – RonLugge Sep 11 '12 at 01:30
  • Indeed, see Zhang's answer below. Reset the timer with [idleTimer invalidate]; in the UItextfield or uitextview delegate methods, and then start the timer up again! – Ron Sep 11 '12 at 01:34
2

UITextField or UITextView has a delegate method to detect when user types something:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
   // user tapped a key
   //
   // reset your "idle" time variable to say user has interacted with your app
}

Remember to conform to the UITextField or UITextView protocol depending which one you use (maybe both if you've got both text field and text views). Also remember to mark each of your text field or text view's delegate as your view controller.

<UITextFieldDelegate,UITextViewDelegate>

Updated Answer

Ron, not sure if you actually googled but I found this:

iPhone: Detecting user inactivity/idle time since last screen touch

Community
  • 1
  • 1
Zhang
  • 11,549
  • 7
  • 57
  • 87