emulate media key press on Mac

北城余情 提交于 2019-11-29 04:51:24

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.)

Fredrik

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)
    }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!