Thursday, February 19, 2009

⌘ Development Progress Day 1

OK, now iKeyEx 0.1-6 has been released, let's turn into the other project left over: ⌘.

⌘ was proposed on Jan 26th as a solution to issue 10. You can read the design concept here. As I develop the app, I'll keep updating the progress on this blog.

The first thing I've done is to intercept touches coming to a UILabel using -[UILabel touchesBegan:withEvent:]. It turns out not so easy. By default UILabel ignores all touches. But setting userInteractionEnabled = YES does not solve the problem at all (at least in 2.0 firmware). As usual, when something does not work, I look into the UIKit's assembly code. And it turns out that there is a -[UILabel ignoresMouseEvents] method. So I quickly hooked it to always return NO. Then the test application crashed, complaining -[UIScrollView old_touchesBegan:withEvent:] not found. But hey, I did not do anything to the UIScrollView! What's wrong? Turns out the implementation of -[UIResponder touchesBegan:withEvent:] looks like this:

-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
forwardMethod2(self, _cmd, touches, event);
}

where forwardMethod2() is equivalently the statement [[self nextResponder] performSelector:_cmd withObject:touches withObject:event]. This pattern is used for all touchesXXX:withEvent: messages. Now since I have renamed the old touchesBegan:withEvent: for UILabel only, and my code forwards the message to the next responder (the UIScrollView), and it does not recognize old_touchesBegan:withEvent: -- blam, crash.

As a result, I have to store the old IMP before MobileSubstrate-ing it, and invoke the old message like this:

-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
NSLog(@">>> %@", self.text);
old_touchesBegan_withEvent(self, _cmd, touches, event);
}

With this, I can hook all UILabels in the simulator.

No comments:

Post a Comment