emulate media key press on Mac

That took some time and many hacks (trying around with ctypes, the IOKit native interface, Quartz and/or Cocoa). This seems like an easy solution now:

#!/usr/bin/python

import Quartz

# NSEvent.h
NSSystemDefined = 14

# hidsystem/ev_keymap.h
NX_KEYTYPE_SOUND_UP = 0
NX_KEYTYPE_SOUND_DOWN = 1
NX_KEYTYPE_PLAY = 16
NX_KEYTYPE_NEXT = 17
NX_KEYTYPE_PREVIOUS = 18
NX_KEYTYPE_FAST = 19
NX_KEYTYPE_REWIND = 20

def HIDPostAuxKey(key):
    def doKey(down):
        ev = Quartz.NSEvent.otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_(
            NSSystemDefined, # type
            (0,0), # location
            0xa00 if down else 0xb00, # flags
            0, # timestamp
            0, # window
            0, # ctx
            8, # subtype
            (key << 16) | ((0xa if down else 0xb) << 8), # data1
            -1 # data2
            )
        cev = ev.CGEvent()
        Quartz.CGEventPost(0, cev)
    doKey(True)
    doKey(False)

for _ in range(10):
    HIDPostAuxKey(NX_KEYTYPE_SOUND_UP)
HIDPostAuxKey(NX_KEYTYPE_PLAY)

(While I needed this in Python for now, my question was not really Python related and of course you can easily translate that to any other language, esp. ObjC.)


Thank you Albert for that! I expanded on your script a bit to make it an executable that could in turn be called by Quicksilver or another launcher/trigger handler.

#!/usr/bin/python

# CLI program to control the mediakeys on OS X. Used to emulate the mediakey on a keyboard with no such keys.
# Easiest used in combination with a launcher/trigger software such as Quicksilver.
# Main part taken from http://stackoverflow.com/questions/11045814/emulate-media-key-press-on-mac
# Glue to make it into cli program by Fredrik Wallner http://www.wallner.nu/fredrik/

import Quartz
import sys

# NSEvent.h
NSSystemDefined = 14

# hidsystem/ev_keymap.h
NX_KEYTYPE_SOUND_UP = 0
NX_KEYTYPE_SOUND_DOWN = 1
NX_KEYTYPE_PLAY = 16
NX_KEYTYPE_NEXT = 17
NX_KEYTYPE_PREVIOUS = 18
NX_KEYTYPE_FAST = 19
NX_KEYTYPE_REWIND = 20

supportedcmds = {'playpause': NX_KEYTYPE_PLAY, 'next': NX_KEYTYPE_NEXT, 'prev': NX_KEYTYPE_PREVIOUS, 'volup': NX_KEYTYPE_SOUND_UP, 'voldown': NX_KEYTYPE_SOUND_DOWN}

def HIDPostAuxKey(key):
    def doKey(down):
        ev = Quartz.NSEvent.otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_(
            NSSystemDefined, # type
            (0,0), # location
            0xa00 if down else 0xb00, # flags
            0, # timestamp
            0, # window
            0, # ctx
            8, # subtype
            (key << 16) | ((0xa if down else 0xb) << 8), # data1
            -1 # data2
            )
        cev = ev.CGEvent()
        Quartz.CGEventPost(0, cev)
    doKey(True)
    doKey(False)

if __name__ == "__main__":
    try:
        command = sys.argv[1]
        assert(command in supportedcmds)
        HIDPostAuxKey(supportedcmds[command])
    except (IndexError, AssertionError):
        print "Usage: %s command" % (sys.argv[0],)
        print "\tSupported commands are %s" % supportedcmds.keys()

The script can be found at https://gist.github.com/4078034


Swift 5 / MacOS 10.14.4 / Xcode 10.2

    @IBAction func mediaPressed(_ sender: AnyObject) {
        let NX_KEYTYPE_SOUND_UP: UInt32 = 0
        let NX_KEYTYPE_SOUND_DOWN: UInt32 = 1
        let NX_KEYTYPE_PLAY: UInt32 = 16
        let NX_KEYTYPE_NEXT: UInt32 = 17
        let NX_KEYTYPE_PREVIOUS: UInt32 = 18
        let NX_KEYTYPE_FAST: UInt32 = 19
        let NX_KEYTYPE_REWIND: UInt32 = 20

        func HIDPostAuxKey(key: UInt32) {
            func doKey(down: Bool) {
                let flags = NSEvent.ModifierFlags(rawValue: (down ? 0xa00 : 0xb00))
                let data1 = Int((key<<16) | (down ? 0xa00 : 0xb00))

                let ev = NSEvent.otherEvent(with: NSEvent.EventType.systemDefined,
                                            location: NSPoint(x:0,y:0),
                                            modifierFlags: flags,
                                            timestamp: 0,
                                            windowNumber: 0,
                                            context: nil,
                                            subtype: 8,
                                            data1: data1,
                                            data2: -1
                                            )
                let cev = ev?.cgEvent
                cev?.post(tap: CGEventTapLocation.cghidEventTap)
            }
            doKey(down: true)
            doKey(down: false)
        }

        for _ in 1...10 {
            HIDPostAuxKey(key:NX_KEYTYPE_SOUND_UP)
        }
        HIDPostAuxKey(key:NX_KEYTYPE_PLAY)
    }

Tags:

Macos

Keyevent