2 * Copyright (C) 2010-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #import <UIKit/UIKit.h>
22 #import <AVFoundation/AVAudioSession.h>
24 #import "XBMCApplication.h"
25 #import "XBMCController.h"
26 #import "IOSScreenManager.h"
27 #import "XBMCDebugHelpers.h"
28 #import <objc/runtime.h>
30 @implementation XBMCApplicationDelegate
31 XBMCController *m_xbmcController;
33 // - iOS6 rotation API - will be called on iOS7 runtime!--------
34 // - on iOS7 first application is asked for supported orientation
35 // - then the controller of the current view is asked for supported orientation
36 // - if both say OK - rotation is allowed
37 - (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
39 if ([[window rootViewController] respondsToSelector:@selector(supportedInterfaceOrientations)])
40 return [[window rootViewController] supportedInterfaceOrientations];
42 return (1 << UIInterfaceOrientationLandscapeRight) | (1 << UIInterfaceOrientationLandscapeLeft);
45 - (void)applicationWillResignActive:(UIApplication *)application
49 [m_xbmcController pauseAnimation];
50 [m_xbmcController becomeInactive];
53 - (void)applicationDidBecomeActive:(UIApplication *)application
57 [m_xbmcController resumeAnimation];
58 [m_xbmcController enterForeground];
61 - (void)applicationDidEnterBackground:(UIApplication *)application
65 if (application.applicationState == UIApplicationStateBackground)
67 // the app is turn into background, not in by screen lock which has app state inactive.
68 [m_xbmcController enterBackground];
72 - (void)applicationWillTerminate:(UIApplication *)application
76 [m_xbmcController stopAnimation];
79 - (void)applicationWillEnterForeground:(UIApplication *)application
84 - (void)screenDidConnect:(NSNotification *)aNotification
86 [IOSScreenManager updateResolutions];
89 - (void)screenDidDisconnect:(NSNotification *)aNotification
91 [IOSScreenManager updateResolutions];
94 - (void)registerScreenNotifications:(BOOL)bRegister
96 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
100 //register to screen notifications
101 [nc addObserver:self selector:@selector(screenDidConnect:) name:UIScreenDidConnectNotification object:nil];
102 [nc addObserver:self selector:@selector(screenDidDisconnect:) name:UIScreenDidDisconnectNotification object:nil];
106 //deregister from screen notifications
107 [nc removeObserver:self name:UIScreenDidConnectNotification object:nil];
108 [nc removeObserver:self name:UIScreenDidDisconnectNotification object:nil];
112 - (void)applicationDidFinishLaunching:(UIApplication *)application
116 [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
117 UIScreen *currentScreen = [UIScreen mainScreen];
119 m_xbmcController = [[XBMCController alloc] initWithFrame: [currentScreen bounds] withScreen:currentScreen];
120 m_xbmcController.wantsFullScreenLayout = YES;
121 [m_xbmcController startAnimation];
122 [self registerScreenNotifications:YES];
125 if (![[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&err])
127 ELOG(@"AVAudioSession setCategory failed: %@", err);
130 if (![[AVAudioSession sharedInstance] setActive: YES error: &err])
132 ELOG(@"AVAudioSession setActive failed: %@", err);
134 [[AVAudioSession sharedInstance] setDelegate:self];
137 - (void)beginInterruption
140 [m_xbmcController beginInterruption];
142 - (void)endInterruptionWithFlags:(NSUInteger)flags
144 LOG(@"%s: %d", __PRETTY_FUNCTION__, flags);
145 if (flags & AVAudioSessionInterruptionFlags_ShouldResume)
148 if (![[AVAudioSession sharedInstance] setActive: YES error: &err])
150 ELOG(@"AVAudioSession::endInterruption setActive failed: %@", err);
152 [m_xbmcController endInterruption];
158 [self registerScreenNotifications:NO];
159 [m_xbmcController stopAnimation];
160 [m_xbmcController release];
166 //---------------- HOOK FOR BT KEYBOARD CURSORS KEYS START----------------
167 #define GSEVENT_TYPE 2
168 #define GSEVENT_FLAGS 12
169 #define GSEVENTKEY_KEYCODE 15
170 #define GSEVENTKEY_KEYCODE_IOS7 17
171 #define GSEVENTKEY_KEYCODE_64_BIT 19
172 #define GSEVENT_TYPE_KEYUP 11
174 #define MSHookMessageEx(class, selector, replacement, result) \
175 (*(result) = method_setImplementation(class_getInstanceMethod((class), (selector)), (replacement)))
177 static UniChar kGKKeyboardDirectionRight = 79;
178 static UniChar kGKKeyboardDirectionLeft = 80;
179 static UniChar kGKKeyboardDirectionDown = 81;
180 static UniChar kGKKeyboardDirectionUp = 82;
182 // pointer to the original hooked method
183 static void (*UIApplication$sendEvent$Orig)(id, SEL, UIEvent*);
185 static bool ios7Detected = false;
187 void handleKeyCode(UniChar keyCode)
189 XBMCKey key = XBMCK_UNKNOWN;
190 //LOG(@"%s: tmp key %x", __PRETTY_FUNCTION__, keyCode);
191 if (keyCode == kGKKeyboardDirectionRight)
193 else if (keyCode == kGKKeyboardDirectionLeft)
195 else if (keyCode == kGKKeyboardDirectionDown)
197 else if (keyCode == kGKKeyboardDirectionUp)
201 //LOG(@"%s: tmp key unsupported :(", __PRETTY_FUNCTION__);
202 return; // not supported by us - return...
205 [g_xbmcController sendKey:key];
208 static void XBMCsendEvent(id _self, SEL _cmd, UIEvent *event)
210 // call super implementation
211 UIApplication$sendEvent$Orig(_self, _cmd, event);
213 if ([event respondsToSelector:@selector(_gsEvent)])
215 // Key events come in form of UIInternalEvents.
216 // They contain a GSEvent object which contains
217 // a GSEventRecord among other things
218 #pragma clang diagnostic push
219 #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
220 int *eventMem = (int *)[event performSelector:@selector(_gsEvent)];
221 #pragma clang diagnostic pop
225 // So far we got a GSEvent :)
226 int eventType = eventMem[GSEVENT_TYPE];
227 if (eventType == GSEVENT_TYPE_KEYUP)
229 // support 32 and 64bit arm here...
230 int idx = GSEVENTKEY_KEYCODE;
231 if (sizeof(NSInteger) == 8)
232 idx = GSEVENTKEY_KEYCODE_64_BIT;
233 else if (ios7Detected)
234 idx = GSEVENTKEY_KEYCODE_IOS7;
236 // Now we got a GSEventKey!
238 // Read flags from GSEvent
239 // for modifier keys if we want to use them somehow at a later time
240 //int eventFlags = eventMem[GSEVENT_FLAGS];
241 // Read keycode from GSEventKey
242 UniChar tmp = (UniChar)eventMem[idx];
249 // implicit called constructor for hooking into the sendEvent (ios < 7) or handleKeyUiEvent (ios 7 and later)
250 // this one hooks us into the keyboard events
251 __attribute__((constructor)) static void HookKeyboard(void)
253 if (sizeof(NSUInteger) == 8)
255 kGKKeyboardDirectionDown = 31;
256 kGKKeyboardDirectionUp = 30;
257 kGKKeyboardDirectionRight = 29;
258 kGKKeyboardDirectionLeft = 28;
259 LOG(@"Detected 64bit system!!!");
262 LOG(@"Detected 32bit system!!!");
264 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
266 // Hook into sendEvent: to get keyboard events.
267 #pragma clang diagnostic push
268 #pragma clang diagnostic ignored "-Wundeclared-selector"
269 if ([UIApplication instancesRespondToSelector:@selector(handleKeyUIEvent:)])
272 MSHookMessageEx(objc_getClass("UIApplication"), @selector(handleKeyUIEvent:), (IMP)&XBMCsendEvent, (IMP*)&UIApplication$sendEvent$Orig);
274 else if ([UIApplication instancesRespondToSelector:@selector(sendEvent:)])
275 MSHookMessageEx(objc_getClass("UIApplication"), @selector(sendEvent:), (IMP)&XBMCsendEvent, (IMP*)&UIApplication$sendEvent$Orig);
277 ELOG(@"HookKeyboard: Couldn't hook any of the 2 known keyboard hooks (sendEvent or handleKeyUIEvent - cursor keys on btkeyboards won't work!");
278 #pragma clang diagnostic pop
282 //---------------- HOOK FOR BT KEYBOARD CURSORS KEYS END----------------
284 int main(int argc, char *argv[]) {
285 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
289 // SIGPIPE repeatably kills us, turn it off
293 sigaddset(&set, SIGPIPE);
294 sigprocmask(SIG_BLOCK, &set, NULL);
299 retVal = UIApplicationMain(argc,argv,@"UIApplication",@"XBMCApplicationDelegate");
300 //UIApplicationMain(argc, argv, nil, nil);
302 @catch (id theException)
304 ELOG(@"%@", theException);
308 ILOG(@"This always happens.");