1

I'm using ApplicationServices and CGEventPost in C++ on OSX and I'm trying to see if I can hold a key down but it's not working.

Here is the method I'm using:

void postKeyboardEvent( int keyCode, bool keyUp = false )
{

    CGEventSourceRef source = CGEventSourceCreate( kCGEventSourceStateHIDSystemState );

    CGEventRef keyEvent = CGEventCreateKeyboardEvent( source, (CGKeyCode) keyCode, !keyUp );
    CGEventPost( kCGAnnotatedSessionEventTap, keyEvent );
    CFRelease( keyEvent );

    CFRelease( source );

}

This is how I am testing it:

postKeyboardEvent( kVK_Command );
postKeyboardEvent( kVK_Tab );
postKeyboardEvent( kVK_Tab, true );
postKeyboardEvent( kVK_Command, true );

By my understanding this should toggle me to another window but instead it just "lets go of" the Command key and types a Tab character.

IMPORTANT: I don't want to use something like the following:

CGEventSetFlags( keyEvent, kCGEventFlagMaskCommand );

I have a need to send a "serial chain" of key-down and key-up commands without having to know which key-codes are modifier keys or how many to flag the event with.

Is there a way to do this?

Resist Design
  • 4,462
  • 3
  • 22
  • 35

1 Answers1

1

This is the answer! https://stackoverflow.com/a/8202467/877860 posted by https://stackoverflow.com/users/314546/valexa

The simplest way for this is just bitwise OR'ing the current modifier flags with the flag of your desired modifier(s) , e.g.:

CGEventFlags flags = kCGEventFlagMaskShift;
CGEventRef ev;
CGEventSourceRef source = CGEventSourceCreate (kCGEventSourceStateCombinedSessionState);

//press down            
ev = CGEventCreateKeyboardEvent (source, keyCode, true);    
CGEventSetFlags(ev,flags | CGEventGetFlags(ev)); //combine flags                        
CGEventPost(kCGHIDEventTap,ev);
CFRelease(ev);              

//press up                                  
ev = CGEventCreateKeyboardEvent (source, keyCode, false);                       
CGEventSetFlags(ev,flags | CGEventGetFlags(ev)); //combine flags                        
CGEventPost(kCGHIDEventTap,ev); 
CFRelease(ev);              

CFRelease(source);

UPDATE: This is the method I landed on, it could use some clean-up but it works quite well for my purposes of dispatching a sequence of keycodes to the system and having them happen predictably.

A very important element here is the bitwise operation to remove the shift key mask if shift is NOT down using (& ~) meaning AND NOT.

int shiftKeyCode = 56;
bool shiftIsDown = false;

void postKeyboardEvent( int keyCode, bool keyUp = false )
{

    // Don't send keys while blocked.
    if( blockState == 1 ){

        return;

    }

    if( keyCode == shiftKeyCode ){

        if( keyUp ){

            shiftIsDown = false;

        }else{

            shiftIsDown = true;

        }

    }

    CGEventSourceRef source = CGEventSourceCreate( kCGEventSourceStateHIDSystemState );
    CGEventRef keyEvent = CGEventCreateKeyboardEvent( source, (CGKeyCode) keyCode, !keyUp );

    if( shiftIsDown ){

        // Use Shift flag
        CGEventSetFlags( keyEvent, CGEventGetFlags( keyEvent ) | kCGEventFlagMaskShift );

    }else{

        // Use all existing flag except Shift
        CGEventSetFlags( keyEvent, CGEventGetFlags( keyEvent ) & ~kCGEventFlagMaskShift );

    }

    CGEventPost( kCGHIDEventTap, keyEvent );

    CFRelease( keyEvent );
    CFRelease( source );

}
Community
  • 1
  • 1
Resist Design
  • 4,462
  • 3
  • 22
  • 35
  • This is old, Apple may have changed things, I haven't worked with this in quite a while so I don't know if it works in the latest OSX. – Resist Design Nov 28 '14 at 05:18