24

I'm trying to figure out how to detect that the Escape (and other key combinations like Ctrl and alt) have been pressed on a bluetooth keyboard attached to an iOS device.

Some answers seem to suggest this isn't possible. However there are apps in the Appstore that do this (for example iSSH) so I assume it is possible using the public APIs somehow.

I've tried creating my own UITextInput however this receives nothing when the Escape key is pressed. The only part of the API I can see where the iPad might respond is when VoiceOver is enabled (Escape works as back in Safari), so I'm wondering if there's a way in via the accessibility API?

I've also tried to see if there's something I can observe from NSNotificationCenter that might help, but have yet to find anything.

Suggestions welcome, I've been hacking away at this for a day and I'm at a bit of a loss now.

new299
  • 804
  • 1
  • 7
  • 17
  • I filed a radar bug report about unclear documentation or missing functionality it was marked as a duplicate of 7649186, which was marked as closed. – new299 Feb 25 '13 at 19:00

3 Answers3

18

You can do this now in iOS 7. For example, to implement the escape key, override UITextView and place the following methods in your class:

- (NSArray *) keyCommands {
    UIKeyCommand *esc = [UIKeyCommand keyCommandWithInput: UIKeyInputEscape modifierFlags: 0 action: @selector(esc:)];
    return [[NSArray alloc] initWithObjects: esc, nil];
}

- (void) esc: (UIKeyCommand *) keyCommand {
    // Your custom code goes here.
}

You don't need to check to be sure you are on iOS 7, since earlier versions of the OS won't call the keyCommands method.

Jonathan.
  • 53,997
  • 54
  • 186
  • 290
Mike
  • 3,084
  • 1
  • 25
  • 44
6

There are no public APIs for what you intend to accomplish, so this may lead to a rejection.

If you are willing to risk it, you can try this. Wich basically intercepts all events sent to your App by overwriting sendEvent: in your UIApplication.

Daniel
  • 20,420
  • 10
  • 92
  • 149
  • 1
    So yes, in my case it did lead to rejection. I'm still left wondering how the apps that exist in the AppStore do it. – new299 Apr 27 '13 at 00:08
  • 2
    Sometimes, it just depends on the reviewer if your App gets to be in the AppStore or not... Maybe the developer of that app just had more luck. – Daniel Apr 27 '13 at 13:09
  • yes, I remain curious though. They actually rejected it for using _gsEvent which makes me think it was based on some kind of static analysis. I find it odd that IainSmith couldn't find a reference to _gsEvent in the binary. I've resubmitted the app without the _gsEvent stuff and will try revisiting this later. – new299 Apr 28 '13 at 13:27
  • See my last update, if they use a static analyzer and search inside the binary for private keyword, you can masquerade it creating the keyword at runtime. Give it a try :-) – LombaX May 01 '13 at 19:07
5

AFAIK this is not possible using public API. I've done a bit of searching and the esc key is not recognized. The only thing that I didn't do is to try iSSH (it costs 9€ :-), but if you read the description on the AppStore it seems clear that ESC key on a hardware (bluetooth) keyboard doesn't work:

  • Exhaustive key configuration support. Has arrow keys (by pop-up or by toolbar). ctrl, alt, esc, tab, shift, Fn keys (1-10), ` key, PgUp, PgDown and for those keys not listed provides multiple means to add them.

  • Bluetooth keyboard support for arrow keys, function keys and a remapping of the ctrl key through option key mapping in either X11/VNC server or terminal. When enabled, an Option+key press maps to equivalent Ctrl+key press.

As you can see, in the second line the ESC key is not mentioned. Moreover, I've found this (old) post.

EDIT:

As your last updates, I've found a way to "hide" the _gsEvent inside the binary. I don't know if Apple static analyser can find it, however. The trick is simple...create the _gsEvent selector (and other private selectors) at runtime!

-(void)sendEvent:(UIEvent *)event
{

    SEL aSelector = NSSelectorFromString([self theSelector]);
    if ([event respondsToSelector:aSelector]) {

        NSLog(@"Event: %@", event.description);
    }

    [super sendEvent:event];
}

-(NSString *)theSelector
{
    // compose the keyword as you prefer
    NSString *sel = [NSString stringWithFormat:@"%@g%@%@ent", @"_", @"s", @"Ev"];
    return sel;
}

I've tried to search inside the binary and I don't find the _gsEvent keyword, obviously because it's created only at runtime.
Hope this helps.

jezrael
  • 822,522
  • 95
  • 1,334
  • 1,252
LombaX
  • 17,265
  • 5
  • 52
  • 77
  • I have purchased the app and the Escape key on a bluetooth keyboard does work. It also works in Prompt. I've seen that google groups post, but if you dig through the group you'll see references to Ctrl and Esc keys working on the bluetooth keyboard. – new299 Feb 18 '13 at 17:04
  • 1
    From your mac, find the .app of iSSH (it's in your iTunes folder, if not download it from AppStore), right click, show packet content, and then open the executable with an hex editor or simply textedit. If you find the "_gsevent" keyword they are using a private api – LombaX Feb 18 '13 at 21:33
  • 1
    No "_gsevent" in the executable but there are things like "_gs", "_XkbSendNewKeyboardNotify", "_XkbProcessKeyboardEvent_ProcessKeyboardEvent", "_ProcGetKeyboardControl" and "-[iX11ViewController setKeyboardTrigger:]" dont have much experience with what the executable file show but just trying to help. – Iain Smith Feb 24 '13 at 20:22
  • @IainSmith Thanks, I believe he _XKb etc. functions/methods are part of the X11 server support. I guess the _gsEvent could be masked, but still seems odd to me. – new299 Feb 24 '13 at 22:14
  • Looks like this no longer works in a certain NDA-restricted release that rhymes with "SHMY-OH-SHMESS SHEVEN". – swilliams Sep 05 '13 at 04:19