Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[atv2] - rewrite the XBMCAppliance and XBMCController for using obj-c…

… runtime class definition and hooking. This is needed for supporting atv2 on ios6 (see the comments in the impl.)
  • Loading branch information...
commit 71a68133ced1ec3a3e7ea8e198a71b159bd36885 1 parent e49ab72
@Memphiz Memphiz authored
View
8 XBMC-ATV2.xcodeproj/project.pbxproj
@@ -896,7 +896,7 @@
F56C7B89131EC155000AD0F6 /* Util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C780A131EC154000AD0F6 /* Util.cpp */; };
F56C7B8B131EC155000AD0F6 /* XBApplicationEx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C780E131EC154000AD0F6 /* XBApplicationEx.cpp */; };
F56C7B9B131EC1B4000AD0F6 /* AutoPool.mm in Sources */ = {isa = PBXBuildFile; fileRef = F56C7B9A131EC1B4000AD0F6 /* AutoPool.mm */; };
- F56C7BC9131EC2DB000AD0F6 /* XBMCAppliance.m in Sources */ = {isa = PBXBuildFile; fileRef = F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.m */; };
+ F56C7BC9131EC2DB000AD0F6 /* XBMCAppliance.mm in Sources */ = {isa = PBXBuildFile; fileRef = F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.mm */; };
F56C7BCA131EC2DB000AD0F6 /* XBMCController.mm in Sources */ = {isa = PBXBuildFile; fileRef = F56C7BC5131EC2DB000AD0F6 /* XBMCController.mm */; };
F56C7BD0131EC301000AD0F6 /* XBMC.png in Resources */ = {isa = PBXBuildFile; fileRef = F56C7BCD131EC301000AD0F6 /* XBMC.png */; };
F56C7BDC131EC390000AD0F6 /* WinEventsIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = F56C7BD9131EC390000AD0F6 /* WinEventsIOS.mm */; };
@@ -2973,7 +2973,7 @@
F56C780F131EC154000AD0F6 /* XBApplicationEx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBApplicationEx.h; sourceTree = "<group>"; };
F56C7B99131EC1B4000AD0F6 /* AutoPool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutoPool.h; sourceTree = "<group>"; };
F56C7B9A131EC1B4000AD0F6 /* AutoPool.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AutoPool.mm; sourceTree = "<group>"; };
- F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XBMCAppliance.m; sourceTree = "<group>"; };
+ F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = XBMCAppliance.mm; sourceTree = "<group>"; };
F56C7BC3131EC2DB000AD0F6 /* XBMCAppliance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBMCAppliance.h; sourceTree = "<group>"; };
F56C7BC4131EC2DB000AD0F6 /* XBMCController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBMCController.h; sourceTree = "<group>"; };
F56C7BC5131EC2DB000AD0F6 /* XBMCController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = XBMCController.mm; sourceTree = "<group>"; };
@@ -6015,7 +6015,7 @@
F56C7F2D131F0BB4000AD0F6 /* English.lproj */,
F56C7BCD131EC301000AD0F6 /* XBMC.png */,
F56C7BC3131EC2DB000AD0F6 /* XBMCAppliance.h */,
- F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.m */,
+ F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.mm */,
F56C7BCE131EC301000AD0F6 /* XBMCATV2-Info.plist */,
F56C7BC4131EC2DB000AD0F6 /* XBMCController.h */,
F56C7BC5131EC2DB000AD0F6 /* XBMCController.mm */,
@@ -7323,7 +7323,7 @@
F56C7B89131EC155000AD0F6 /* Util.cpp in Sources */,
F56C7B8B131EC155000AD0F6 /* XBApplicationEx.cpp in Sources */,
F56C7B9B131EC1B4000AD0F6 /* AutoPool.mm in Sources */,
- F56C7BC9131EC2DB000AD0F6 /* XBMCAppliance.m in Sources */,
+ F56C7BC9131EC2DB000AD0F6 /* XBMCAppliance.mm in Sources */,
F56C7BCA131EC2DB000AD0F6 /* XBMCController.mm in Sources */,
F56C7BDC131EC390000AD0F6 /* WinEventsIOS.mm in Sources */,
F56C7BDD131EC390000AD0F6 /* WinSystemIOS.mm in Sources */,
View
6 xbmc/osx/atv2/XBMCAppliance.h
@@ -28,4 +28,10 @@
XBMCTopShelfController *_topShelfController;
}
@property(nonatomic, readonly, retain) id topShelfController;
+
+- (id) initWithApplianceInfo:(id) applianceInfo;
+- (void) setTopShelfController:(id) topShelfControl;
+- (void) setApplianceCategories:(id) applianceCategories;
+- (void) XBMCfixUIDevice;
+- (id) init;
@end
View
218 xbmc/osx/atv2/XBMCAppliance.m
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Team XBMC
- * http://www.xbmc.org
- *
- * This Program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This Program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with XBMC; see the file COPYING. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#import <Foundation/Foundation.h>
-#import <UIKit/UIKit.h>
-#import <BackRow/BackRow.h>
-// objc-runtime.h is missing from iPhoneOS4.2SDK but present in iPhoneSimulator4.2.sdk
-// pull it from runtime system for now
-#import "/usr/include/objc/objc-runtime.h"
-
-#import "XBMCAppliance.h"
-#import "XBMCController.h"
-
-#define XBMCAppliance_CAT [BRApplianceCategory categoryWithName:@"XBMC" identifier:@"xbmc" preferredOrder:-5]
-
-// ATVVersionInfo declare to shut up compiler warning
-@interface ATVVersionInfo : NSObject
-{
-}
-+ (id)currentOSVersion;
-@end
-//--------------------------------------------------------------
-//--------------------------------------------------------------
-@interface BRTopShelfView (specialAdditions)
-//
-- (BRImageControl *)productImage;
-
-@end
-
-@implementation BRTopShelfView (specialAdditions)
-- (BRImageControl *)productImage
-{
- Ivar ivar = object_getInstanceVariable(self, "_productImage", NULL);
- id result = object_getIvar(self, ivar);
- return result;
-}
-@end
-
-//--------------------------------------------------------------
-//--------------------------------------------------------------
-@interface XBMCTopShelfController : NSObject
-{
-}
-- (void) selectCategoryWithIdentifier:(id)identifier;
-- (id) topShelfView;
-// added in 4.1+
-- (void) refresh;
-@end
-
-@implementation XBMCTopShelfController
-//
-- (void) selectCategoryWithIdentifier:(id)identifier
-{
-}
-
-- (BRTopShelfView *)topShelfView {
- BRTopShelfView *topShelf = [[BRTopShelfView alloc] init];
- BRImageControl *imageControl = [topShelf productImage];
- BRImage *gpImage = [BRImage imageWithPath:[[NSBundle bundleForClass:[XBMCAppliance class]] pathForResource:@"XBMC" ofType:@"png"]];
- [imageControl setImage:gpImage];
-
- return topShelf;
-}
-- (void) refresh
-{
-}
-@end
-
-//--------------------------------------------------------------
-//--------------------------------------------------------------
-@implementation XBMCAppliance
-@synthesize topShelfController=_topShelfController;
-
--(void)XBMCfixUIDevice
-{
- // iOS 5.x has removed the internal load of UIKit in AppleTV app
- // and there is an overlap of some UIKit and AppleTV methods.
- // This voodoo seems to clear up the wonkiness. :)
- Class cls = NSClassFromString(@"ATVVersionInfo");
- if (cls != nil && [[cls currentOSVersion] rangeOfString:@"5."].location != NSNotFound)
- {
- id cd = nil;
-
- @try
- {
- cd = [UIDevice currentDevice];
- }
-
- @catch (NSException *e)
- {
- NSLog(@"exception: %@", e);
- }
-
- @finally
- {
- //NSLog(@"will it work the second try?");
- cd = [UIDevice currentDevice];
- NSLog(@"current device fixed: %@", cd);
- }
- }
-}
-
--(id) init
-{
- //NSLog(@"%s", __PRETTY_FUNCTION__);
-
- if ((self = [super init]) != nil)
- {
- _topShelfController = [[XBMCTopShelfController alloc] init];
- _applianceCategories = [[NSArray alloc] initWithObjects:XBMCAppliance_CAT ,nil];
- }
-
- return self;
-}
-
-- (void) dealloc
-{
- //NSLog(@"%s", __PRETTY_FUNCTION__);
-
- [_applianceCategories release];
- [_topShelfController release];
-
- [super dealloc];
-}
-
-- (id) applianceCategories
-{
- // on ios 5.x this gets called whenever a user hits the xbmc icon
- // in the frontrow mainmenu
- // we use this indication for faking the "select" key.
- // This leads to a one click start of XBMC instead of needing
- // to hit select on the only XBMC category called "XBMC" again ;)
- Class cls = NSClassFromString(@"ATVVersionInfo");
- if (cls != nil && [[cls currentOSVersion] rangeOfString:@"5."].location != NSNotFound)
- {
- // eventaction 5 == kBREventRemoteActionPlay from XBMCController.m
- // value == 1 meanse we pressed that key
- BREvent *eventKeySelect = [BREvent eventWithAction:5 value:1];
- // when we suppress the sound below
- // this will even suppress the initial click
- // sound because this is threaded
- // thats why we just play that first click sound
- // directly here before suppressing the sounds
- // and doing the fake click (which would result in an unwanted
- // second click sound without that hack)
- [BRSoundHandler playSound:1];// sound number 1 is the ios click sound
- // ios >= 5 only - so ignore the compiler warning on older SDKs
- // since we guarded that code with the currentOSVersion above
- [BRSoundHandler setSoundSuppressed:TRUE];
- [[BRApplication sharedApplication] postEvent:eventKeySelect];
- }
-
- return _applianceCategories;
-}
-
-- (id) identifierForContentAlias:(id)contentAlias
-{
- return @"xbmc";
-}
-
-- (id) selectCategoryWithIdentifier:(id)ident
-{
- //NSLog(@"eglv2:selecteCategoryWithIdentifier: %@", ident);
-
- return nil;
-}
-- (BOOL) handleObjectSelection:(id)fp8 userInfo:(id)fp12
-{
- //NSLog(@"%s", __PRETTY_FUNCTION__);
-
- return YES;
-}
-
-- (id) applianceSpecificControllerForIdentifier:(id)arg1 args:(id)arg2
-{
- return nil;
-}
-- (BOOL) handlePlay:(id)play userInfo:(id)info
-{
- //NSLog(@"%s", __PRETTY_FUNCTION__);
-
- return YES;
-}
-
-- (id) controllerForIdentifier:(id)identifier args:(id)args
-{
- //NSLog(@"%s", __PRETTY_FUNCTION__);
-
- [self XBMCfixUIDevice];
- XBMCController *controller = [[[XBMCController alloc] init] autorelease];
- //XBMCController *controller = [XBMCController sharedInstance];
- return controller;
-}
-
-- (id) localizedSearchTitle { return @"xbmc"; }
-- (id) applianceName { return @"xbmc"; }
-- (id) moduleName { return @"xbmc"; }
-- (id) applianceKey { return @"xbmc"; }
-
-@end
-
View
433 xbmc/osx/atv2/XBMCAppliance.mm
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2010-2013 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+/* HowTo code in this file:
+ * Since AppleTV/iOS6.x (atv2 version 5.2) Apple removed the AppleTV.framework and put all those classes into the
+ * AppleTV.app. So we can't use standard obj-c coding here anymore. Instead we need to use the obj-c runtime
+ * functions for subclassing and adding methods to our instances during runtime (hooking).
+ *
+ * 1. For implementing a method of a base class:
+ * a) declare it in the form <XBMCAppliance$nameOfMethod> like the others
+ * b) these methods need to be static and have XBMCAppliance* self, SEL _cmd (replace XBMCAppliance with the class the method gets implemented for) as minimum params.
+ * c) add the method to the XBMCAppliance.h for getting rid of the compiler warnings of unresponsive selectors (declare the method like done in the baseclass).
+ * d) in initApplianceRuntimeClasses exchange the base class implementation with ours by calling MSHookMessageEx
+ * e) if we need to call the base class implementation as well we have to save the original implementation (see initWithApplianceInfo$Orig for reference)
+ *
+ * 2. For implementing a new method which is not part of the base class:
+ * a) same as 1.a
+ * b) same as 1.b
+ * c) same as 1.c
+ * d) in initApplianceRuntimeClasses add the method to our class via class_addMethod
+ *
+ * 3. Never access any BackRow classes directly - but always get the class via objc_getClass - if the class is used in multiple places
+ * save it as static (see BRApplianceCategoryCls)
+ *
+ * 4. Keep the structure of this file based on the section comments (marked with // SECTIONCOMMENT).
+ * 5. really - obey 4.!
+ *
+ * 6. for adding class members use associated objects - see topShelfControllerKey
+ *
+ * For further reference see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+// objc-runtime.h is missing from iPhoneOS4.2SDK but present in iPhoneSimulator4.2.sdk
+// pull it from runtime system for now
+#import "/usr/include/objc/objc-runtime.h"
+
+#import "XBMCAppliance.h"
+#import "XBMCController.h"
+#include "substrate.h"
+
+// SECTIONCOMMENT
+// classes we need multiple times
+static Class BRApplianceCategoryCls;
+
+// category for ios5.x and higher is just a short text before xbmc auto starts
+#define XBMCAppliance_CAT_5andhigher [BRApplianceCategoryCls categoryWithName:@"XBMC is starting..." identifier:@"xbmc" preferredOrder:0]
+// category for ios4.x is the menu entry
+#define XBMCAppliance_CAT_4 [BRApplianceCategoryCls categoryWithName:@"XBMC" identifier:@"xbmc" preferredOrder:0]
+
+// SECTIONCOMMENT
+// forward declaration all referenced classes
+@class XBMCAppliance;
+@class BRTopShelfView;
+@class XBMCApplianceInfo;
+
+// SECTIONCOMMENT
+// orig method handlers we wanna call in hooked methods
+static id (*XBMCAppliance$initWithApplianceInfo$Orig)(XBMCAppliance*, SEL, id);
+static id (*XBMCAppliance$init$Orig)(XBMCAppliance*, SEL);
+static id (*XBMCAppliance$applianceInfo$Orig)(XBMCAppliance*, SEL);
+
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+// ATVVersionInfo declare to shut up compiler warning
+@interface ATVVersionInfo : NSObject
+{
+}
++ (id)currentOSVersion;
+
+@end
+
+@interface XBMCATV2Detector : NSObject{}
++ (BOOL) hasOldGui;
++ (BOOL) isIos5;
++ (BOOL) needsApplianceInfoHack;
+@end
+
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+// We need a real implementation (not a runtime generated one)
+// for getting our NSBundle instance by calling
+// [[NSBundle bundleForClass:objc_getClass("XBMCATV2Detector")]
+// so we just implement some usefull helpers here
+// and use those
+@implementation XBMCATV2Detector : NSObject{}
++ (BOOL) hasOldGui
+{
+ Class cls = NSClassFromString(@"ATVVersionInfo");
+ if (cls != nil && [[cls currentOSVersion] rangeOfString:@"4."].location != NSNotFound)
+ return TRUE;
+ if (cls != nil && [[cls currentOSVersion] rangeOfString:@"5.0"].location != NSNotFound)
+ return TRUE;
+ return FALSE;
+}
+
++ (BOOL) isIos5
+{
+ Class cls = NSClassFromString(@"ATVVersionInfo");
+ if (cls != nil && [[cls currentOSVersion] rangeOfString:@"5."].location != NSNotFound)
+ return TRUE;
+ return FALSE;
+}
+
++ (BOOL) needsApplianceInfoHack
+{
+ // if the runtime base class (BRBaseAppliance) doesn't have the initWithApplianceInfo selector
+ // we need to hack the appliance info in (id) applianceInfo (XBMCAppliance$applianceInfo)
+ if (class_respondsToSelector(objc_getClass("BRBaseAppliance"),@selector(initWithApplianceInfo:)))
+ return FALSE;
+ return TRUE;
+}
+@end
+
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+// XBMCApplication declare to shut up compiler warning of BRApplication
+@interface XBMCApplication : NSObject
+{
+}
+- (void)setFirstResponder:(id)responder;
+@end
+
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+@interface XBMCTopShelfController : NSObject
+{
+}
+- (void) selectCategoryWithIdentifier:(id)identifier;
+- (id) topShelfView;
+// added in 4.1+
+- (void) refresh;
+@end
+
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+@implementation XBMCTopShelfController
+
+- (void) selectCategoryWithIdentifier:(id)identifier
+{
+}
+
+- (BRTopShelfView *)topShelfView
+{
+ Class cls = objc_getClass("BRTopShelfView");
+ id topShelf = [[cls alloc] init];
+
+ // diddle the topshelf logo on old gui
+ if ([XBMCATV2Detector hasOldGui])
+ {
+ Class cls = objc_getClass("BRImage");
+ BRImageControl *imageControl = (BRImageControl *)MSHookIvar<id>(topShelf, "_productImage");// hook the productImage so we can diddle with it
+ BRImage *gpImage = [cls imageWithPath:[[NSBundle bundleForClass:[XBMCATV2Detector class]] pathForResource:@"XBMC" ofType:@"png"]];
+ [imageControl setImage:gpImage];
+ }
+
+ return topShelf;
+}
+
+- (void) refresh
+{
+}
+@end
+
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+// SECTIONCOMMENT
+// since we can't inject ivars we need to use associated objects
+// these are the keys for XBMCAppliance
+//implementation XBMCAppliance
+static char const * const topShelfControllerKey = "topShelfController";
+static char const * const applianceCategoriesKey = "applianceCategories";
+
+static NSString* XBMCApplianceInfo$key(XBMCApplianceInfo* self, SEL _cmd)
+{
+ return [[[NSBundle bundleForClass:objc_getClass("XBMCATV2Detector")] infoDictionary] objectForKey:(NSString*)kCFBundleIdentifierKey];
+}
+
+static NSString* XBMCApplianceInfo$name(XBMCApplianceInfo* self, SEL _cmd)
+{
+ return [[[NSBundle bundleForClass:objc_getClass("XBMCATV2Detector")] infoDictionary] objectForKey:(NSString*)kCFBundleNameKey];
+}
+
+static id XBMCApplianceInfo$localizedStringsFileName(XBMCApplianceInfo* self, SEL _cmd)
+{
+ return @"xbmc";
+}
+
+static void XBMCAppliance$XBMCfixUIDevice(XBMCAppliance* self, SEL _cmd)
+{
+ // iOS 5.x has removed the internal load of UIKit in AppleTV app
+ // and there is an overlap of some UIKit and AppleTV methods.
+ // This voodoo seems to clear up the wonkiness. :)
+ if ([XBMCATV2Detector isIos5])
+ {
+ id cd = nil;
+
+ @try
+ {
+ cd = [UIDevice currentDevice];
+ }
+
+ @catch (NSException *e)
+ {
+ NSLog(@"exception: %@", e);
+ }
+
+ @finally
+ {
+ //NSLog(@"will it work the second try?");
+ cd = [UIDevice currentDevice];
+ NSLog(@"current device fixed: %@", cd);
+ }
+ }
+}
+
+
+static id XBMCAppliance$init(XBMCAppliance* self, SEL _cmd)
+{
+ //NSLog(@"%s", __PRETTY_FUNCTION__);
+ if ([XBMCATV2Detector needsApplianceInfoHack])
+ {
+ NSLog(@"%s for ios 4", __PRETTY_FUNCTION__);
+ if ((self = XBMCAppliance$init$Orig(self, _cmd))!= nil)
+ {
+ id topShelfControl = [[XBMCTopShelfController alloc] init];
+ [self setTopShelfController:topShelfControl];
+
+ NSArray *catArray = [[NSArray alloc] initWithObjects:XBMCAppliance_CAT_4,nil];
+ [self setApplianceCategories:catArray];
+ return self;
+ }
+ }
+ else// ios >= 5
+ {
+ NSLog(@"%s for ios 5 and newer", __PRETTY_FUNCTION__);
+ return [self initWithApplianceInfo:nil]; // legacy for ios < 6
+ }
+ return self;
+}
+
+static id XBMCAppliance$identifierForContentAlias(XBMCAppliance* self, SEL _cmd, id contentAlias)
+{
+ return@"xbmc";
+}
+
+static BOOL XBMCAppliance$handleObjectSelection(XBMCAppliance* self, SEL _cmd, id fp8, id fp12)
+{
+ //NSLog(@"%s", __PRETTY_FUNCTION__);
+ return YES;
+}
+
+static id XBMCAppliance$applianceInfo(XBMCAppliance* self, SEL _cmd)
+{
+ //NSLog(@"%s", __PRETTY_FUNCTION)
+
+ // load our plist into memory and merge it with
+ // the dict from the baseclass if needed
+ // cause ios seems to fail on that somehow (at least on 4.x)
+ if ([XBMCATV2Detector needsApplianceInfoHack] && self != nil)
+ {
+ id original = XBMCAppliance$applianceInfo$Orig(self, _cmd);
+ id info = MSHookIvar<id>(original, "_info");// hook the infoDictionary so we can diddle with it
+
+ NSString *plistPath = [[NSBundle bundleForClass:objc_getClass("XBMCATV2Detector")] pathForResource:@"Info" ofType:@"plist"];
+ NSString *bundlePath = [[NSBundle bundleForClass:objc_getClass("XBMCATV2Detector")] bundlePath];
+ NSMutableDictionary *ourInfoDict = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
+
+ if (ourInfoDict != nil && bundlePath != nil)
+ {
+ // inject this or we won't get shown up properly on ios4
+ [ourInfoDict setObject:bundlePath forKey:@"NSBundleInitialPath"];
+
+ // add our plist info to the baseclass info and return it
+ [(NSMutableDictionary *)info addEntriesFromDictionary:ourInfoDict];
+ [ourInfoDict release];
+ }
+ return original;
+ }
+ else
+ {
+ Class cls = objc_getClass("XBMCApplianceInfo");
+ return [[[cls alloc] init] autorelease];
+ }
+ return nil;
+}
+
+
+static id XBMCAppliance$topShelfController(XBMCAppliance* self, SEL _cmd)
+{
+ return objc_getAssociatedObject(self, topShelfControllerKey);
+}
+
+
+static void XBMCAppliance$setTopShelfController(XBMCAppliance* self, SEL _cmd, id topShelfControl)
+{
+ objc_setAssociatedObject(self, topShelfControllerKey, topShelfControl, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+static id XBMCAppliance$applianceCategories(XBMCAppliance* self, SEL _cmd)
+{
+ return objc_getAssociatedObject(self, applianceCategoriesKey);
+}
+
+static void XBMCAppliance$setApplianceCategories(XBMCAppliance* self, SEL _cmd, id applianceCategories)
+{
+ objc_setAssociatedObject(self, applianceCategoriesKey, applianceCategories, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+static id XBMCAppliance$initWithApplianceInfo(XBMCAppliance* self, SEL _cmd, id applianceInfo)
+{
+ //NSLog(@"%s", __PRETTY_FUNCTION__);
+ if((self = XBMCAppliance$initWithApplianceInfo$Orig(self, _cmd, applianceInfo)) != nil)
+ {
+ id topShelfControl = [[XBMCTopShelfController alloc] init];
+ [self setTopShelfController:topShelfControl];
+
+ NSArray *catArray = [[NSArray alloc] initWithObjects:XBMCAppliance_CAT_5andhigher,nil];
+ [self setApplianceCategories:catArray];
+ }
+ return self;
+}
+
+static id XBMCAppliance$controllerForIdentifier(XBMCAppliance* self, SEL _cmd, id identifier, id args)
+{
+ //NSLog(@"%s", __PRETTY_FUNCTION__);
+ id menuController = nil;
+ Class cls = objc_getClass("BRApplication");
+ if ([identifier isEqualToString:@"xbmc"])
+ {
+ [self XBMCfixUIDevice];
+ menuController = [[objc_getClass("XBMCController") alloc] init];
+ if (menuController == nil)
+ NSLog(@"initialise controller - fail");
+ }
+ XBMCApplication *brapp = (XBMCApplication *)[cls sharedApplication];
+ [brapp setFirstResponder:menuController];
+ return menuController;
+}
+
+// SECTIONCOMMENT
+// c'tor - this sets up our class at runtime by
+// 1. subclassing from the base classes
+// 2. adding new methods to our class
+// 3. exchanging (hooking) base class methods with ours
+// 4. register the classes to the objc runtime system
+static __attribute__((constructor)) void initApplianceRuntimeClasses()
+{
+ // subclass BRApplianceInfo into XBMCApplianceInfo
+ Class XBMCApplianceInfoCls = objc_allocateClassPair(objc_getClass("BRApplianceInfo"), "XBMCApplianceInfo", 0);
+
+ // and hook up our methods (implementation of the base class methods)
+ // XBMCApplianceInfo::key
+ MSHookMessageEx(XBMCApplianceInfoCls,@selector(key), (IMP)&XBMCApplianceInfo$key, nil);
+ // XBMCApplianceInfo::name
+ MSHookMessageEx(XBMCApplianceInfoCls,@selector(name), (IMP)&XBMCApplianceInfo$name, nil);
+
+ //not available in ios4.x - so probe or crash&burn
+ if (class_respondsToSelector(objc_getClass("BRApplianceInfo"),@selector(localizedStringsFileName)))
+ {
+ // XBMCApplianceInfo::localizedStringsFileName
+ MSHookMessageEx(XBMCApplianceInfoCls,@selector(localizedStringsFileName), (IMP)&XBMCApplianceInfo$localizedStringsFileName, nil);
+ }
+ else// else we need to add it
+ {
+ class_addMethod(XBMCApplianceInfoCls,@selector(localizedStringsFileName), (IMP)&XBMCApplianceInfo$localizedStringsFileName, "@@:");
+ }
+ // and register the class to the runtime
+ objc_registerClassPair(XBMCApplianceInfoCls);
+
+ // subclass BRBaseAppliance into XBMCAppliance
+ Class XBMCApplianceCls = objc_allocateClassPair(objc_getClass("BRBaseAppliance"), "XBMCAppliance", 0);
+ // add our custom methods which are not part of the baseclass
+ // XBMCAppliance::XBMCfixUIDevice
+ class_addMethod(XBMCApplianceCls,@selector(XBMCfixUIDevice), (IMP)XBMCAppliance$XBMCfixUIDevice, "v@:");
+ class_addMethod(XBMCApplianceCls,@selector(setTopShelfController:), (IMP)&XBMCAppliance$setTopShelfController, "v@:@");
+ class_addMethod(XBMCApplianceCls,@selector(setApplianceCategories:), (IMP)&XBMCAppliance$setApplianceCategories, "v@:@");
+
+ // and hook up our methods (implementation of the base class methods)
+ // XBMCAppliance::init
+ MSHookMessageEx(XBMCApplianceCls,@selector(init), (IMP)&XBMCAppliance$init, (IMP*)&XBMCAppliance$init$Orig);
+ // XBMCAppliance::identifierForContentAlias
+ MSHookMessageEx(XBMCApplianceCls,@selector(identifierForContentAlias:), (IMP)&XBMCAppliance$identifierForContentAlias, nil);
+
+ // not there in ios6 - probing for getting rid of the syslog warning
+ if (class_respondsToSelector(objc_getClass("BRBaseAppliance"),@selector(handleObjectSelection:userInfo:)))
+ {
+ // XBMCAppliance::handleObjectSelection
+ MSHookMessageEx(XBMCApplianceCls,@selector(handleObjectSelection:userInfo:), (IMP)&XBMCAppliance$handleObjectSelection, nil);
+ }
+
+ // XBMCAppliance::applianceInfo
+ MSHookMessageEx(XBMCApplianceCls,@selector(applianceInfo), (IMP)&XBMCAppliance$applianceInfo, (IMP *)&XBMCAppliance$applianceInfo$Orig);
+ // XBMCAppliance::topShelfController
+ MSHookMessageEx(XBMCApplianceCls,@selector(topShelfController), (IMP)&XBMCAppliance$topShelfController, nil);
+ // XBMCAppliance::applianceCategories
+ MSHookMessageEx(XBMCApplianceCls,@selector(applianceCategories), (IMP)&XBMCAppliance$applianceCategories, nil);
+
+ // not there on ios 4.x - probing ...
+ if (class_respondsToSelector(objc_getClass("BRBaseAppliance"),@selector(initWithApplianceInfo:)))
+ {
+ // XBMCAppliance::initWithApplianceInfo
+ MSHookMessageEx(XBMCApplianceCls,@selector(initWithApplianceInfo:), (IMP)&XBMCAppliance$initWithApplianceInfo, (IMP*)&XBMCAppliance$initWithApplianceInfo$Orig);
+ }
+
+ // XBMCAppliance::controllerForIdentifier
+ MSHookMessageEx(XBMCApplianceCls,@selector(controllerForIdentifier:args:), (IMP)&XBMCAppliance$controllerForIdentifier, nil);
+
+ // and register the class to the runtime
+ objc_registerClassPair(XBMCApplianceCls);
+
+ // save this as static for referencing it in the macro at the top of the file
+ BRApplianceCategoryCls = objc_getClass("BRApplianceCategory");
+}
View
13 xbmc/osx/atv2/XBMCController.h
@@ -58,7 +58,18 @@
- (void) stopAnimation;
- (bool) changeScreen: (unsigned int)screenIdx withMode:(UIScreenMode *)mode;
- (void) activateScreen: (UIScreen *)screen;
-
+- (id) glView;
+- (void) setGlView:(id)view;
+- (BOOL) ATVClientEventFromBREvent:(id)event Repeatable:(bool *)isRepeatable ButtonState:(bool *)isPressed Result:(int *)xbmc_ir_key;
+- (void) setUserEvent:(int) eventId withHoldTime:(unsigned int) holdTime;
+- (void) startKeyPressTimer:(int) keyId;
+- (void) stopKeyPressTimer;
+- (void) setSystemSleepTimeout:(id) timeout;
+- (id) systemSleepTimeout;
+- (void) setKeyTimer:(id) timer;
+- (id) keyTimer;
+- (void) setSystemScreenSaverTimeout:(id) timeout;
+- (id) systemScreenSaverTimeout;
@end
View
1,376 xbmc/osx/atv2/XBMCController.mm
@@ -18,6 +18,36 @@
*
*/
+
+/* HowTo code in this file:
+ * Since AppleTV/iOS6.x (atv2 version 5.2) Apple removed the AppleTV.framework and put all those classes into the
+ * AppleTV.app. So we can't use standard obj-c coding here anymore. Instead we need to use the obj-c runtime
+ * functions for subclassing and adding methods to our instances during runtime (hooking).
+ *
+ * 1. For implementing a method of a base class:
+ * a) declare it in the form <XBMCController$nameOfMethod> like the others
+ * b) these methods need to be static and have XBMCController* self, SEL _cmd (replace XBMCAppliance with the class the method gets implemented for) as minimum params.
+ * c) add the method to the XBMCController.h for getting rid of the compiler warnings of unresponsive selectors (declare the method like done in the baseclass).
+ * d) in initControllerRuntimeClasses exchange the base class implementation with ours by calling MSHookMessageEx
+ * e) if we need to call the base class implementation as well we have to save the original implementation (see brEventAction$Orig for reference)
+ *
+ * 2. For implementing a new method which is not part of the base class:
+ * a) same as 1.a
+ * b) same as 1.b
+ * c) same as 1.c
+ * d) in initControllerRuntimeClasses add the method to our class via class_addMethod
+ *
+ * 3. Never access any BackRow classes directly - but always get the class via objc_getClass - if the class is used in multiple places
+ * save it as static (see BRWindowCls)
+ *
+ * 4. Keep the structure of this file based on the section comments (marked with // SECTIONCOMMENT).
+ * 5. really - obey 4.!
+ *
+ * 6. for adding class members use associated objects - see timerKey
+ *
+ * For further reference see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html
+ */
+
//hack around problem with xbmc's typedef int BOOL
// and obj-c's typedef unsigned char BOOL
#define BOOL XBMC_BOOL
@@ -31,13 +61,17 @@
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
-#import <BackRow/BackRow.h>
#import "XBMCController.h"
#import "XBMCDebugHelpers.h"
+#import "IOSEAGLView.h"
+#import "IOSSCreenManager.h"
+#include "XBMC_keysym.h"
+#include "substrate.h"
+
//start repeating after 0.5s
-#define REPEATED_KEYPRESS_DELAY_S 0.5
+#define REPEATED_KEYPRESS_DELAY_S 0.5
//pause 0.01s (10ms) between keypresses
#define REPEATED_KEYPRESS_PAUSE_S 0.01
@@ -58,7 +92,7 @@
ATV_ALUMINIUM_PLAY = 12,
ATV_ALUMINIUM_PLAY_H = 11,
- //newly added remote buttons
+ //newly added remote buttons
ATV_BUTTON_PAGEUP = 13,
ATV_BUTTON_PAGEDOWN = 14,
ATV_BUTTON_PAUSE = 15,
@@ -102,6 +136,7 @@
ATV_INVALID_BUTTON
} eATVClientEvent;
+
typedef enum {
// for originator kBREventOriginatorRemote
kBREventRemoteActionMenu = 1,
@@ -157,410 +192,504 @@
kBREventRemoteActionHoldDown,
} BREventRemoteAction;
+
XBMCController *g_xbmcController;
//--------------------------------------------------------------
// so we don't have to include AppleTV.frameworks/PrivateHeaders/ATVSettingsFacade.h
-@interface ATVSettingsFacade : BRSettingsFacade {}
+@interface XBMCSettingsFacade : NSObject
-(int)screenSaverTimeout;
-(void)setScreenSaverTimeout:(int) f_timeout;
-(void)setSleepTimeout:(int)timeout;
-(int)sleepTimeout;
+-(void)flushDiskChanges;
@end
// notification messages
extern NSString* kBRScreenSaverActivated;
extern NSString* kBRScreenSaverDismissed;
+
//--------------------------------------------------------------
//--------------------------------------------------------------
-@interface XBMCController (PrivateMethods)
-- (void) observeDefaultCenterStuff: (NSNotification *) notification;
-- (void) keyPressTimerCallback: (NSTimer*)theTimer;
-- (void) startKeyPressTimer: (int) keyId;
-- (void) stopKeyPressTimer;
-- (void) setUserEvent:(int) id withHoldTime:(unsigned int) holdTime;
-@end
+// SECTIONCOMMENT
+// orig method handlers we wanna call in hooked methods ([super method])
+static BOOL (*XBMCController$brEventAction$Orig)(XBMCController*, SEL, BREvent*);
+static id (*XBMCController$init$Orig)(XBMCController*, SEL);
+static void (*XBMCController$dealloc$Orig)(XBMCController*, SEL);
+static void (*XBMCController$controlWasActivated$Orig)(XBMCController*, SEL);
+static void (*XBMCController$controlWasDeactivated$Orig)(XBMCController*, SEL);
+
+// SECTIONCOMMENT
+// classes we need multiple times
+static Class BRWindowCls;
+
+int padding[16];//obsolete? - was commented with "credit is due here to SapphireCompatibilityClasses!!"
+
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+// SECTIONCOMMENT
+// since we can't inject ivars we need to use associated objects
+// these are the keys for XBMCController
+static char const * const timerKey = "m_keyTimer";
+static char const * const glviewKey = "m_glView";
+static char const * const screensaverKey = "m_screenSaverTimeout";
+static char const * const systemsleepKey = "m_systemsleepTimeout";
+
//
//
-@implementation XBMCController
+// SECTIONCOMMENT
+//implementation XBMCController
+
+static id XBMCController$keyTimer(XBMCController* self, SEL _cmd)
+{
+ return objc_getAssociatedObject(self, timerKey);
+}
-/*
-+ (XBMCController*) sharedInstance
-{
- // the instance of this class is stored here
- static XBMCController *myInstance = nil;
+static void XBMCController$setKeyTimer(XBMCController* self, SEL _cmd, id timer)
+{
+ objc_setAssociatedObject(self, timerKey, timer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
- // check to see if an instance already exists
- if (nil == myInstance)
- myInstance = [[[[self class] alloc] init] autorelease];
+static id XBMCController$glView(XBMCController* self, SEL _cmd)
+{
+ return objc_getAssociatedObject(self, glviewKey);
+}
+
+static void XBMCController$setGlView(XBMCController* self, SEL _cmd, id view)
+{
+ objc_setAssociatedObject(self, glviewKey, view, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
- // return the instance of this class
- return myInstance;
+static id XBMCController$systemScreenSaverTimeout(XBMCController* self, SEL _cmd)
+{
+ return objc_getAssociatedObject(self, screensaverKey);
}
-*/
-- (void) applicationDidExit
+static void XBMCController$setSystemScreenSaverTimeout(XBMCController* self, SEL _cmd, id timeout)
+{
+ objc_setAssociatedObject(self, screensaverKey, timeout, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+static id XBMCController$systemSleepTimeout(XBMCController* self, SEL _cmd)
+{
+ return objc_getAssociatedObject(self, systemsleepKey);
+}
+
+static void XBMCController$setSystemSleepTimeout(XBMCController* self, SEL _cmd, id timeout)
+{
+ objc_setAssociatedObject(self, systemsleepKey, timeout, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+static void XBMCController$applicationDidExit(XBMCController* self, SEL _cmd)
{
- [m_glView stopAnimation];
+ //NSLog(@"%s", __PRETTY_FUNCTION__);
+ [[self glView] stopAnimation];
[self enableScreenSaver];
[self enableSystemSleep];
-
[[self stack] popController];
}
-- (void) initDisplayLink
+
+static void XBMCController$initDisplayLink(XBMCController* self, SEL _cmd)
{
- [m_glView initDisplayLink];
+ //NSLog(@"%s", __PRETTY_FUNCTION__);
+
+ [[self glView] initDisplayLink];
}
-- (void) deinitDisplayLink
+
+static void XBMCController$deinitDisplayLink(XBMCController* self, SEL _cmd)
{
- [m_glView deinitDisplayLink];
+ //NSLog(@"%s", __PRETTY_FUNCTION__);
+
+ [[self glView] deinitDisplayLink];
}
-- (double) getDisplayLinkFPS
+
+static double XBMCController$getDisplayLinkFPS(XBMCController* self, SEL _cmd)
{
- return [m_glView getDisplayLinkFPS];
+ //NSLog(@"%s", __PRETTY_FUNCTION__);
+
+ return [[self glView] getDisplayLinkFPS];
}
-- (void) setFramebuffer
-{
- [m_glView setFramebuffer];
+
+static void XBMCController$setFramebuffer(XBMCController* self, SEL _cmd)
+{
+ [[self glView] setFramebuffer];
}
-- (bool) presentFramebuffer
-{
- return [m_glView presentFramebuffer];
+
+static bool XBMCController$presentFramebuffer(XBMCController* self, SEL _cmd)
+{
+ return [[self glView] presentFramebuffer];
}
-- (CGSize) getScreenSize
+
+static CGSize XBMCController$getScreenSize(XBMCController* self, SEL _cmd)
{
CGSize screensize;
-
- screensize.width = [BRWindow interfaceFrame].size.width;
- screensize.height = [BRWindow interfaceFrame].size.height;
-
+ screensize.width = [BRWindowCls interfaceFrame].size.width;
+ screensize.height = [BRWindowCls interfaceFrame].size.height;
//NSLog(@"%s UpdateResolutions width=%f, height=%f",
- // __PRETTY_FUNCTION__, screensize.width, screensize.height);
-
+ //__PRETTY_FUNCTION__, screensize.width, screensize.height);
return screensize;
}
-- (void) sendKey: (XBMCKey) key
+
+static void XBMCController$sendKey(XBMCController* self, SEL _cmd, XBMCKey key)
{
//empty because its not used here. Only implemented for getting rid
//of "may not respond to selector" compile warnings in IOSExternalTouchController
}
-
-- (id) init
-{
- //NSLog(@"%s", __PRETTY_FUNCTION__);
-
- self = [super init];
- if ( !self )
- return ( nil );
-
- NSNotificationCenter *center;
- // first the default notification center, which is all
- // notifications that only happen inside of our program
- center = [NSNotificationCenter defaultCenter];
- [center addObserver: self
- selector: @selector(observeDefaultCenterStuff:)
- name: nil
- object: nil];
-
- m_glView = [[IOSEAGLView alloc] initWithFrame:[BRWindow interfaceFrame] withScreen:[UIScreen mainScreen]];
- [[IOSScreenManager sharedInstance] setView:m_glView];
-
- g_xbmcController = self;
-
+static id XBMCController$init(XBMCController* self, SEL _cmd)
+{
+ if((self = XBMCController$init$Orig(self, _cmd)) != nil)
+ {
+ //NSLog(@"%s", __PRETTY_FUNCTION__);
+
+ NSNotificationCenter *center;
+ // first the default notification center, which is all
+ // notifications that only happen inside of our program
+ center = [NSNotificationCenter defaultCenter];
+ [center addObserver: self
+ selector: @selector(observeDefaultCenterStuff:)
+ name: nil
+ object: nil];
+
+ IOSEAGLView *view = [[IOSEAGLView alloc] initWithFrame:[BRWindowCls interfaceFrame] withScreen:[UIScreen mainScreen]];
+ [self setGlView:view];
+
+ [[IOSScreenManager sharedInstance] setView:[self glView]];
+
+ g_xbmcController = self;
+ }
return self;
}
-- (void)dealloc
+static void XBMCController$dealloc(XBMCController* self, SEL _cmd)
{
//NSLog(@"%s", __PRETTY_FUNCTION__);
- [m_glView stopAnimation];
- [m_glView release];
-
+ [[self glView] stopAnimation];
+ [[self glView] release];
NSNotificationCenter *center;
// take us off the default center for our app
center = [NSNotificationCenter defaultCenter];
[center removeObserver: self];
- [super dealloc];
+ XBMCController$dealloc$Orig(self, _cmd);
}
-- (void)controlWasActivated
+static void XBMCController$controlWasActivated(XBMCController* self, SEL _cmd)
{
//NSLog(@"%s", __PRETTY_FUNCTION__);
-
- [super controlWasActivated];
+
+ XBMCController$controlWasActivated$Orig(self, _cmd);
[self disableSystemSleep];
[self disableScreenSaver];
-
+
+ IOSEAGLView *view = [self glView];
//inject our gles layer into the backrow root layer
- [[BRWindow rootLayer] addSublayer:m_glView.layer];
+ [[BRWindowCls rootLayer] addSublayer:view.layer];
- [m_glView startAnimation];
+ [[self glView] startAnimation];
}
-- (void)controlWasDeactivated
+static void XBMCController$controlWasDeactivated(XBMCController* self, SEL _cmd)
{
NSLog(@"XBMC was forced by FrontRow to exit via controlWasDeactivated");
- [m_glView stopAnimation];
- [m_glView.layer removeFromSuperlayer];
+ [[self glView] stopAnimation];
+ [[[self glView] layer] removeFromSuperlayer];
[self enableScreenSaver];
[self enableSystemSleep];
- [super controlWasDeactivated];
+ XBMCController$controlWasDeactivated$Orig(self, _cmd);
}
-- (BOOL) recreateOnReselect
-{
+static BOOL XBMCController$recreateOnReselect(XBMCController* self, SEL _cmd)
+{
//NSLog(@"%s", __PRETTY_FUNCTION__);
return YES;
}
-- (eATVClientEvent) ATVClientEventFromBREvent:(BREvent*) f_event
- Repeatable:(bool &) isRepeatable
- ButtonState:(bool &) isPressed
+static void XBMCController$ATVClientEventFromBREvent(XBMCController* self, SEL _cmd, BREvent* f_event, bool * isRepeatable, bool * isPressed, int * result)
{
+ if(f_event == nil)// paranoia
+ return;
+
int remoteAction = [f_event remoteAction];
CLog::Log(LOGDEBUG,"XBMCPureController: Button press remoteAction = %i", remoteAction);
- isRepeatable = false;
- isPressed = false;
+ *isRepeatable = false;
+ *isPressed = false;
switch (remoteAction)
{
// tap up
case kBREventRemoteActionUp:
case 65676:
- isRepeatable = true;
+ *isRepeatable = true;
if([f_event value] == 1)
- isPressed = true;
- return ATV_BUTTON_UP;
+ *isPressed = true;
+ *result = ATV_BUTTON_UP;
+ return;
// tap down
case kBREventRemoteActionDown:
case 65677:
- isRepeatable = true;
+ *isRepeatable = true;
if([f_event value] == 1)
- isPressed = true;
- return ATV_BUTTON_DOWN;
-
+ *isPressed = true;
+ *result = ATV_BUTTON_DOWN;
+ return;
+
// tap left
case kBREventRemoteActionLeft:
case 65675:
- isRepeatable = true;
+ *isRepeatable = true;
if([f_event value] == 1)
- isPressed = true;
- return ATV_BUTTON_LEFT;
-
+ *isPressed = true;
+ *result = ATV_BUTTON_LEFT;
+ return;
+
// hold left
case 786612:
if([f_event value] == 1)
- return ATV_LEARNED_REWIND;
+ *result = ATV_LEARNED_REWIND;
else
- return ATV_INVALID_BUTTON;
-
+ *result = ATV_INVALID_BUTTON;
+ return;
+
// tap right
case kBREventRemoteActionRight:
case 65674:
- isRepeatable = true;
+ *isRepeatable = true;
if ([f_event value] == 1)
- isPressed = true;
- return ATV_BUTTON_RIGHT;
-
+ *isPressed = true;
+ *result = ATV_BUTTON_RIGHT;
+ return ;
+
// hold right
case 786611:
if ([f_event value] == 1)
- return ATV_LEARNED_FORWARD;
+ *result = ATV_LEARNED_FORWARD;
else
- return ATV_INVALID_BUTTON;
-
+ *result = ATV_INVALID_BUTTON;
+ return ;
+
// tap play
case kBREventRemoteActionPlay:
case 65673:
- return ATV_BUTTON_PLAY;
-
+ *result = ATV_BUTTON_PLAY;
+ return ;
+
// hold play
case kBREventRemoteActionPlayHold:
case kBREventRemoteActionCenterHold:
case kBREventRemoteActionCenterHold42:
case 65668:
- return ATV_BUTTON_PLAY_H;
-
+ *result = ATV_BUTTON_PLAY_H;
+ return ;
+
// menu
case kBREventRemoteActionMenu:
case 65670:
- return ATV_BUTTON_MENU;
-
+ *result = ATV_BUTTON_MENU;
+ return ;
+
// hold menu
case kBREventRemoteActionMenuHold:
case 786496:
- return ATV_BUTTON_MENU_H;
-
+ *result = ATV_BUTTON_MENU_H;
+ return ;
+
// learned play
case 786608:
- return ATV_LEARNED_PLAY;
-
+ *result = ATV_LEARNED_PLAY;
+ return ;
+
// learned pause
case 786609:
- return ATV_LEARNED_PAUSE;
-
+ *result = ATV_LEARNED_PAUSE;
+ return ;
+
// learned stop
case 786615:
- return ATV_LEARNED_STOP;
-
+ *result = ATV_LEARNED_STOP;
+ return ;
+
// learned next
case 786613:
- return ATV_LEARNED_NEXT;
-
+ *result = ATV_LEARNED_NEXT;
+ return ;
+
// learned previous
case 786614:
- return ATV_LEARNED_PREVIOUS;
-
+ *result = ATV_LEARNED_PREVIOUS;
+ return ;
+
// learned enter, like go into something
case 786630:
- return ATV_LEARNED_ENTER;
-
+ *result = ATV_LEARNED_ENTER;
+ return ;
+
// learned return, like go back
case 786631:
- return ATV_LEARNED_RETURN;
-
+ *result = ATV_LEARNED_RETURN;
+ return ;
+
// tap play on new Al IR remote
case kBREventRemoteActionALPlay:
case 786637:
- return ATV_ALUMINIUM_PLAY;
+ *result = ATV_ALUMINIUM_PLAY;
+ return ;
case kBREventRemoteActionKeyPress:
case kBREventRemoteActionKeyPress42:
- return ATV_BTKEYPRESS;
-
+ *result = ATV_BTKEYPRESS;
+ return ;
+
// PageUp
case kBREventRemoteActionPageUp:
- return ATV_BUTTON_PAGEUP;
-
+ *result = ATV_BUTTON_PAGEUP;
+ return ;
+
// PageDown
case kBREventRemoteActionPageDown:
- return ATV_BUTTON_PAGEDOWN;
-
+ *result = ATV_BUTTON_PAGEDOWN;
+ return ;
+
// Pause
case kBREventRemoteActionPause:
- return ATV_BUTTON_PAUSE;
-
+ *result = ATV_BUTTON_PAUSE;
+ return ;
+
// Play2
case kBREventRemoteActionPlay2:
- return ATV_BUTTON_PLAY2;
-
+ *result = ATV_BUTTON_PLAY2;
+ return ;
+
// Stop
case kBREventRemoteActionStop:
- return ATV_BUTTON_STOP;
-
+ *result = ATV_BUTTON_STOP;
+ return ;
+
// Fast Forward
case kBREventRemoteActionFastFwd:
- return ATV_BUTTON_FASTFWD;
-
+ *result = ATV_BUTTON_FASTFWD;
+ return ;
+
// Rewind
case kBREventRemoteActionRewind:
- return ATV_BUTTON_REWIND;
+ *result = ATV_BUTTON_REWIND;
+ return ;
// Skip Forward
case kBREventRemoteActionSkipFwd:
- return ATV_BUTTON_SKIPFWD;
+ *result = ATV_BUTTON_SKIPFWD;
+ return ;
- // Skip Back
+ // Skip Back
case kBREventRemoteActionSkipBack:
- return ATV_BUTTON_SKIPBACK;
-
+ *result = ATV_BUTTON_SKIPBACK;
+ return ;
+
// Gesture Swipe Left
case kBREventRemoteActionSwipeLeft:
if ([f_event value] == 1)
- return ATV_GESTURE_SWIPE_LEFT;
+ *result = ATV_GESTURE_SWIPE_LEFT;
else
- return ATV_INVALID_BUTTON;
-
+ *result = ATV_INVALID_BUTTON;
+ return ;
+
// Gesture Swipe Right
case kBREventRemoteActionSwipeRight:
if ([f_event value] == 1)
- return ATV_GESTURE_SWIPE_RIGHT;
+ *result = ATV_GESTURE_SWIPE_RIGHT;
else
- return ATV_INVALID_BUTTON;
+ *result = ATV_INVALID_BUTTON;
+ return ;
// Gesture Swipe Up
case kBREventRemoteActionSwipeUp:
if ([f_event value] == 1)
- return ATV_GESTURE_SWIPE_UP;
+ *result = ATV_GESTURE_SWIPE_UP;
else
- return ATV_INVALID_BUTTON;
-
+ *result = ATV_INVALID_BUTTON;
+ return ;
+
// Gesture Swipe Down
case kBREventRemoteActionSwipeDown:
if ([f_event value] == 1)
- return ATV_GESTURE_SWIPE_DOWN;
+ *result = ATV_GESTURE_SWIPE_DOWN;
else
- return ATV_INVALID_BUTTON;
+ *result = ATV_INVALID_BUTTON;
+ return;
// Gesture Flick Left
case kBREventRemoteActionFlickLeft:
if ([f_event value] == 1)
- return ATV_GESTURE_FLICK_LEFT;
+ *result = ATV_GESTURE_FLICK_LEFT;
else
- return ATV_INVALID_BUTTON;
-
+ *result = ATV_INVALID_BUTTON;
+ return;
+
// Gesture Flick Right
case kBREventRemoteActionFlickRight:
if ([f_event value] == 1)
- return ATV_GESTURE_FLICK_RIGHT;
+ *result = ATV_GESTURE_FLICK_RIGHT;
else
- return ATV_INVALID_BUTTON;
-
+ *result = ATV_INVALID_BUTTON;
+ return;
+
// Gesture Flick Up
case kBREventRemoteActionFlickUp:
if ([f_event value] == 1)
- return ATV_GESTURE_FLICK_UP;
+ *result = ATV_GESTURE_FLICK_UP;
else
- return ATV_INVALID_BUTTON;
-
+ *result = ATV_INVALID_BUTTON;
+ return;
+
// Gesture Flick Down
case kBREventRemoteActionFlickDown:
if ([f_event value] == 1)
- return ATV_GESTURE_FLICK_DOWN;
+ *result = ATV_GESTURE_FLICK_DOWN;
else
- return ATV_INVALID_BUTTON;
-
-
+ *result = ATV_INVALID_BUTTON;
+ return;
default:
ELOG(@"XBMCPureController: Unknown button press remoteAction = %i", remoteAction);
- return ATV_INVALID_BUTTON;
+ *result = ATV_INVALID_BUTTON;
}
}
-- (void)setUserEvent:(int) id withHoldTime:(unsigned int) holdTime
+static void XBMCController$setUserEvent(XBMCController* self, SEL _cmd, int eventId, unsigned int holdTime)
{
+
XBMC_Event newEvent;
memset(&newEvent, 0, sizeof(newEvent));
newEvent.type = XBMC_USEREVENT;
- newEvent.jbutton.which = id;
+ newEvent.jbutton.which = eventId;
newEvent.jbutton.holdTime = holdTime;
CWinEventsIOS::MessagePush(&newEvent);
}
-- (BOOL)brEventAction:(BREvent*)event
+
+static BOOL XBMCController$brEventAction(XBMCController* self, SEL _cmd, BREvent* event)
{
//NSLog(@"%s", __PRETTY_FUNCTION__);
- if ([m_glView isAnimating])
+ if ([[self glView] isAnimating])
{
BOOL is_handled = NO;
bool isRepeatable = false;
bool isPressed = false;
- eATVClientEvent xbmc_ir_key = [self ATVClientEventFromBREvent:event
- Repeatable:isRepeatable
- ButtonState:isPressed];
-
+ int xbmc_ir_key = ATV_INVALID_BUTTON;
+ [self ATVClientEventFromBREvent:event
+ Repeatable:&isRepeatable
+ ButtonState:&isPressed
+ Result:&xbmc_ir_key];
+
if ( xbmc_ir_key != ATV_INVALID_BUTTON )
{
if (xbmc_ir_key == ATV_BTKEYPRESS && [event value] == 1)
@@ -579,7 +708,7 @@ - (BOOL)brEventAction:(BREvent*)event
const char* wstr = [key_nsstring cStringUsingEncoding:NSUTF16StringEncoding];
//NSLog(@"%s, key: wstr[0] = %d, wstr[1] = %d", __PRETTY_FUNCTION__, wstr[0], wstr[1]);
- if (wstr[0] != 92) // trap out "\" which toggle fullscreen/windowed
+ if (wstr[0] != 92)
{
if (wstr[0] == 62 && wstr[1] == -9)
{
@@ -607,8 +736,8 @@ - (BOOL)brEventAction:(BREvent*)event
{
if(isPressed)
{
- [self setUserEvent:xbmc_ir_key withHoldTime:0]; //fire event
- [self startKeyPressTimer:xbmc_ir_key];//start repeat timer
+ [self setUserEvent:xbmc_ir_key withHoldTime:0];
+ [self startKeyPressTimer:xbmc_ir_key];
}
else
{
@@ -618,60 +747,62 @@ - (BOOL)brEventAction:(BREvent*)event
}
else
{
- [self setUserEvent:xbmc_ir_key withHoldTime:0];
+ [self setUserEvent:xbmc_ir_key withHoldTime:0];
}
is_handled = TRUE;
}
}
return is_handled;
- }
+ }
else
{
- return [super brEventAction:event];
- }
+ return XBMCController$brEventAction$Orig(self, _cmd, event);
+ }
}
#pragma mark -
#pragma mark private helper methods
-- (void)startKeyPressTimer: (int) keyId
+static void XBMCController$startKeyPressTimer(XBMCController* self, SEL _cmd, int keyId)
{
- NSNumber *number = [NSNumber numberWithInt:keyId];
+ NSNumber *number = [NSNumber numberWithInt:keyId];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSDate date], @"StartDate",
number, @"keyId", nil];
- NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:REPEATED_KEYPRESS_DELAY_S];
-
+ NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:REPEATED_KEYPRESS_DELAY_S];
[self stopKeyPressTimer];
-
+
//schedule repeated timer which starts after REPEATED_KEYPRESS_DELAY_S and fires
//every REPEATED_KEYPRESS_PAUSE_S
- m_keyTimer = [[NSTimer alloc] initWithFireDate:fireDate
+ NSTimer *timer = [[NSTimer alloc] initWithFireDate:fireDate
interval:REPEATED_KEYPRESS_PAUSE_S
target:self
selector:@selector(keyPressTimerCallback:)
userInfo:dict
- repeats:YES];
+ repeats:YES];
+
//schedule the timer to the runloop
- NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
- [runLoop addTimer:m_keyTimer forMode:NSDefaultRunLoopMode];
+ NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
+ [runLoop addTimer:timer forMode:NSDefaultRunLoopMode];
+ [self setKeyTimer:timer];
}
-- (void)stopKeyPressTimer
+static void XBMCController$stopKeyPressTimer(XBMCController* self, SEL _cmd)
{
- if(m_keyTimer != nil)
+ if([self keyTimer] != nil)
{
- [m_keyTimer invalidate];
- [m_keyTimer release];
- m_keyTimer = nil;
+ [[self keyTimer] invalidate];
+ [[self keyTimer] release];
+ [self setKeyTimer:nil];
}
}
-- (void)keyPressTimerCallback:(NSTimer*)theTimer
+static void XBMCController$keyPressTimerCallback(XBMCController* self, SEL _cmd, NSTimer* theTimer)
{
//if queue is empty - skip this timer event
//for letting it process
if(CWinEventsIOS::GetQueueSize())
return;
+
NSDate *startDate = [[theTimer userInfo] objectForKey:@"StartDate"];
int keyId = [[[theTimer userInfo] objectForKey:@"keyId"] intValue];
//calc the holdTime - timeIntervalSinceNow gives the
@@ -681,14 +812,13 @@ - (void)keyPressTimerCallback:(NSTimer*)theTimer
[self setUserEvent:keyId withHoldTime:(unsigned int)holdTime];
}
-//
-- (void)observeDefaultCenterStuff: (NSNotification *) notification
+static void XBMCController$observeDefaultCenterStuff(XBMCController* self, SEL _cmd, NSNotification * notification)
{
//NSLog(@"default: %@", [notification name]);
if ([notification name] == UIApplicationDidReceiveMemoryWarningNotification)
NSLog(@"XBMC: %@", [notification name]);
-
+
//if ([notification name] == kBRScreenSaverActivated)
// [m_glView stopAnimation];
@@ -696,378 +826,578 @@ - (void)observeDefaultCenterStuff: (NSNotification *) notification
// [m_glView startAnimation];
}
-- (void) disableSystemSleep
+static void XBMCController$disableSystemSleep(XBMCController* self, SEL _cmd)
{
- m_systemsleepTimeout = [[ATVSettingsFacade singleton] sleepTimeout];
- [[ATVSettingsFacade singleton] setSleepTimeout: -1];
- [[ATVSettingsFacade singleton] flushDiskChanges];
+ Class ATVSettingsFacadeCls = objc_getClass("ATVSettingsFacade");
+ XBMCSettingsFacade *single = (XBMCSettingsFacade *)[ATVSettingsFacadeCls singleton];
+
+ int tmpTimeout = [single sleepTimeout];
+ NSNumber *timeout = [NSNumber numberWithInt:tmpTimeout];
+ [self setSystemSleepTimeout:timeout];
+ [single setSleepTimeout: -1];
+ [single flushDiskChanges];
}
-- (void) enableSystemSleep
+static void XBMCController$enableSystemSleep(XBMCController* self, SEL _cmd)
{
- [[ATVSettingsFacade singleton] setSleepTimeout: m_systemsleepTimeout];
- [[ATVSettingsFacade singleton] flushDiskChanges];
+ Class ATVSettingsFacadeCls = objc_getClass("ATVSettingsFacade");
+ int timeoutInt = [[self systemSleepTimeout] intValue];
+ [[ATVSettingsFacadeCls singleton] setSleepTimeout:timeoutInt];
+ [[ATVSettingsFacadeCls singleton] flushDiskChanges];
}
-- (void) disableScreenSaver
+static void XBMCController$disableScreenSaver(XBMCController* self, SEL _cmd)
{
//NSLog(@"%s", __PRETTY_FUNCTION__);
//store screen saver state and disable it
- m_screensaverTimeout = [[ATVSettingsFacade singleton] screenSaverTimeout];
- [[ATVSettingsFacade singleton] setScreenSaverTimeout: -1];
- [[ATVSettingsFacade singleton] flushDiskChanges];
+ Class ATVSettingsFacadeCls = objc_getClass("ATVSettingsFacade");
+ XBMCSettingsFacade *single = (XBMCSettingsFacade *)[ATVSettingsFacadeCls singleton];
+
+ int tmpTimeout = [single screenSaverTimeout];
+ NSNumber *timeout = [NSNumber numberWithInt:tmpTimeout];
+ [self setSystemScreenSaverTimeout:timeout];
+ [single setScreenSaverTimeout: -1];
+ [single flushDiskChanges];
// breaks in 4.2.1 [[BRBackgroundTaskManager singleton] holdOffBackgroundTasks];
}
-- (void) enableScreenSaver
+static void XBMCController$enableScreenSaver(XBMCController* self, SEL _cmd)
{
//NSLog(@"%s", __PRETTY_FUNCTION__);
//reset screen saver to user settings
+ Class ATVSettingsFacadeCls = objc_getClass("ATVSettingsFacade");
- [[ATVSettingsFacade singleton] setScreenSaverTimeout: m_screensaverTimeout];
- [[ATVSettingsFacade singleton] flushDiskChanges];
+ int timeoutInt = [[self systemScreenSaverTimeout] intValue];
+ [[ATVSettingsFacadeCls singleton] setScreenSaverTimeout:timeoutInt];
+ [[ATVSettingsFacadeCls singleton] flushDiskChanges];
// breaks in 4.2.1 [[BRBackgroundTaskManager singleton] okToDoBackgroundProcessing];
}
+/*
- (XBMC_Event) translateCocoaToXBMCEvent: (unichar) c
{
XBMC_Event newEvent;
memset(&newEvent, 0, sizeof(newEvent));
-/*
- switch (c)
- {
- // Alt
- case NSMenuFunctionKey:
- return "Alt";
-
- // "Apps"
- // "BrowserBack"
- // "BrowserForward"
- // "BrowserHome"
- // "BrowserRefresh"
- // "BrowserSearch"
- // "BrowserStop"
- // "CapsLock"
-
- // "Clear"
- case NSClearLineFunctionKey:
- return "Clear";
-
- // "CodeInput"
- // "Compose"
- // "Control"
- // "Crsel"
- // "Convert"
- // "Copy"
- // "Cut"
-
- // "Down"
- case NSDownArrowFunctionKey:
- return "Down";
- // "End"
- case NSEndFunctionKey:
- return "End";
- // "Enter"
- case 0x3: case 0xA: case 0xD: // Macintosh calls the one on the main keyboard Return, but Windows calls it Enter, so we'll do the same for the DOM
- return "Enter";
-
- // "EraseEof"
-
- // "Execute"
- case NSExecuteFunctionKey:
- return "Execute";
-
- // "Exsel"
-
- // "F1"
- case NSF1FunctionKey:
- return "F1";
- // "F2"
- case NSF2FunctionKey:
- return "F2";
- // "F3"
- case NSF3FunctionKey:
- return "F3";
- // "F4"
- case NSF4FunctionKey:
- return "F4";
- // "F5"
- case NSF5FunctionKey:
- return "F5";
- // "F6"
- case NSF6FunctionKey:
- return "F6";
- // "F7"
- case NSF7FunctionKey:
- return "F7";
- // "F8"
- case NSF8FunctionKey:
- return "F8";
- // "F9"
- case NSF9FunctionKey:
- return "F9";
- // "F10"
- case NSF10FunctionKey:
- return "F10";
- // "F11"
- case NSF11FunctionKey:
- return "F11";
- // "F12"
- case NSF12FunctionKey:
- return "F12";
- // "F13"
- case NSF13FunctionKey:
- return "F13";
- // "F14"
- case NSF14FunctionKey:
- return "F14";
- // "F15"
- case NSF15FunctionKey:
- return "F15";
- // "F16"
- case NSF16FunctionKey:
- return "F16";
- // "F17"
- case NSF17FunctionKey:
- return "F17";
- // "F18"
- case NSF18FunctionKey:
- return "F18";
- // "F19"
- case NSF19FunctionKey:
- return "F19";
- // "F20"
- case NSF20FunctionKey:
- return "F20";
- // "F21"
- case NSF21FunctionKey:
- return "F21";
- // "F22"
- case NSF22FunctionKey:
- return "F22";
- // "F23"
- case NSF23FunctionKey:
- return "F23";
- // "F24"
- case NSF24FunctionKey:
- return "F24";
-
- // "FinalMode"
-
- // "Find"
- case NSFindFunctionKey:
- return "Find";
-
- // "FullWidth"
- // "HalfWidth"
- // "HangulMode"
- // "HanjaMode"
-
- // "Help"
- case NSHelpFunctionKey:
- return "Help";
-
- // "Hiragana"
-
- // "Home"
- case NSHomeFunctionKey:
- return "Home";
- // "Insert"
- case NSInsertFunctionKey:
- return "Insert";
-
- // "JapaneseHiragana"
- // "JapaneseKatakana"
- // "JapaneseRomaji"
- // "JunjaMode"
- // "KanaMode"
- // "KanjiMode"
- // "Katakana"
- // "LaunchApplication1"
- // "LaunchApplication2"
- // "LaunchMail"
-
- // "Left"
- case NSLeftArrowFunctionKey:
- return "Left";
-
- // "Meta"
- // "MediaNextTrack"
- // "MediaPlayPause"
- // "MediaPreviousTrack"
- // "MediaStop"
-
- // "ModeChange"
- case NSModeSwitchFunctionKey:
- return "ModeChange";
-
- // "Nonconvert"
- // "NumLock"
-
- // "PageDown"
- case NSPageDownFunctionKey:
- return "PageDown";
- // "PageUp"
- case NSPageUpFunctionKey:
- return "PageUp";
-
- // "Paste"
-
- // "Pause"
- case NSPauseFunctionKey:
- return "Pause";
-
- // "Play"
- // "PreviousCandidate"
-
- // "PrintScreen"
- case NSPrintScreenFunctionKey:
- return "PrintScreen";
-
- // "Process"
- // "Props"
-
- // "Right"
- case NSRightArrowFunctionKey:
- return "Right";
-
- // "RomanCharacters"
-
- // "Scroll"
- case NSScrollLockFunctionKey:
- return "Scroll";
- // "Select"
- case NSSelectFunctionKey:
- return "Select";
-
- // "SelectMedia"
- // "Shift"
-
- // "Stop"
- case NSStopFunctionKey:
- return "Stop";
- // "Up"
- case NSUpArrowFunctionKey:
- return "Up";
- // "Undo"
- case NSUndoFunctionKey:
- return "Undo";
-
- // "VolumeDown"
- // "VolumeMute"
- // "VolumeUp"
- // "Win"
- // "Zoom"
-
- // More function keys, not in the key identifier specification.
- case NSF25FunctionKey:
- return "F25";
- case NSF26FunctionKey:
- return "F26";
- case NSF27FunctionKey:
- return "F27";
- case NSF28FunctionKey:
- return "F28";
- case NSF29FunctionKey:
- return "F29";
- case NSF30FunctionKey:
- return "F30";
- case NSF31FunctionKey:
- return "F31";
- case NSF32FunctionKey:
- return "F32";
- case NSF33FunctionKey:
- return "F33";
- case NSF34FunctionKey:
- return "F34";
- case NSF35FunctionKey:
- return "F35";
-
- // Turn 0x7F into 0x08, because backspace needs to always be 0x08.
- case 0x7F:
- XBMCK_BACKSPACE
- // Standard says that DEL becomes U+007F.
- case NSDeleteFunctionKey:
- XBMCK_DELETE;
-
- // Always use 0x09 for tab instead of AppKit's backtab character.
- case NSBackTabCharacter:
- return "U+0009";
-
- case NSBeginFunctionKey:
- case NSBreakFunctionKey:
- case NSClearDisplayFunctionKey:
- case NSDeleteCharFunctionKey:
- case NSDeleteLineFunctionKey:
- case NSInsertCharFunctionKey:
- case NSInsertLineFunctionKey:
- case NSNextFunctionKey:
- case NSPrevFunctionKey:
- case NSPrintFunctionKey:
- case NSRedoFunctionKey:
- case NSResetFunctionKey:
- case NSSysReqFunctionKey:
- case NSSystemFunctionKey:
- case NSUserFunctionKey:
+
+ switch (c)
+ {
+ // Alt
+ case NSMenuFunctionKey:
+ return "Alt";
+
+ // "Apps"
+ // "BrowserBack"
+ // "BrowserForward"
+ // "BrowserHome"
+ // "BrowserRefresh"
+ // "BrowserSearch"
+ // "BrowserStop"
+ // "CapsLock"
+
+ // "Clear"
+ case NSClearLineFunctionKey:
+ return "Clear";
+
+ // "CodeInput"
+ // "Compose"
+ // "Control"
+ // "Crsel"
+ // "Convert"
+ // "Copy"
+ // "Cut"
+
+ // "Down"
+ case NSDownArrowFunctionKey:
+ return "Down";
+ // "End"
+ case NSEndFunctionKey:
+ return "End";
+ // "Enter"
+ case 0x3: case 0xA: case 0xD: // Macintosh calls the one on the main keyboard Return, but Windows calls it Enter, so we'll do the same for the DOM
+ return "Enter";
+
+ // "EraseEof"
+
+ // "Execute"
+ case NSExecuteFunctionKey:
+ return "Execute";
+
+ // "Exsel"
+
+ // "F1"
+ case NSF1FunctionKey:
+ return "F1";
+ // "F2"
+ case NSF2FunctionKey:
+ return "F2";
+ // "F3"
+ case NSF3FunctionKey:
+ return "F3";
+ // "F4"
+ case NSF4FunctionKey:
+ return "F4";
+ // "F5"
+ case NSF5FunctionKey:
+ return "F5";
+ // "F6"
+ case NSF6FunctionKey:
+ return "F6";
+ // "F7"
+ case NSF7FunctionKey:
+ return "F7";
+ // "F8"
+ case NSF8FunctionKey:
+ return "F8";
+ // "F9"
+ case NSF9FunctionKey:
+ return "F9";
+ // "F10"
+ case NSF10FunctionKey:
+ return "F10";
+ // "F11"
+ case NSF11FunctionKey:
+ return "F11";
+ // "F12"
+ case NSF12FunctionKey:
+ return "F12";
+ // "F13"
+ case NSF13FunctionKey:
+ return "F13";
+ // "F14"
+ case NSF14FunctionKey:
+ return "F14";
+ // "F15"
+ case NSF15FunctionKey:
+ return "F15";
+ // "F16"
+ case NSF16FunctionKey:
+ return "F16";
+ // "F17"
+ case NSF17FunctionKey:
+ return "F17";
+ // "F18"
+ case NSF18FunctionKey:
+ return "F18";
+ // "F19"
+ case NSF19FunctionKey:
+ return "F19";
+ // "F20"
+ case NSF20FunctionKey:
+ return "F20";
+ // "F21"
+ case NSF21FunctionKey:
+ return "F21";
+ // "F22"
+ case NSF22FunctionKey:
+ return "F22";
+ // "F23"
+ case NSF23FunctionKey:
+ return "F23";
+ // "F24"
+ case NSF24FunctionKey:
+ return "F24";
+
+ // "FinalMode"
+
+ // "Find"
+ case NSFindFunctionKey:
+ return "Find";
+
+ // "FullWidth"
+ // "HalfWidth"
+ // "HangulMode"
+ // "HanjaMode"
+
+ // "Help"
+ case NSHelpFunctionKey:
+ return "Help";
+
+ // "Hiragana"
+
+ // "Home"
+ case NSHomeFunctionKey:
+ return "Home";
+ // "Insert"
+ case NSInsertFunctionKey:
+ return "Insert";
+
+ // "JapaneseHiragana"
+ // "JapaneseKatakana"
+ // "JapaneseRomaji"
+ // "JunjaMode"
+ // "KanaMode"
+ // "KanjiMode"
+ // "Katakana"
+ // "LaunchApplication1"
+ // "LaunchApplication2"
+ // "LaunchMail"
+
+ // "Left"
+ case NSLeftArrowFunctionKey:
+ return "Left";
+
+ // "Meta"
+ // "MediaNextTrack"
+ // "MediaPlayPause"
+ // "MediaPreviousTrack"
+ // "MediaStop"
+
+ // "ModeChange"
+ case NSModeSwitchFunctionKey:
+ return "ModeChange";
+
+ // "Nonconvert"
+ // "NumLock"
+
+ // "PageDown"
+ case NSPageDownFunctionKey:
+ return "PageDown";
+ // "PageUp"
+ case NSPageUpFunctionKey:
+ return "PageUp";
+
+ // "Paste"
+
+ // "Pause"
+ case NSPauseFunctionKey:
+ return "Pause";
+
+ // "Play"
+ // "PreviousCandidate"
+
+ // "PrintScreen"
+ case NSPrintScreenFunctionKey:
+ return "PrintScreen";
+
+ // "Process"
+ // "Props"
+
+ // "Right"
+ case NSRightArrowFunctionKey:
+ return "Right";
+
+ // "RomanCharacters"
+
+ // "Scroll"
+ case NSScrollLockFunctionKey:
+ return "Scroll";
+ // "Select"
+ case NSSelectFunctionKey:
+ return "Select";
+
+ // "SelectMedia"
+ // "Shift"
+
+ // "Stop"
+ case NSStopFunctionKey:
+ return "Stop";
+ // "Up"
+ case NSUpArrowFunctionKey:
+ return "Up";
+ // "Undo"
+ case NSUndoFunctionKey:
+ return "Undo";
+
+ // "VolumeDown"
+ // "VolumeMute"
+ // "VolumeUp"
+ // "Win"
+ // "Zoom"
+
+ // More function keys, not in the key identifier specification.
+ case NSF25FunctionKey:
+ return "F25";
+ case NSF26FunctionKey:
+ return "F26";
+ case NSF27FunctionKey:
+ return "F27";
+ case NSF28FunctionKey:
+ return "F28";
+ case NSF29FunctionKey:
+ return "F29";
+ case NSF30FunctionKey:
+ return "F30";
+ case NSF31FunctionKey:
+ return "F31";
+ case NSF32FunctionKey:
+ return "F32";
+ case NSF33FunctionKey:
+ return "F33";
+ case NSF34FunctionKey:
+ return "F34";
+ case NSF35FunctionKey:
+ return "F35";
+
+ // Turn 0x7F into 0x08, because backspace needs to always be 0x08.
+ case 0x7F:
+ XBMCK_BACKSPACE
+ // Standard says that DEL becomes U+007F.
+ case NSDeleteFunctionKey:
+ XBMCK_DELETE;
+
+ // Always use 0x09 for tab instead of AppKit's backtab character.
+ case NSBackTabCharacter:
+ return "U+0009";
+
+ case NSBeginFunctionKey:
+ case NSBreakFunctionKey:
+ case NSClearDisplayFunctionKey:
+ case NSDeleteCharFunctionKey:
+ case NSDeleteLineFunctionKey:
+ case NSInsertCharFunctionKey:
+ case NSInsertLineFunctionKey:
+ case NSNextFunctionKey:
+ case NSPrevFunctionKey:
+ case NSPrintFunctionKey:
+ case NSRedoFunctionKey:
+ case NSResetFunctionKey:
+ case NSSysReqFunctionKey:
+ case NSSystemFunctionKey:
+ case NSUserFunctionKey:
// FIXME: We should use something other than the vendor-area Unicode values for the above keys.
// For now, just fall through to the default.
default:
return String::format("U+%04X", toASCIIUpper(c));
}
-*/
return newEvent;
-}
+}*/
//--------------------------------------------------------------
-- (void)pauseAnimation
+static void XBMCController$pauseAnimation(XBMCController* self, SEL _cmd)
{
XBMC_Event newEvent;
memset(&newEvent, 0, sizeof(XBMC_Event));
-
+
newEvent.appcommand.type = XBMC_APPCOMMAND;
newEvent.appcommand.action = ACTION_PLAYER_PLAYPAUSE;
CWinEventsIOS::MessagePush(&newEvent);
- /* Give player time to pause */
- Sleep(2000);
- //NSLog(@"%s", __PRETTY_FUNCTION__);
-
- [m_glView pauseAnimation];
-
+ Sleep(2000);
+ [[self glView] pauseAnimation];
}
//--------------------------------------------------------------
-- (void)resumeAnimation
+static void XBMCController$resumeAnimation(XBMCController* self, SEL _cmd)
{
+ NSLog(@"%s", __PRETTY_FUNCTION__);
+
XBMC_Event newEvent;
memset(&newEvent, 0, sizeof(XBMC_Event));
-
+
newEvent.appcommand.type = XBMC_APPCOMMAND;
newEvent.appcommand.action = ACTION_PLAYER_PLAY;
- CWinEventsIOS::MessagePush(&newEvent);
-
- [m_glView resumeAnimation];
+ CWinEventsIOS::MessagePush(&newEvent);
+
+ [[self glView] resumeAnimation];
}
//--------------------------------------------------------------
-- (void)startAnimation
+static void XBMCController$startAnimation(XBMCController* self, SEL _cmd)
{
- [m_glView startAnimation];
+ NSLog(@"%s", __PRETTY_FUNCTION__);
+
+ [[self glView] startAnimation];
}
//--------------------------------------------------------------
-- (void)stopAnimation
+static void XBMCController$stopAnimation(XBMCController* self, SEL _cmd)
{
- [m_glView stopAnimation];
+ NSLog(@"%s", __PRETTY_FUNCTION__);
+
+ [[self glView] stopAnimation];
}
//--------------------------------------------------------------
-- (bool) changeScreen: (unsigned int)screenIdx withMode:(UIScreenMode *)mode
+static bool XBMCController$changeScreen(XBMCController* self, SEL _cmd, unsigned int screenIdx, UIScreenMode * mode)
{
return [[IOSScreenManager sharedInstance] changeScreen: screenIdx withMode: mode];
}
//--------------------------------------------------------------
-- (void) activateScreen: (UIScreen *)screen
+static void XBMCController$activateScreen(XBMCController* self, SEL _cmd, UIScreen * screen)
{
}
-@end
+// SECTIONCOMMENT
+// c'tor - this sets up our class at runtime by
+// 1. subclassing from the base classes
+// 2. adding new methods to our class
+// 3. exchanging (hooking) base class methods with ours
+// 4. register the classes to the objc runtime system
+static __attribute__((constructor)) void initControllerRuntimeClasses()
+{
+ char _typeEncoding[1024];
+ unsigned int i = 0;
+
+ // subclass BRController into XBMCController
+ Class XBMCControllerCls = objc_allocateClassPair(objc_getClass("BRController"), "XBMCController", 0);
+ // add our custom methods which are not part of the baseclass
+ // XBMCController::keyTimer
+ class_addMethod(XBMCControllerCls, @selector(keyTimer), (IMP)&XBMCController$keyTimer, "@@:");
+ // XBMCController::setKeyTimer
+ class_addMethod(XBMCControllerCls, @selector(setKeyTimer:), (IMP)&XBMCController$setKeyTimer, "v@:@");
+ // XBMCController::glView
+ class_addMethod(XBMCControllerCls, @selector(glView), (IMP)&XBMCController$glView, "@@:");
+ // XBMCController::setGlView
+ class_addMethod(XBMCControllerCls, @selector(setGlView:), (IMP)&XBMCController$setGlView, "v@:@");
+ // XBMCController::systemScreenSaverTimeout
+ class_addMethod(XBMCControllerCls, @selector(systemScreenSaverTimeout), (IMP)&XBMCController$systemScreenSaverTimeout, "@@:");
+ // XBMCController::setSystemScreenSaverTimeout
+ class_addMethod(XBMCControllerCls, @selector(setSystemScreenSaverTimeout:), (IMP)&XBMCController$setSystemScreenSaverTimeout, "v@:@");
+ // XBMCController::systemSleepTimeout
+ class_addMethod(XBMCControllerCls, @selector(systemSleepTimeout), (IMP)&XBMCController$systemSleepTimeout, "@@:");
+ // XBMCController::setSystemSleepTimeout
+ class_addMethod(XBMCControllerCls, @selector(setSystemSleepTimeout:), (IMP)&XBMCController$setSystemSleepTimeout, "v@:@");
+ // XBMCController::applicationDidExit
+ class_addMethod(XBMCControllerCls, @selector(applicationDidExit), (IMP)&XBMCController$applicationDidExit, "v@:");
+ // XBMCController::initDisplayLink
+ class_addMethod(XBMCControllerCls, @selector(initDisplayLink), (IMP)&XBMCController$initDisplayLink, "v@:");
+ // XBMCController::deinitDisplayLink
+ class_addMethod(XBMCControllerCls, @selector(deinitDisplayLink), (IMP)&XBMCController$deinitDisplayLink, "v@:");
+ // XBMCController::getDisplayLinkFPS
+ class_addMethod(XBMCControllerCls, @selector(getDisplayLinkFPS), (IMP)&XBMCController$getDisplayLinkFPS, "d@:");
+ // XBMCController::setFramebuffer
+ class_addMethod(XBMCControllerCls, @selector(setFramebuffer), (IMP)&XBMCController$setFramebuffer, "v@:");
+ // XBMCController::presentFramebuffer
+ class_addMethod(XBMCControllerCls, @selector(presentFramebuffer), (IMP)&XBMCController$presentFramebuffer, "B@:");
+ // XBMCController::setUserEvent
+ class_addMethod(XBMCControllerCls, @selector(setUserEvent:withHoldTime:), (IMP)&XBMCController$setUserEvent, "v@:iI");
+ // XBMCController::startKeyPressTimer
+ class_addMethod(XBMCControllerCls, @selector(startKeyPressTimer:), (IMP)&XBMCController$startKeyPressTimer, "v@:i");
+ // XBMCController::stopKeyPressTimer
+ class_addMethod(XBMCControllerCls, @selector(stopKeyPressTimer), (IMP)&XBMCController$stopKeyPressTimer, "v@:");
+ // XBMCController::disableSystemSleep
+ class_addMethod(XBMCControllerCls, @selector(disableSystemSleep), (IMP)&XBMCController$disableSystemSleep, "v@:");
+ // XBMCController__enableSystemSleep
+ class_addMethod(XBMCControllerCls, @selector(enableSystemSleep), (IMP)&XBMCController$enableSystemSleep, "v@:");
+ // XBMCController::disableScreenSaver
+ class_addMethod(XBMCControllerCls, @selector(disableScreenSaver), (IMP)&XBMCController$disableScreenSaver, "v@:");
+ // XBMCController::enableScreenSaver
+ class_addMethod(XBMCControllerCls, @selector(enableScreenSaver), (IMP)&XBMCController$enableScreenSaver, "v@:");
+ // XBMCController::pauseAnimation
+ class_addMethod(XBMCControllerCls, @selector(pauseAnimation), (IMP)&XBMCController$pauseAnimation, "v@:");
+ // XBMCController::resumeAnimation
+ class_addMethod(XBMCControllerCls, @selector(resumeAnimation), (IMP)&XBMCController$resumeAnimation, "v@:");
+ // XBMCController::startAnimation
+ class_addMethod(XBMCControllerCls, @selector(startAnimation), (IMP)&XBMCController$startAnimation, "v@:");
+ // XBMCController::stopAnimation
+ class_addMethod(XBMCControllerCls, @selector(stopAnimation), (IMP)&XBMCController$stopAnimation, "v@:");
+
+ i = 0;
+ memcpy(_typeEncoding + i, @encode(CGSize), strlen(@encode(CGSize)));
+ i += strlen(@encode(CGSize));
+ _typeEncoding[i] = '@';
+ i += 1;
+ _typeEncoding[i] = ':';
+ i += 1;
+ _typeEncoding[i] = '\0';
+ // XBMCController::getScreenSize
+ class_addMethod(XBMCControllerCls, @selector(getScreenSize), (IMP)&XBMCController$getScreenSize, _typeEncoding);
+
+ i = 0;
+ _typeEncoding[i] = 'v';
+ i += 1;
+ _typeEncoding[i] = '@';
+ i += 1;
+ _typeEncoding[i] = ':';
+ i += 1;
+ memcpy(_typeEncoding + i, @encode(XBMCKey), strlen(@encode(XBMCKey)));
+ i += strlen(@encode(XBMCKey));