1/* 2 * Copyright (C) 2012-2018 Team Kodi 3 * This file is part of Kodi - https://kodi.tv 4 * 5 * SPDX-License-Identifier: GPL-2.0-or-later 6 * See LICENSES/README.md for more information. 7 */ 8 9#import "IOSExternalTouchController.h" 10 11#include "Util.h" 12#import "XBMCController.h" 13#include "filesystem/SpecialProtocol.h" 14#include "guilib/LocalizeStrings.h" 15#include "input/mouse/MouseStat.h" 16 17//dim the touchscreen after 15 secs without touch event 18const CGFloat touchScreenDimTimeoutSecs = 15.0; 19const CGFloat timeFadeSecs = 2.0; 20 21@implementation IOSExternalTouchController 22//-------------------------------------------------------------- 23- (id)init 24{ 25 CGRect frame = [[UIScreen mainScreen] bounds]; 26 27 self = [super init]; 28 if (self) 29 { 30 UIImage *xbmcLogo; 31 UIImageView *xbmcLogoView; 32 UILabel *descriptionLabel; 33 34 _internalWindow = [[UIWindow alloc] initWithFrame:frame]; 35 _touchView = [[UIView alloc] initWithFrame:frame]; 36 /* Turn on autoresizing for the whole hierarchy*/ 37 [_touchView setAutoresizesSubviews:YES]; 38 [_touchView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; 39 [_touchView setAlpha:0.0];//start with alpha 0 and fade in with animation below 40 [_touchView setMultipleTouchEnabled:YES]; 41 [_touchView setContentMode:UIViewContentModeCenter]; 42 43 //load the splash image 44 std::string strUserSplash = CUtil::GetSplashPath(); 45 xbmcLogo = [UIImage imageWithContentsOfFile:[NSString stringWithUTF8String:strUserSplash.c_str()]]; 46 47 //make a view with the image 48 xbmcLogoView = [[UIImageView alloc] initWithImage:xbmcLogo]; 49 //center the image and add it to the view 50 [xbmcLogoView setFrame:frame]; 51 [xbmcLogoView setContentMode:UIViewContentModeScaleAspectFill]; 52 //autoresize the image frame 53 [xbmcLogoView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; 54 [xbmcLogoView setAutoresizesSubviews:YES]; 55 [_touchView addSubview:xbmcLogoView]; 56 //send the image to the background 57 [_touchView sendSubviewToBack:xbmcLogoView]; 58 59 CGRect labelRect = frame; 60 labelRect.size.height/=2; 61 //uilabel with the description 62 descriptionLabel = [[UILabel alloc] initWithFrame:labelRect]; 63 //gray textcolor on transparent background 64 [descriptionLabel setTextColor:[UIColor grayColor]]; 65 [descriptionLabel setBackgroundColor:[UIColor clearColor]]; 66 //text is aligned left in its frame 67 [descriptionLabel setTextAlignment:NSTextAlignmentCenter]; 68 [descriptionLabel setContentMode:UIViewContentModeCenter]; 69 //setup multiline behaviour 70 [descriptionLabel setLineBreakMode:(NSLineBreakMode)NSLineBreakByTruncatingTail]; 71 72 [descriptionLabel setNumberOfLines:5]; 73 std::string descText = g_localizeStrings.Get(34404) + "\n"; 74 descText += g_localizeStrings.Get(34405) + "\n"; 75 descText += g_localizeStrings.Get(34406) + "\n"; 76 descText += g_localizeStrings.Get(34407) + "\n"; 77 descText += g_localizeStrings.Get(34408) + "\n"; 78 79 NSString *stringFromUTFString = [[NSString alloc] initWithUTF8String:descText.c_str()]; 80 81 [descriptionLabel setText:stringFromUTFString]; 82 83 //resize it to full view 84 [descriptionLabel setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; 85 [descriptionLabel setAutoresizesSubviews:YES]; 86 [_touchView addSubview:descriptionLabel]; 87 88 [[self view] addSubview: _touchView]; 89 90 [self createGestureRecognizers]; 91 92 [_internalWindow addSubview:[self view]]; 93 [_internalWindow setBackgroundColor:[UIColor blackColor]]; 94 [_internalWindow setScreen:[UIScreen mainScreen]]; 95 [_internalWindow makeKeyAndVisible]; 96 [_internalWindow setRootViewController:self]; 97 98 [self startSleepTimer];//will fade from black too 99 } 100 return self; 101} 102//-------------------------------------------------------------- 103- (UIInterfaceOrientationMask)supportedInterfaceOrientations 104{ 105 return UIInterfaceOrientationMaskLandscape; 106} 107//-------------------------------------------------------------- 108- (void)startSleepTimer 109{ 110 NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:touchScreenDimTimeoutSecs]; 111 112 //schedule sleep timer to fire once in touchScreenDimTimeoutSecs if not reset 113 _sleepTimer = [[NSTimer alloc] initWithFireDate:fireDate 114 interval:1 115 target:self 116 selector:@selector(sleepTimerCallback:) 117 userInfo:nil 118 repeats:NO]; 119 //schedule the timer to the runloop 120 NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 121 [self fadeFromBlack]; 122 [runLoop addTimer:_sleepTimer forMode:NSDefaultRunLoopMode]; 123} 124//-------------------------------------------------------------- 125- (void)stopSleepTimer 126{ 127 if(_sleepTimer != nil) 128 { 129 [_sleepTimer invalidate]; 130 _sleepTimer = nil; 131 } 132} 133//-------------------------------------------------------------- 134- (void)sleepTimerCallback:(NSTimer*)theTimer 135{ 136 [self fadeToBlack]; 137 [self stopSleepTimer]; 138} 139//-------------------------------------------------------------- 140- (bool)wakeUpFromSleep//returns false if we where dimmed, true if not 141{ 142 if(_sleepTimer == nil) 143 { 144 [self startSleepTimer]; 145 return false; 146 } 147 else 148 { 149 NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:touchScreenDimTimeoutSecs]; 150 [_sleepTimer setFireDate:fireDate]; 151 return true; 152 } 153} 154//-------------------------------------------------------------- 155- (void)fadeToBlack 156{ 157 [UIView animateWithDuration:timeFadeSecs delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 158 [_touchView setAlpha:0.01];//fade to black (don't fade to 0.0 else we don't get gesture callbacks) 159 } 160 completion:^(BOOL finished){}]; 161} 162//-------------------------------------------------------------- 163- (void)fadeFromBlack 164{ 165 [UIView animateWithDuration:timeFadeSecs delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 166 [_touchView setAlpha:1.0];//fade in to full alpha 167 } 168 completion:^(BOOL finished){}]; 169} 170//-------------------------------------------------------------- 171- (void)createGestureRecognizers 172{ 173 //2 finger single tab - right mouse 174 //single finger double tab delays single finger single tab - so we 175 //go for 2 fingers here - so single finger single tap is instant 176 UITapGestureRecognizer *doubleFingerSingleTap = [[UITapGestureRecognizer alloc] 177 initWithTarget:self action:@selector(handleDoubleFingerSingleTap:)]; 178 [doubleFingerSingleTap setNumberOfTapsRequired:1]; 179 [doubleFingerSingleTap setNumberOfTouchesRequired:2]; 180 [[self view] addGestureRecognizer:doubleFingerSingleTap]; 181 182 //1 finger single long tab - right mouse - alternative 183 UITapGestureRecognizer *singleFingerSingleLongTap = (UITapGestureRecognizer*)[[UILongPressGestureRecognizer alloc] 184 initWithTarget:self action:@selector(handleSingleFingerSingleLongTap:)]; 185 singleFingerSingleLongTap.delaysTouchesBegan = YES; 186 singleFingerSingleLongTap.delaysTouchesEnded = YES; 187 singleFingerSingleLongTap.numberOfTouchesRequired = 1; 188 [self.view addGestureRecognizer:singleFingerSingleLongTap]; 189 190 //1 finger single tab - left mouse 191 UITapGestureRecognizer *singleFingerSingleTap = [[UITapGestureRecognizer alloc] 192 initWithTarget:self action:@selector(handleSingleFingerSingleTap:)]; 193 [singleFingerSingleTap setDelaysTouchesBegan:NO]; 194 [[self view] addGestureRecognizer:singleFingerSingleTap]; 195 196 //double finger swipe left for backspace ... i like this fast backspace feature ;) 197 UISwipeGestureRecognizer *swipeDoubleLeft = [[UISwipeGestureRecognizer alloc] 198 initWithTarget:self action:@selector(handleDoubleSwipeLeft:)]; 199 [swipeDoubleLeft setNumberOfTouchesRequired:2]; 200 [swipeDoubleLeft setDirection:UISwipeGestureRecognizerDirectionLeft]; 201 [[self view] addGestureRecognizer:swipeDoubleLeft]; 202 203 //single finger swipe left for left 204 UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] 205 initWithTarget:self action:@selector(handleSwipeLeft:)]; 206 [swipeLeft setNumberOfTouchesRequired:1]; 207 [swipeLeft setDirection:UISwipeGestureRecognizerDirectionLeft]; 208 [[self view] addGestureRecognizer:swipeLeft]; 209 210 //single finger swipe right for right 211 UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] 212 initWithTarget:self action:@selector(handleSwipeRight:)]; 213 [swipeRight setNumberOfTouchesRequired:1]; 214 [swipeRight setDirection:UISwipeGestureRecognizerDirectionRight]; 215 [[self view] addGestureRecognizer:swipeRight]; 216 217 //single finger swipe up for up 218 UISwipeGestureRecognizer *swipeUp = [[UISwipeGestureRecognizer alloc] 219 initWithTarget:self action:@selector(handleSwipeUp:)]; 220 [swipeUp setNumberOfTouchesRequired:1]; 221 [swipeUp setDirection:UISwipeGestureRecognizerDirectionUp]; 222 [[self view] addGestureRecognizer:swipeUp]; 223 224 //single finger swipe down for down 225 UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] 226 initWithTarget:self action:@selector(handleSwipeDown:)]; 227 [swipeDown setNumberOfTouchesRequired:1]; 228 [swipeDown setDirection:UISwipeGestureRecognizerDirectionDown]; 229 [[self view] addGestureRecognizer:swipeDown]; 230 231} 232//-------------------------------------------------------------- 233- (IBAction)handleDoubleSwipeLeft:(UISwipeGestureRecognizer *)sender 234{ 235 if([self wakeUpFromSleep]) 236 { 237 [g_xbmcController sendKey:XBMCK_BACKSPACE]; 238 } 239} 240//-------------------------------------------------------------- 241- (IBAction)handleSwipeLeft:(UISwipeGestureRecognizer *)sender 242{ 243 if([self wakeUpFromSleep]) 244 { 245 [g_xbmcController sendKey:XBMCK_LEFT]; 246 } 247} 248//-------------------------------------------------------------- 249- (IBAction)handleSwipeRight:(UISwipeGestureRecognizer *)sender 250{ 251 if([self wakeUpFromSleep]) 252 { 253 [g_xbmcController sendKey:XBMCK_RIGHT]; 254 } 255} 256//-------------------------------------------------------------- 257- (IBAction)handleSwipeUp:(UISwipeGestureRecognizer *)sender 258{ 259 if([self wakeUpFromSleep]) 260 { 261 [g_xbmcController sendKey:XBMCK_UP]; 262 } 263} 264//-------------------------------------------------------------- 265- (IBAction)handleSwipeDown:(UISwipeGestureRecognizer *)sender 266{ 267 if([self wakeUpFromSleep]) 268 { 269 [g_xbmcController sendKey:XBMCK_DOWN]; 270 } 271} 272//-------------------------------------------------------------- 273- (IBAction)handleDoubleFingerSingleTap:(UIGestureRecognizer *)sender 274{ 275 if([self wakeUpFromSleep]) 276 { 277 [g_xbmcController sendKey:XBMCK_c]; 278 } 279} 280//-------------------------------------------------------------- 281- (IBAction)handleSingleFingerSingleLongTap:(UIGestureRecognizer *)sender 282{ 283 if([self wakeUpFromSleep]) 284 { 285 if (sender.state == UIGestureRecognizerStateEnded) 286 { 287 [self handleDoubleFingerSingleTap:sender]; 288 } 289 } 290} 291//-------------------------------------------------------------- 292- (IBAction)handleSingleFingerSingleTap:(UIGestureRecognizer *)sender 293{ 294 if([self wakeUpFromSleep]) 295 { 296 [g_xbmcController sendKey:XBMCK_RETURN]; 297 } 298} 299//-------------------------------------------------------------- 300- (void)viewWillAppear:(BOOL)animated 301{ 302 [super viewWillAppear:animated]; 303} 304//-------------------------------------------------------------- 305- (void)dealloc 306{ 307 [self stopSleepTimer]; 308} 309//-------------------------------------------------------------- 310@end 311