forked from albertz/music-player
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmediakeys.py
130 lines (107 loc) · 3.43 KB
/
mediakeys.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import sys
class MacMediaKeyEventsTap:
# http://weblog.rogueamoeba.com/2007/09/29/apple-keyboard-media-key-event-handling/
def __init__(self):
# IOKit/hidsystem/ev_keymap.h
self._keyControls = {
16: 'play-pause',
17: 'next',
18: 'previous',
19: 'next', # actually 'fast', but we handle it like next
20: 'previous', # actually 'rewind', but we handle it like previous
}
def eventTap(self, proxy, type_, event, refcon):
from AppKit import NSKeyUp, NSEvent
# Convert the Quartz CGEvent into something more useful
keyEvent = NSEvent.eventWithCGEvent_(event)
if keyEvent.subtype() is 8: # subtype 8 is media keys
data = keyEvent.data1()
keyCode = (data & 0xFFFF0000) >> 16
keyState = (data & 0xFF00) >> 8
if keyCode in self._keyControls:
if keyState == NSKeyUp:
self.onMediaKeyUp(self._keyControls[keyCode])
return None # consume event
return event # pass through
def onMediaKeyUp(self, control):
#print "handleKeyUp:", control
pass
def runEventsCapture(self):
import AppKit, Quartz
from AppKit import NSSystemDefined
pool = AppKit.NSAutoreleasePool.alloc().init()
self.runLoopRef = Quartz.CFRunLoopGetCurrent()
while True:
# https://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html
tap = Quartz.CGEventTapCreate(
Quartz.kCGSessionEventTap, # Quartz.kCGSessionEventTap or kCGHIDEventTap
Quartz.kCGHeadInsertEventTap, # Insert wherever, we do not filter
Quartz.kCGEventTapOptionDefault, #Quartz.kCGEventTapOptionListenOnly,
Quartz.CGEventMaskBit(NSSystemDefined), # NSSystemDefined for media keys
self.eventTap,
None
)
assert tap
# Create a runloop source and add it to the current loop
runLoopSource = Quartz.CFMachPortCreateRunLoopSource(None, tap, 0)
Quartz.CFRunLoopAddSource(
self.runLoopRef,
runLoopSource,
Quartz.kCFRunLoopDefaultMode
)
# Enable the tap
Quartz.CGEventTapEnable(tap, True)
try:
# and run! This won't return until we exit or are terminated.
Quartz.CFRunLoopRun()
except:
# I got this one here once:
# error: NSInternalInconsistencyException - Invalid parameter not satisfying: cgsEvent.type > 0 && cgsEvent.type <= kCGSLastEventType
sys.excepthook(*sys.exc_info())
continue # rerun
# this is a regular quit
break
del pool
def start(self):
from threading import Thread
self.thread = Thread(target = self.runEventsCapture, name = "mediakeys runEventsCapture")
self.thread.daemon = True
self.thread.start()
def stop(self):
import Quartz
Quartz.CFRunLoopStop(self.runLoopRef)
if sys.platform == "darwin":
EventListener = MacMediaKeyEventsTap
else:
print "No media key event listener implementation"
# Dummy implementation
class EventListener:
def start(self): pass
def stop(self): pass
from State import state
def onMediaKeyUp(control):
try:
if control == "play-pause":
state.playPause()
elif control == "next":
state.nextSong()
except:
sys.excepthook(*sys.exc_info())
def mediakeysMain():
eventTap = EventListener()
eventTap.onMediaKeyUp = onMediaKeyUp
eventTap.start()
for ev in state.updates.read(): pass # wait for exit
eventTap.stop()
if __name__ == '__main__':
tap = EventListener()
def onMediaKeyUp(control):
print "onMediaKeyUp:", control
tap.onMediaKeyUp = onMediaKeyUp
tap.start()
import time, sys
try:
while True: time.sleep(10)
except: pass
tap.stop()
print