문제

Before I continue, I'd like to preface this post by saying that this is possibly the most hacky, downright evil, nasty topic, so I don't expect answers to contain "legal" code by any stretch.

While trying to access the internal preferences file OS X Mountain Lion uses to contain the hot key combination to activate dictation, I came across some beautifully crafted signed integers containing the key codes defined in System Preferences.app. The problem is, the only way I can think of bumming them into a CGEvent would be to go through and basically parse out the bitmask for the given key code, which is a potentially fruitless and annoying endeavor. And because CGEvent is conveniently typedef'd to an internal struct (__CGEvent), there's no way of seeing it's internal organization (in other words, I can't malloc() my way out of this). What I've garnered so far is show in the code below:

/***************************************UNSAFE*****************************************************/
//1048584, -1048585 - Two Left CMD presses; 1048576, -1048577 - Two CMD presses; 8388608, -8388609 - Two Fn presses; 1048592, -1048593 - Two Right CMD presses
- (void)forceDictation {

    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject]stringByAppendingPathComponent:@"Preferences/com.apple.symbolichotkeys.plist"];
    NSDictionary *dictationPrefs = [NSDictionary dictionaryWithContentsOfFile:path];
    NSDictionary *dictationDict = dictationPrefs[@"AppleSymbolicHotKeys"];
    NSDictionary *keyvalueDict = dictationDict[@"164"];
    NSDictionary *valueDict = keyvalueDict[@"value"];
    NSArray *parameters = valueDict[@"parameters"];
    NSInteger firstCode = [[parameters objectAtIndex:0]longLongValue];
    NSInteger secondCode = [[parameters objectAtIndex:1]longLongValue];
}

Anyone familiar with the event bitmasks in HIToolbox can see just how incredibly helpful these key code representations would be, if only they could be easily turned into events then fired off into the blue.

도움이 되었습니까?

해결책

Let's look at the bit-patterns (and you'll note that I've changed the order from the order in which you listed them):

2 × ⌘:
 1048576: 00000000000100000000000000000000
-1048577: 11111111111011111111111111111111

2 × left-⌘:
 1048584: 00000000000100000000000000001000
-1048585: 11111111111011111111111111110111

2 × right-⌘:
 1048592: 00000000000100000000000000010000
-1048593: 11111111111011111111111111101111

2 × Fn:
 8388608: 00000000100000000000000000000000
-8388609: 11111111011111111111111111111111

There's not much I can tell from this except that:

  • Assuming that the positive value is the “real” one (see my comment for my theory on why there are two and why all four pairs are complementary), the key identifier is at least 20 bits up (note that in the first pair in my order, the positive value is exactly 2**20), and at least 4 bits long (2×Fn is 2**23).
  • At least two of the lowest five bits specify which key (left or right), if the setting is so restricted. Left appears to be the first ⌘, whereas right is the second. If this part is zero, any of the identified key will match—e.g., left or right ⌘.

But we may not actually need to parse the bits.

On my MacBook Air, running Key Codes gives me the following output:

Modifier Change
  Keys:       ⌘
  Key Code:   65535 / 0xffff
  Modifiers:  1048848 / 0x100110

Modifier Change
  Keys:       
  Key Code:   65535 / 0xffff
  Modifiers:  256 / 0x100

Modifier Change
  Keys:       ⌘
  Key Code:   65535 / 0xffff
  Modifiers:  1048840 / 0x100108

Modifier Change
  Keys:       
  Key Code:   65535 / 0xffff
  Modifiers:  256 / 0x100

Modifier Change
  Keys:       
  Key Code:   65535 / 0xffff
  Modifiers:  8388864 / 0x800100

Modifier Change
  Keys:       
  Key Code:   65535 / 0xffff
  Modifiers:  256 / 0x100

Some of those numbers look mighty familiar, don't they?

  • Any time I press a ⌘ key, the modifiers state changes to something in the 1048000 range.
  • When I press Fn, the modifiers state changes to 8388864. Yours was 8388608.

Let's look at the modifier masks in NSEvent.h:

NSCommandKeyMask            = 1 << 20,
NSFunctionKeyMask           = 1 << 23,

Oh, hey.

And both of these, and in fact all of the modifier key (as we know them) masks, are within NSDeviceIndependentModifierFlagsMask:

NSDeviceIndependentModifierFlagsMask    = 0xffff0000UL

Which implies that the lower 16 bits are device-dependent: they may differ from one machine or one keyboard to the next. In other words, your lower 16 bits may differ from my lower 16 bits.

But wait! There's more!

If we look in I/O Kit's IOLLEvent.h, we find masks similar to the ones in NSEvent, plus these:

/* device-dependent (really?) */

#define   NX_DEVICELCTLKEYMASK    0x00000001
#define   NX_DEVICELSHIFTKEYMASK  0x00000002
#define   NX_DEVICERSHIFTKEYMASK  0x00000004
#define   NX_DEVICELCMDKEYMASK    0x00000008
#define   NX_DEVICERCMDKEYMASK    0x00000010
#define   NX_DEVICELALTKEYMASK    0x00000020
#define   NX_DEVICERALTKEYMASK    0x00000040
#define NX_DEVICERCTLKEYMASK  0x00002000

So, LCMDKEYMASK is 0b1000, and RCMDKEYMASK is 0b10000. This, too, matches up with the left-⌘ and right-⌘ values you found: left is NX_COMMANDMASK | NX_DEVICELCMDKEYMASK, while right is NX_COMMANDMASK | NX_DEVICERCMDKEYMASK.

From this, I can conclude that:

  • These numbers are not entire CGEvents.
  • Within each pair, the positive value is a modifier flags mask, and the negative value is simply its complement.
  • The events you need to generate are modifier-change events (kCGEventFlagsChanged), the same as Key Codes looks for (when you turn that checkbox on), with the modifier flags of each event as shown above. (Whether you can actually trigger dictation by generating such events, I don't know—you'll have to see for yourself.)
  • The bit layout isn't terribly important, but if you really want to know, the upper half (“device-independent”) identifies which modifiers are turned on, and the lower half (“device-dependent” and presumably only present in a flags-changed event) identify which keys have just been pressed to change them.
  • The number of modifier key presses is, presumably, hard-coded (or, if not, it's specified elsewhere).
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top