Home   

Making Sense of kAXMenuItemCmdModifiersAttribute

Update: Apple updated the headers and documentation for the flags used by kAXMenuItemCmdModifiersAttribute in 2014. The new constants are available in 10.9 and later. The original article remains below.

Anyone who needs to to read the keyboard shortut of a menu item using OS X’s Accessibility API will need to be able to understand the kAXMenuItemCmdModifiersAttribute of the menu item. This attribute contains information about which modifier keys (Control, Option, Shift, and Command) are part of the shortcut. While the documentation correctly explains that this attribute is an integer, it does not explain how the information is stored in the integer. Unfortunately this attribute stores modifiers differently than any other API on OS X, leaving the user to figure it out themselves through testing. I recently did the work to figure this out myself, and since I can’t find this information anywhere on the Internet, I’m posting this information so that it’s availiable to others who have this problem.

The only documentation for kAXMenuItemCmdModifiersAttribute can be found in the Carbon Accessibility Reference. It is only one sentence. There is no additional information that can be found in the header files of HIServices.framework.

kAXMenuItemCmdModifiersAttribute

An integer mask that represents the modifier keys held down in the keyboard shortcut for the command represented by this accessibility object.

Because users of the Accessibility API often need to post Keyboard events, they might be inclined to guess that the integer mask is the same as a CGEventFlag, and write a method like this.i

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (void) logModifiers: (int) bitmask
{    
    if (bitmask & kCGEventFlagMaskControl)
    {
        NSLog(@"The Control Key is present");
    }
    
    if (bitmask & kCGEventFlagMaskAlternate)
    {
        NSLog(@"The Option Key is present");
    }
    
    if (bitmask & kCGEventFlagMaskShift)
    {
        NSLog(@"The Shift Key is present");
    }
    
    if (bitmask & kCGEventFlagMaskCommand)
    {
        NSLog(@"The Command Key is present");
    }
}

But since the integer mask is not actually a CGEventMask, this will not work. The integer mask actually uses the lowest 4 bits to represent the modifier keys. For Control, Option and Shift, a set bit means that the key is present in the keyboard shortcut. However, for Command a set bit means that the Command key is not present in the shortcut. I was unable to find any constant definitions in the HIServices.framework headers which corresponded to these flags. The corrected method looks like this.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- (void) logModifiers: (int) bitmask
{
    NSLog(@"This is how the bitmask actually works");
    
    if (bitmask & 4)
    {
        NSLog(@"The Control Key is present");
    }
    
    if (bitmask & 2)
    {
        NSLog(@"The Option Key is present");
    }
    
    if (bitmask & 1)
    {
        NSLog(@"The Shift Key is present");
    }
    
    if (!(bitmask & 8))
    {
        NSLog(@"The Command Key is present");
    }
}

I have filed two radars with Apple related to this behavior. The first asks Apple to add a new attribute which returns a CGEventMask rdar://12261141, and the second asks Apple to update the documentation for kAXMenuItemCmdModifiersAttribute rdar://12261193.