Detecting Multitasking Gestures

Wow, it has been a really long time since I wrote up a technical post here. But I finally had a technical challenge today that felt worth sharing, so here it goes!

As you may know, I’m working on a new game called Finger Tied. The game is a multi-touch puzzle game. Some of the levels require that you drag 4 fingers around on the screen at once. I sent an early build out to a limited set of testers yesterday afternoon and a few reported problems playing the 4-finger levels. This is why: Multitasking Gestures.

A while back Apple added a feature to iOS called Multitasking Gestures. This feature is turned on by default on the iPad, I believe. When it is active, you can use 4- or 5-finger gestures to do things like switch between running apps, close the active app, or bring up the multitasking bar. The problem is, as developers, we have absolutely no control over this. As far as I can tell, we can’t even query the OS to ask it if the feature is turned on, and we certainly can’t temporarily override the behaviour.

So testers were running into problems where they would start to play a level with 4 fingers, and the app would close. Or their iPad would switch to another app, etc. I had seen some other games bring up a message on first launch that say things like:

“Please disable Multitasking Gestures to play this game properly.”

But I don’t like the idea of ruining that initial play experience with a text-heavy popup that might not even be needed. I figured there had to be a way to detect when one of those gestures has happened. I started looking at what events I get in the game just before the gesture is captured at the OS level. It turns out, your app will receive a touches cancelled event when one of these gestures is captured. I realized I could use this in the game.

Here’s some pseudocode that runs inside touchesCancelled:

if (number of touches cancelled >= 4)
    save a BOOL that says a gesture was used

Any time I get 4 or more cancelled touches at the same time, I’ll save out that boolean value to NSUserDefaults. Now, the next time the user launches a level I do this:

gestureUsed = get saved BOOL value
if (gestureUsed && level requires >= 4 fingers)
    display a popup explaining how to turn off Multitasking Gestures
    clear the saved BOOL value from the save file

This means that the user can play through levels that don’t require 4 fingers to play without ever seeing that message. It also means if they never use a multitasking gesture (or have them turned off), they’ll never see the message. It’s only if they use a gesture and then try to play a level that needs 4 fingers that they’ll see it.

I also force the same check on applicationDidBecomeActive so that I catch the cases where the Gesture happened mid-level and the user was dumped out of the game. This means that in the case where the user has Gestures turned on (but doesn’t use them), then tries to play a 4-finger level, if they accidentally trigger a Gesture then return immediately to the game, the game will immediately pop this message up giving them an explanation of what happened.

However, this is not foolproof. Because I want to try to catch as many cases as possible, this code can generate some false positives in the following case:

  1. Player has Gestures enabled
  2. Player enters the game, then uses a Gesture to switch to another app (this will save that a Gesture occurred)
  3. Player returns to the game, realizes their Gestures will interfere with the app
  4. Player quits the game and turns off Gestures in the OS settings
  5. Player reenters the game, plays a 4-finger level
  6. The game will present the Gesture warning dialog

The other false positive that could happen occurs when a player places 4 fingers on the iPad, then drags all 4 fingers off the screen in the same frame of execution. In that case you would also get 4 touches cancelled in one event, but it would be extremely rare.

Update (2012-07-27): As Alex pointed out in the comments, you’ll also get 4 touches cancelled in the case where the user has 4 fingers on the screen then presses the Home button on the iPad. Again, I believe this is a rare enough occurrence that I’m OK with a few potential false-positives in order to catch the real ones.

So, it’s not perfect, but these are cases I can live with.

Finally, since I haven’t ever submitted this code to Apple, I make no guarantees that it will pass review. This is also untested against iOS 6, so it might fail down the road. Use at your own risk. :)

Owen