Fix keymap.
[vuplus_xbmc] / xbmc / osx / IOSExternalTouchController.mm
1 /*
2  *      Copyright (C) 2012-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 //hack around problem with xbmc's typedef int BOOL
22 // and obj-c's typedef unsigned char BOOL
23 #define BOOL XBMC_BOOL 
24 #include "MouseStat.h"
25 #include "WindowingFactory.h"
26 #include "filesystem/SpecialProtocol.h"
27 #include "guilib/LocalizeStrings.h"
28 #undef BOOL
29
30 #import "IOSExternalTouchController.h"
31 #import "XBMCController.h"
32
33 //dim the touchscreen after 15 secs without touch event
34 const CGFloat touchScreenDimTimeoutSecs       = 15.0;
35 const CGFloat timeFadeSecs                    = 2.0;
36
37 @implementation IOSExternalTouchController
38 //--------------------------------------------------------------
39 - (id)init
40 {
41   CGRect frame = [[UIScreen mainScreen] bounds];
42   
43   self = [super init];
44   if (self) 
45   {
46     UIImage       *xbmcLogo;
47     UIImageView   *xbmcLogoView;
48     UILabel       *descriptionLabel;
49   
50     _internalWindow = [[UIWindow alloc] initWithFrame:frame];
51     _touchView = [[UIView alloc] initWithFrame:frame];
52     /* Turn on autoresizing for the whole hirarchy*/
53     [_touchView setAutoresizesSubviews:YES];
54     [_touchView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
55     [_touchView setAlpha:0.0];//start with alpha 0 and fade in with animation below
56     [_touchView setMultipleTouchEnabled:YES];
57     [_touchView setContentMode:UIViewContentModeCenter];
58     
59     
60     CGRect labelRect = frame;
61     labelRect.size.height/=2;
62     //uilabel with the description
63     descriptionLabel = [[UILabel alloc] initWithFrame:labelRect];
64     //gray textcolor on transparent background
65     [descriptionLabel setTextColor:[UIColor grayColor]];
66     [descriptionLabel setBackgroundColor:[UIColor clearColor]];
67     //text is aligned left in its frame
68     [descriptionLabel setTextAlignment:UITextAlignmentCenter];
69     [descriptionLabel setContentMode:UIViewContentModeCenter];
70     //setup multiline behaviour
71     [descriptionLabel setLineBreakMode:UILineBreakModeTailTruncation];
72
73     [descriptionLabel setNumberOfLines:5];
74     CStdString descText    = g_localizeStrings.Get(34404) + "\n";
75     descText              += g_localizeStrings.Get(34405) + "\n";
76     descText              += g_localizeStrings.Get(34406) + "\n";
77     descText              += g_localizeStrings.Get(34407) + "\n";
78     descText              += g_localizeStrings.Get(34408) + "\n";
79
80     NSString *stringFromUTFString = [[NSString alloc] initWithUTF8String:descText];
81     
82     [descriptionLabel setText:stringFromUTFString];
83     [stringFromUTFString release];
84
85     //resize it to full view
86     [descriptionLabel setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
87     [descriptionLabel setAutoresizesSubviews:YES];
88     [_touchView addSubview:descriptionLabel];
89     [descriptionLabel release];
90
91     //load the splash image
92     CStdString strUserSplash = CSpecialProtocol::TranslatePath("special://xbmc/media/Splash.png");
93     xbmcLogo = [UIImage imageWithContentsOfFile:[NSString stringWithUTF8String:strUserSplash.c_str()]];
94     
95     //make a view with the image
96     xbmcLogoView = [[UIImageView alloc] initWithImage:xbmcLogo];
97     //center the image and add it to the view
98     [xbmcLogoView setFrame:frame];
99     [xbmcLogoView setContentMode:UIViewContentModeCenter];
100     //autoresize the image frame
101     [xbmcLogoView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
102     [xbmcLogoView setAutoresizesSubviews:YES];
103     [_touchView addSubview:xbmcLogoView];
104     //send the image to the background
105     [_touchView sendSubviewToBack:xbmcLogoView];
106     [xbmcLogoView release];
107   
108     [[self view] addSubview: _touchView];
109
110     [self createGestureRecognizers];
111
112     [_internalWindow addSubview:[self view]];
113     [_internalWindow setBackgroundColor:[UIColor blackColor]];
114     [_internalWindow setScreen:[UIScreen mainScreen]];
115     [_internalWindow makeKeyAndVisible];
116     [_internalWindow setRootViewController:self];
117
118     [self setWantsFullScreenLayout:YES];
119
120     [self startSleepTimer];//will fade from black too
121   }
122   return self;
123 }
124 //--------------------------------------------------------------
125 - (void)startSleepTimer
126 {
127   NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:touchScreenDimTimeoutSecs]; 
128
129   //schedule sleep timer to fire once in touchScreenDimTimeoutSecs if not reset 
130   _sleepTimer       = [[NSTimer alloc] initWithFireDate:fireDate 
131                                       interval:1 
132                                       target:self 
133                                       selector:@selector(sleepTimerCallback:) 
134                                       userInfo:nil
135                                       repeats:NO]; 
136   //schedule the timer to the runloop
137   NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 
138   [self fadeFromBlack];
139   [runLoop addTimer:_sleepTimer forMode:NSDefaultRunLoopMode]; 
140
141 //--------------------------------------------------------------
142 - (void)stopSleepTimer
143 {
144   if(_sleepTimer != nil)
145   {
146     [_sleepTimer invalidate];
147     [_sleepTimer release];
148     _sleepTimer = nil;
149   }
150 }
151 //--------------------------------------------------------------
152 - (void)sleepTimerCallback:(NSTimer*)theTimer 
153
154   [self fadeToBlack];
155   [self stopSleepTimer];
156
157 //--------------------------------------------------------------
158 - (bool)wakeUpFromSleep//returns false if we where dimmed, true if not
159 {
160   if(_sleepTimer == nil)
161   {
162     [self startSleepTimer];
163     return false;
164   }
165   else
166   {
167     NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:touchScreenDimTimeoutSecs]; 
168     [_sleepTimer setFireDate:fireDate];
169     return true;
170   }
171 }
172 //--------------------------------------------------------------
173 - (void)fadeToBlack
174 {
175     [UIView animateWithDuration:timeFadeSecs delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
176     [_touchView setAlpha:0.01];//fade to black (don't fade to 0.0 else we don't get gesture callbacks)
177     }
178     completion:^(BOOL finished){}];
179 }
180 //--------------------------------------------------------------
181 - (void)fadeFromBlack
182 {
183     [UIView animateWithDuration:timeFadeSecs delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
184     [_touchView setAlpha:1.0];//fade in to full alpha
185     }
186     completion:^(BOOL finished){}];
187 }
188 //--------------------------------------------------------------
189 - (void)createGestureRecognizers
190 {
191   //2 finger single tab - right mouse
192   //single finger double tab delays single finger single tab - so we
193   //go for 2 fingers here - so single finger single tap is instant
194   UITapGestureRecognizer *doubleFingerSingleTap = [[UITapGestureRecognizer alloc]
195                                                     initWithTarget:self action:@selector(handleDoubleFingerSingleTap:)];  
196   [doubleFingerSingleTap setNumberOfTapsRequired:1];
197   [doubleFingerSingleTap setNumberOfTouchesRequired:2];
198   [[self view] addGestureRecognizer:doubleFingerSingleTap];
199   [doubleFingerSingleTap release];
200   
201   //1 finger single long tab - right mouse - alernative
202   UITapGestureRecognizer *singleFingerSingleLongTap = (UITapGestureRecognizer*)[[UILongPressGestureRecognizer alloc]
203                                                         initWithTarget:self action:@selector(handleSingleFingerSingleLongTap:)];  
204   singleFingerSingleLongTap.delaysTouchesBegan = YES;
205   singleFingerSingleLongTap.delaysTouchesEnded = YES;  
206   singleFingerSingleLongTap.numberOfTouchesRequired = 1;
207   [self.view addGestureRecognizer:singleFingerSingleLongTap];
208   [singleFingerSingleLongTap release];
209   
210   //1 finger single tab - left mouse
211   UITapGestureRecognizer *singleFingerSingleTap = [[UITapGestureRecognizer alloc]
212                                                     initWithTarget:self action:@selector(handleSingleFingerSingleTap:)];  
213   [singleFingerSingleTap setDelaysTouchesBegan:NO];
214   [[self view] addGestureRecognizer:singleFingerSingleTap];
215   [singleFingerSingleTap release];
216   
217   //double finger swipe left for backspace ... i like this fast backspace feature ;)
218   UISwipeGestureRecognizer *swipeDoubleLeft = [[UISwipeGestureRecognizer alloc]
219                                           initWithTarget:self action:@selector(handleDoubleSwipeLeft:)];
220   [swipeDoubleLeft setNumberOfTouchesRequired:2];
221   [swipeDoubleLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
222   [[self view] addGestureRecognizer:swipeDoubleLeft];
223   [swipeDoubleLeft release];
224   
225   //single finger swipe left for left
226   UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc]
227                                       initWithTarget:self action:@selector(handleSwipeLeft:)];
228   [swipeLeft setNumberOfTouchesRequired:1];
229   [swipeLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
230   [[self view] addGestureRecognizer:swipeLeft];
231   [swipeLeft release];
232
233   //single finger swipe right for right
234   UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc]
235                                       initWithTarget:self action:@selector(handleSwipeRight:)];
236   [swipeRight setNumberOfTouchesRequired:1];
237   [swipeRight setDirection:UISwipeGestureRecognizerDirectionRight];
238   [[self view] addGestureRecognizer:swipeRight];
239   [swipeRight release];
240
241   //single finger swipe up for up
242   UISwipeGestureRecognizer *swipeUp = [[UISwipeGestureRecognizer alloc]
243                                       initWithTarget:self action:@selector(handleSwipeUp:)];
244   [swipeUp setNumberOfTouchesRequired:1];
245   [swipeUp setDirection:UISwipeGestureRecognizerDirectionUp];
246   [[self view] addGestureRecognizer:swipeUp];  
247   [swipeUp release];
248
249   //single finger swipe down for down
250   UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc]
251                                       initWithTarget:self action:@selector(handleSwipeDown:)];
252   [swipeDown setNumberOfTouchesRequired:1];
253   [swipeDown setDirection:UISwipeGestureRecognizerDirectionDown];
254   [[self view] addGestureRecognizer:swipeDown];
255   [swipeDown release];
256   
257 }
258 //--------------------------------------------------------------
259 - (IBAction)handleDoubleSwipeLeft:(UISwipeGestureRecognizer *)sender 
260 {
261   if([self wakeUpFromSleep])
262   {
263     [g_xbmcController sendKey:XBMCK_BACKSPACE];
264   }
265 }
266 //--------------------------------------------------------------
267 - (IBAction)handleSwipeLeft:(UISwipeGestureRecognizer *)sender 
268 {
269   if([self wakeUpFromSleep])
270   {
271     [g_xbmcController sendKey:XBMCK_LEFT];
272   }
273 }
274 //--------------------------------------------------------------
275 - (IBAction)handleSwipeRight:(UISwipeGestureRecognizer *)sender 
276 {
277   if([self wakeUpFromSleep])
278   {
279     [g_xbmcController sendKey:XBMCK_RIGHT];
280   }
281 }
282 //--------------------------------------------------------------
283 - (IBAction)handleSwipeUp:(UISwipeGestureRecognizer *)sender 
284 {
285   if([self wakeUpFromSleep])
286   {
287     [g_xbmcController sendKey:XBMCK_UP];
288   }
289 }
290 //--------------------------------------------------------------
291 - (IBAction)handleSwipeDown:(UISwipeGestureRecognizer *)sender 
292 {
293   if([self wakeUpFromSleep])
294   {
295     [g_xbmcController sendKey:XBMCK_DOWN];
296   }
297 }
298 //--------------------------------------------------------------
299 - (IBAction)handleDoubleFingerSingleTap:(UIGestureRecognizer *)sender 
300 {
301   if([self wakeUpFromSleep])
302   {
303     [g_xbmcController sendKey:XBMCK_c];
304   }
305 }
306 //--------------------------------------------------------------
307 - (IBAction)handleSingleFingerSingleLongTap:(UIGestureRecognizer *)sender
308 {
309   if([self wakeUpFromSleep])
310   {
311     if (sender.state == UIGestureRecognizerStateEnded)
312     {
313       [self handleDoubleFingerSingleTap:sender];
314     }
315   }
316 }
317 //--------------------------------------------------------------
318 - (IBAction)handleSingleFingerSingleTap:(UIGestureRecognizer *)sender 
319 {
320   if([self wakeUpFromSleep])
321   {
322     [g_xbmcController sendKey:XBMCK_RETURN];
323   }
324 }
325 //--------------------------------------------------------------
326 - (void)viewWillAppear:(BOOL)animated
327 {
328   _startup = true;
329   [super viewWillAppear:animated];
330 }
331 //--------------------------------------------------------------
332 - (void)dealloc
333 {
334   [self stopSleepTimer];
335   [_touchView release];  
336   [_internalWindow release];
337   [super dealloc];  
338 }
339 //--------------------------------------------------------------
340 // - iOS6 rotation API - will be called on iOS7 runtime!--------
341 - (NSUInteger)supportedInterfaceOrientations
342 {
343   // mask defines available as of ios6 sdk
344   //return UIInterfaceOrientationMaskAll;
345   return (1 << UIInterfaceOrientationLandscapeLeft) | (1 << UIInterfaceOrientationLandscapeRight) |
346   (1 << UIInterfaceOrientationPortraitUpsideDown) | (1 << UIInterfaceOrientationPortrait);
347 }
348 - (BOOL)shouldAutorotate
349 {
350   _startup = false;
351   return [self shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)[[UIDevice currentDevice] orientation]];
352 }
353 // - old rotation API will be called on iOS6 and lower - removed in iOS7
354 -(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
355
356   if(_startup)
357   {
358     //start with landscape
359     switch(interfaceOrientation)
360     {
361       case UIInterfaceOrientationLandscapeLeft:
362       case UIInterfaceOrientationLandscapeRight:
363         return YES;
364       default:
365         return FALSE;
366     }
367   }
368   else
369   {
370     return YES;//we allow all rotations after startup...
371   }
372 }
373 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
374 {
375   if(_startup)
376   {
377     //start with landscape
378     switch(toInterfaceOrientation)
379     {
380       case UIInterfaceOrientationLandscapeLeft:
381       case UIInterfaceOrientationLandscapeRight:
382         _startup = false;//allow all orientations after initial landscape rotation
383         break;
384       default:
385         break;
386     }
387   }
388 }
389 //--------------------------------------------------------------
390 @end