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