sbAppleMediaKeyController.mm
Go to the documentation of this file.
1 /*
2 //
3 // BEGIN NIGHTINGALE GPL
4 //
5 // This file is part of the Nightingale Media Player.
6 //
7 // Copyright(c) 2014
8 // http://getnightingale.com
9 //
10 // This file may be licensed under the terms of of the
11 // GNU General Public License Version 2 (the "GPL").
12 //
13 // Software distributed under the License is distributed
14 // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
15 // express or implied. See the GPL for the specific language
16 // governing rights and limitations.
17 //
18 // You should have received a copy of the GPL along with this
19 // program. If not, go to http://www.gnu.org/licenses/gpl.html
20 // or write to the Free Software Foundation, Inc.,
21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 // END NIGHTINGALE GPL
24 //
25 */
26 
28 
29 #include <nsIObserverService.h>
30 #include <nsComponentManagerUtils.h>
31 #include <nsServiceManagerUtils.h>
32 #include <nsICategoryManager.h>
33 
34 #include <sbIApplicationController.h>
35 #include <sbIMediacoreManager.h>
36 #include <sbIMediacorePlaybackControl.h>
37 #include <sbIMediacoreSequencer.h>
38 #include <sbIMediacoreVolumeControl.h>
39 #include <sbIMediacoreStatus.h>
40 
41 #import <AppKit/AppKit.h>
42 #import <IOKit/hidsystem/ev_keymap.h>
43 #import </usr/include/objc/objc-class.h>
44 
45 
46 //------------------------------------------------------------------------------
47 
48 void MethodSwizzle(Class aClass, SEL orig_sel, SEL alt_sel)
49 {
50  Method orig_method = nil, alt_method = nil;
51 
52  // First, look for methods
53  orig_method = class_getInstanceMethod(aClass, orig_sel);
54  alt_method = class_getInstanceMethod(aClass, alt_sel);
55 
56  // If both are found, swizzle them.
57  if ((orig_method != nil) && (alt_method != nil)) {
58  char *temp1;
59  IMP temp2;
60 
61  temp1 = orig_method->method_types;
62  orig_method->method_types = alt_method->method_types;
63  alt_method->method_types = temp1;
64 
65  temp2 = orig_method->method_imp;
66  orig_method->method_imp = alt_method->method_imp;
67  alt_method->method_imp = temp2;
68  }
69 }
70 
71 //------------------------------------------------------------------------------
72 
74 {
75  nsresult rv;
76  nsCOMPtr<sbIMediacoreManager> manager =
77  do_GetService("@songbirdnest.com/Songbird/Mediacore/Manager;1", &rv);
78  NS_ENSURE_SUCCESS(rv, PR_FALSE);
79 
80  nsCOMPtr<sbIMediacoreStatus> status;
81  rv = manager->GetStatus(getter_AddRefs(status));
82  NS_ENSURE_SUCCESS(rv, PR_FALSE);
83 
84  PRUint32 state;
85  rv = status->GetState(&state);
86  NS_ENSURE_SUCCESS(rv, PR_FALSE);
87 
88  return state == sbIMediacoreStatus::STATUS_PLAYING ||
90 }
91 
93 {
94  nsresult rv;
95  nsCOMPtr<sbIMediacoreManager> manager =
96  do_GetService("@songbirdnest.com/Songbird/Mediacore/Manager;1", &rv);
97  if (NS_FAILED(rv)) {
98  return;
99  }
100 
101  nsCOMPtr<sbIMediacorePlaybackControl> playbackControl;
102  rv = manager->GetPlaybackControl(getter_AddRefs(playbackControl));
103  if (NS_SUCCEEDED(rv) && playbackControl && IsPlaybackPlaying()) {
104  playbackControl->Pause();
105  }
106  else {
107  nsCOMPtr<sbIApplicationController> app =
108  do_GetService("@songbirdnest.com/Songbird/ApplicationController;1", &rv);
109  NS_ENSURE_SUCCESS(rv,);
110  rv = app->PlayDefault();
111  NS_ENSURE_SUCCESS(rv,);
112  }
113 }
114 
116 {
117  nsresult rv;
118  nsCOMPtr<sbIMediacoreManager> manager =
119  do_GetService("@songbirdnest.com/Songbird/Mediacore/Manager;1", &rv);
120  if (NS_FAILED(rv)) {
121  return;
122  }
123 
124  nsCOMPtr<sbIMediacoreSequencer> sequencer;
125  rv = manager->GetSequencer(getter_AddRefs(sequencer));
126  if (NS_FAILED(rv)) {
127  return;
128  }
129 
130  sequencer->Previous(PR_FALSE);
131 }
132 
134 {
135  nsresult rv;
136  nsCOMPtr<sbIMediacoreManager> manager =
137  do_GetService("@songbirdnest.com/Songbird/Mediacore/Manager;1", &rv);
138  if (NS_FAILED(rv)) {
139  return;
140  }
141 
142  nsCOMPtr<sbIMediacoreSequencer> sequencer;
143  rv = manager->GetSequencer(getter_AddRefs(sequencer));
144  if (NS_FAILED(rv)) {
145  return;
146  }
147 
148  sequencer->Next(PR_FALSE);
149 }
150 
151 //------------------------------------------------------------------------------
152 
153 // Add a category to |NSApplication| so that we can swizzle-hack the
154 // |sendEvent:| method between our category and the actual implementation.
156 
157 - (void)sendSongbirdEvent:(NSEvent *)event;
158 
159 @end
160 
162 
163 - (void)sendSongbirdEvent:(NSEvent *)event
164 {
165  // These are the magic bits that are media-key events
166  if ([event type] == NSSystemDefined && [event subtype] == 8) {
167  int keyCode = (([event data1] & 0xFFFF0000) >> 16);
168  int keyFlags = ([event data1] & 0x0000FFFF);
169  int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA;
170 
171  // Sadly, the media key events get posted 4 times for a key-up/key-down
172  // combo. So to prevent making the call 4 times, simply filter out the
173  // event until we get the last 'up' event (keyState == 0).
174  if (keyState == 0) {
175  switch (keyCode) {
176  case NX_KEYTYPE_PLAY:
178  break;
179  case NX_KEYTYPE_FAST:
180  case NX_KEYTYPE_NEXT:
181  OnNextPressed();
182  break;
183  case NX_KEYTYPE_REWIND:
184  case NX_KEYTYPE_PREVIOUS:
186  break;
187  }
188  }
189 
190  // No need to have the real |NSApplication| process this event.
191  return;
192  }
193 
194  // So un-swizzle - to make the call to the real implementation -
195  // then re-swizzle back to our swizzle'd method.
196  MethodSwizzle([NSApplication class],
197  @selector(sendSongbirdEvent:),
198  @selector(sendEvent:));
199 
200  [self sendEvent:event];
201 
202  // Swizzle back..
203  MethodSwizzle([NSApplication class],
204  @selector(sendEvent:),
205  @selector(sendSongbirdEvent:));
206 }
207 
208 @end
209 
210 //------------------------------------------------------------------------------
211 
212 
214 
216 {
217 }
218 
220 {
221 }
222 
223 NS_IMETHODIMP
225 {
226  nsresult rv;
227  nsCOMPtr<nsIObserverService> observerService =
228  do_GetService("@mozilla.org/observer-service;1", &rv);
229  NS_ENSURE_SUCCESS(rv, rv);
230 
231  rv = observerService->AddObserver(this, "final-ui-startup", PR_FALSE);
232  NS_ENSURE_SUCCESS(rv, rv);
233 
234  rv = observerService->AddObserver(this, "quit-application-granted", PR_FALSE);
235  NS_ENSURE_SUCCESS(rv, rv);
236 
237  return NS_OK;
238 }
239 
240 NS_IMETHODIMP
241 sbAppleMediaKeyController::Observe(nsISupports *aSubject,
242  const char *aTopic,
243  const PRUnichar *aData)
244 {
245  NS_ENSURE_ARG_POINTER(aTopic);
246 
247  if (strcmp(aTopic, "final-ui-startup") == 0) {
248  MethodSwizzle([NSApplication class],
249  @selector(sendEvent:),
250  @selector(sendSongbirdEvent:));
251  }
252  else if (strcmp(aTopic, "quit-application-granted") == 0) {
253  nsresult rv;
254  nsCOMPtr<nsIObserverService> observerService =
255  do_GetService("@mozilla.org/observer-service;1", &rv);
256  NS_ENSURE_SUCCESS(rv, rv);
257 
258  rv = observerService->RemoveObserver(this, "final-ui-startup");
259  NS_ENSURE_SUCCESS(rv, rv);
260 
261  rv = observerService->RemoveObserver(this, aTopic);
262  NS_ENSURE_SUCCESS(rv, rv);
263  }
264 
265  return NS_OK;
266 }
267 
268 /* static */ NS_METHOD
269 sbAppleMediaKeyController::RegisterSelf(nsIComponentManager *aCompMgr,
270  nsIFile *aFile,
271  const char *aLoaderStr,
272  const char *aType,
273  const nsModuleComponentInfo *aInfo)
274 {
275  NS_ENSURE_ARG_POINTER(aCompMgr);
276  NS_ENSURE_ARG_POINTER(aFile);
277  NS_ENSURE_ARG_POINTER(aLoaderStr);
278  NS_ENSURE_ARG_POINTER(aType);
279  NS_ENSURE_ARG_POINTER(aInfo);
280 
281  nsresult rv = NS_ERROR_UNEXPECTED;
282  nsCOMPtr<nsICategoryManager> catMgr =
283  do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
284  NS_ENSURE_SUCCESS(rv, rv);
285 
286  rv = catMgr->AddCategoryEntry("app-startup",
288  "service,"
290  PR_TRUE, PR_TRUE, nsnull);
291  return rv;
292 }
293 
return NS_OK
static nsCOMPtr< nsIObserverService > observerService
Definition: UnityProxy.cpp:6
#define SONGBIRD_APPLEMEDIAKEYCONTROLLER_CLASSNAME
const unsigned long STATUS_PLAYING
void OnPreviousPressed()
void OnNextPressed()
NS_IMPL_ISUPPORTS1(sbDeviceCapabilitiesUtils, sbIDeviceCapabilitiesUtils) sbDeviceCapabilitiesUtils
var event
#define SONGBIRD_APPLEMEDIAKEYCONTROLLER_CONTRACTID
const unsigned long STATUS_BUFFERING
NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER NS_IMETHOD Init()
PRBool IsPlaybackPlaying()
void MethodSwizzle(Class aClass, SEL orig_sel, SEL alt_sel)
static NS_METHOD RegisterSelf(nsIComponentManager *aCompMgr, nsIFile *aPath, const char *aLoaderStr, const char *aType, const nsModuleComponentInfo *aInfo)
var Class
void OnPlayPausePressed()
_updateTextAndScrollDataForFrame aData