7
votes

Is there anyway to trap all keyboard events across my application? I need to know if user is entering anything using keyboard across my application (Application has multiple views). I was able to capture touchEvents by subclassing UIWindow but unable to capture keyboard events.

3

3 Answers

14
votes

Use NSNotificationCenter

[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(keyPressed:) name: UITextFieldTextDidChangeNotification object: nil];

[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(keyPressed:) name: UITextViewTextDidChangeNotification object: nil];

........

-(void) keyPressed: (NSNotification*) notification
{
  NSLog([[notification object]text]);
}
12
votes

I wrote about catching events using a little hack of UIEvent in my Blog

Please refer to : Catching Keyboard Events in iOS for details.

From the above mentioned blog:

The trick is in accessing GSEventKey struct memory directly and check certain bytes to know the keycode and flags of the key pressed. Below code is almost self explanatory and should be put in your UIApplication subclass.

#define GSEVENT_TYPE 2
#define GSEVENT_FLAGS 12
#define GSEVENTKEY_KEYCODE 15
#define GSEVENT_TYPE_KEYUP 11

NSString *const GSEventKeyUpNotification = @"GSEventKeyUpHackNotification";

- (void)sendEvent:(UIEvent *)event
{
    [super sendEvent:event];

    if ([event respondsToSelector:@selector(_gsEvent)]) {

        // Key events come in form of UIInternalEvents.
        // They contain a GSEvent object which contains 
        // a GSEventRecord among other things

        int *eventMem;
        eventMem = (int *)[event performSelector:@selector(_gsEvent)];
        if (eventMem) {

            // So far we got a GSEvent :)

            int eventType = eventMem[GSEVENT_TYPE];
            if (eventType == GSEVENT_TYPE_KEYUP) {

                // Now we got a GSEventKey!

                // Read flags from GSEvent
                int eventFlags = eventMem[GSEVENT_FLAGS];
                if (eventFlags) { 

                    // This example post notifications only when 
                    // pressed key has Shift, Ctrl, Cmd or Alt flags

                    // Read keycode from GSEventKey
                    int tmp = eventMem[GSEVENTKEY_KEYCODE];
                    UniChar *keycode = (UniChar *)&tmp;

                    // Post notification
                    NSDictionary *inf;
                    inf = [[NSDictionary alloc] initWithObjectsAndKeys:
                      [NSNumber numberWithShort:keycode[0]],
                      @"keycode",
                      [NSNumber numberWithInt:eventFlags], 
                      @"eventFlags",
                      nil];
                    [[NSNotificationCenter defaultCenter] 
                        postNotificationName:GSEventKeyUpNotification 
                                      object:nil
                                    userInfo:userInfo];
                }
            }
        }
    }
}
2
votes

Not a simple answer, but I think you have two approaches available.

  1. subclass the input components (UITextView, UITextField, etc) as you've done with the UIWindow.

  2. Create a application wide UITextViewDelegate (and UITextFieldDelegate) and assign all your input field delegates to it.