Hi all.  I have a menu-bar background app that relies on global hotkeys.  I
have been using Carbon¹s RegisterEventHotKey to register callbacks for my
hotkeys in Leopard.  Is this still the preferred/only method for global
hotkeys in Snow Leopard?

Presuming it is, here is my problem, which relates to making my code 64-bit
clean:

I am using the Carbon/Cocoa hybrid approach described in this somewhat dated
blog post:  http://unsanity.org/archives/000045.php

I call ³RegisterEventHotKey² from CarbonEvents.h to register the hotkeys,
and then listen for them in my app delegate¹s ³sendEvent:² method, checking
for event subtype Œ6¹ (hotkey pressed).  The RegisterEventHotKey function is
passed the address of an ³EventHotKeyRef² variable, and returns a unique
reference to the hotkey.  In the NSEvent received by ³sendEvent:², the
Œdata1¹ attribute contains the same EventHotKeyRef, allowing one to
correlate the hotkey event with a specific hot key.

After registering the hotkeys, I convert the EventHotKeyRef to an NSValue
using ³valueFromPointer² and then use those values as keys to an
NSMutableDictionary which I then reference in sendEvent to figure out which
action goes with the hotkey that was pressed.  Later on, I can unregister
all of the hotkeys by iterating through the dictionary keys, reconverting
the NSValues to pointers (and casting as EventHotKeyRef), and passing to
ŒUnregisterEventHotKey¹.

All this worked fine in 32-bit mode.  However, in 64-bit mode, the
EventHotKeyRef passed by CarbonEvents as Œdata1¹ of the NSEvent object does
not match up with the values I am getting back from the RegisterEventHotKey
function.  When I register the hotkeys and convert the EventHotKeyRef to an
NSValue, they typically look something like this:  ³<20ed1200 01000000>².
However, when I take the Œdata1¹ field from NSEvent on the same hotkey and
convert that to an NSValue, it will look like this: ³<20ed1200 00000000>².
Thus, I can¹t look up the right hotkey in my dictionary.   It appears that
whatever mechanism converts the Carbon Event to an NSEvent is munging the
EventHotKeyRef it passes as Œdata1¹ of the NSEvent by truncating the size.

I clearly don¹t have a good grasp of precisely what the ŒEventHotKeyRef¹
type is (it is typedef¹d to an opaque type).  I think that I messing things
up when I convert the EventHotKeyRef to an NSValue using ŒvalueFromPointer¹,
but I am not really clear what the better/correct method would be.

So, I need a way to (1) record the EventHotKeyRef returned by
RegisterEventHotKey and correlate it to the desired action; (2) unpack the
EventHotKeyRef returned by Œdata1¹ of the NSEvent and look up the desired
action; and (3) iterate through the stored EventHotKeyRefs for the purpose
of calling ŒUnregisterEventHotKey¹.

One approach would be to find the right combination of typecasts/conversions
to store the EventHotKeyRef in a dictionary and have consistent results
between the RegisterEventHotKey and data1 of the NSEvent.  Another approach
would be to store the ³good² EventHotKeyRefs in a primitive array for use in
the unregister calls, and then create my lookup dictionary with a shortened
version of the ref that chops off the padding bytes that are getting munged
so that the results are the same when looking up the Œdata1¹ field.

I have not tried going the pure-Carbon route (e.g., as described here
http://dbachrach.com/blog/2005/11/program-global-hotkeys-in-cocoa-easily/ ),
as I am hoping to find a workaround that lets me stay with the (in my
opinion) simpler Cocoa ³sendEvent² method.

(I am also not sure why my NSDictionary lookup works in 32-bit mode if the
NSValue created from the NSEvent Œdata1¹ is a different (but numerically
equivalent) object from the one originally stored in the dictionary key (I
gather NSDictionary¹s ŒobjectForKey¹ will return the entry for any NSValue
that returns true from ŒisEqualToValue¹ of the comparator?)

Any and all advice on this would be appreciated.  Relevant code is below.

Thanks in advance
Tobias Zimmerman

/* Method to register hotkeys /*

> - (void)assignHotKey: (UInt32)keyEquiv
>            modifiers: (UInt32)mods
>         hotKeyNumber: (NSInteger)menuIndex  //the menu item index of the
> associated action
> {
>     EventHotKeyID hotKeyID;
>     EventHotKeyRef theRef;
>     
>     hotKeyID.signature = 'SWMN';
>     hotKeyID.id = keyEquiv;
>     
>     RegisterEventHotKey(
>                         keyEquiv,
>                         mods,
>                         hotKeyID,
>                         GetApplicationEventTarget(),
>                         0,
>                         &theRef
>                         );
> 
>     NSValue *HKValue = [NSValue valueWithPointer:(EventHotKeyRef)theRef];
> 
>     NSLog(@"Storing HKValue: %@", HKValue);           // in 64-bit, e.g.,
> ³<20ed1200 01000000>²
> 
>     [hotKeys setObject: [NSNumber numberWithInteger: menuIndex] forKey:
> HKValue];   //hotkeys is an NSMutableDictionary
> }
> 
> 
/*method that processes hotkey events */

> - (void)sendEvent: (NSEvent *)theEvent
> {
>     if ( ([theEvent type] == NSSystemDefined) && ([theEvent subtype] ==
> kEventHotKeyPressedSubtype) ) {   // kEventHotKeyPressedSubtype == 6
>         
>         NSValue *HKValue = [NSValue valueWithPointer:(EventHotKeyRef)[theEvent
> data1]];
> 
>         NSLog(@"Received Hot Key: %@", HKValue);    // in 64-bit, e.g.,
> ³<20ed1200 00000000>²
> 
>         NSInteger menuIndex = [ [hotKeys objectForKey:HKValue] integerValue];
> // Not really sure why this works in 32-bit
>                  
> // if NSValue objects aren¹t identical
>                  
> // (but are numerically equal)
> 
>         [statusMenu performActionForItemAtIndex: menuIndex];   // Calls the
> appropriate menu item for the desired action
>     }        
>     [super sendEvent:theEvent];
> }
> 
> 
/* method to unregister hotkeys */

> - (void)unregisterHotKeys
> {
>     for ( NSValue *key in hotKeys ) {
>         UnregisterEventHotKey( (EventHotKeyRef)[key pointerValue] );
>     }
>     hotKeys = [NSMutableDictionary dictionary];
> }

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to