How to make the Help key do something useful

2011-06-14 01:51:52 -08:00

If you want to see the techniques explored in this blog post in a working application, download ContextHelpTest and/or its source code.

If you’ve used Mac OS X with an Apple extended keyboard of some sort, chances are you’ve seen this:

The Help cursor, a question mark.

That’s the cursor that comes up when you press the Help key. And every time, if you click while that cursor is up, you get a beep and the cursor changes back. (If you press a key instead, the cursor changes back and the keystroke goes through, which often will still get you a beep.)

So most of us probably forget the Help key exists, and curse it when we are reminded of it by pressing it by accident.

But what does it do, really? What is it meant to do?

Every responder can respond to a message called helpRequested:. The default implementation is to ask the help manager for the attributed string set as help for itself. If you’ve never set any help for it, then the help manager will return nil, and the default helpRequested: implementation will pass the message on to the next responder. If you have set help for the responder, then it will tell the help manager to show that help.

So here’s what you need to do:

  • To associate a help text with a view or other object, send the help manager a setContextHelp:forObject: message, passing the help attributed string and the view/other object. When the object is a view, this is all you need to do for Help-clicking on the view to do the right thing.
  • To programmatically show context help for an object, use showContextHelpForObject:locationHint:. Note that you pass the object to look up, not the help text, here. The location hint is where the user might have Help-clicked to bring up the context help.
  • To make your custom view able to show context help for things it draws within itself, override helpRequested:, find what the user clicked on, lazily set the context help for the clicked object (if appropriate), and look it up. If the user didn’t click on anything or you don’t have any help worth providing for it, pass the message on to super.
  • To programmatically enter Help-key mode, send the activateContextHelpMode: action message to the application object. If you want to make a control or menu item in a nib do this, connect it to that action on the First Responder.

Note that the help manager does not retain your definable objects. If an object that has help set for it is deallocated, that will cause a crash later on. Therefore, when setting context help for a view, the view itself should do so within its initWithFrame: (or other designated initializer) and initWithCoder: methods, and remove itself from context help in dealloc. (I don’t know how this goes under GC or ARC.)

You might also have noticed that I’m not simply saying “view” or “responder”. The help manager does not restrict you to setting help for responders or views; any object can have context help set for it. This includes model objects. This is very, very useful for implementing a view that does selective context help on things within it: You set context help for each model object, and the view tells the help manager to show help for the clicked model object.

When setting context help for a non-responder, the controller that owns it should do that, and should remove the object from context help before releasing the ownership.

So, here’s a test app.

Context help works the usual way on the word-count field:

Help-clicking on the word-count field shows a tooltip-looking popover that shows the context help associated with the field.

The text view is a subclass of NSTextView that implements helpRequested: by determining what word the user clicked on (by sending itself characterIndexForInsertionAtPoint: and then using a CFStringTokenizer to walk through its words) and then looking that word up in the dictionary.

Help-clicking on the word-count field shows a tooltip-looking popover that shows the dictionary definition associated with the clicked-on word.

Naturally, since not everybody has a Help key anymore, I provided an alternative.

The Edit menu contains a Define menu item, with the keyboard shortcut of ctrl-slash.

I look forward to seeing what uses you come up with in your apps for this.

Leave a Reply

Do not delete the second sentence.