2 * Copyright (C) 2012-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
20 #define BOOL XBMC_BOOL
21 #include "guilib/GUIWindowManager.h"
22 #include "guilib/GUIKeyboardFactory.h"
23 #include "threads/Event.h"
24 #include "Application.h"
27 #import "IOSKeyboardView.h"
28 #import "IOSScreenManager.h"
29 #import "XBMCController.h"
30 #import "XBMCDebugHelpers.h"
31 #include "IOSKeyboard.h"
33 static CEvent keyboardFinishedEvent;
35 #define INPUT_BOX_HEIGHT 30
36 #define SPACE_BETWEEN_INPUT_AND_KEYBOARD 0
38 @implementation KeyboardView
40 @synthesize _confirmed;
41 @synthesize _iosKeyboard;
43 - (id)initWithFrame:(CGRect)frame
45 self = [super initWithFrame:frame];
49 _keyboardIsShowing = 0;
55 self.text = [NSMutableString stringWithString:@""];
57 // default input box position above the half screen.
58 CGRect textFieldFrame = CGRectMake(frame.size.width/2,
59 frame.size.height/2-INPUT_BOX_HEIGHT-SPACE_BETWEEN_INPUT_AND_KEYBOARD,
62 _textField = [[UITextField alloc] initWithFrame:textFieldFrame];
63 _textField.clearButtonMode = UITextFieldViewModeAlways;
64 _textField.borderStyle = UITextBorderStyleRoundedRect;
65 _textField.returnKeyType = UIReturnKeyDone;
66 _textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
67 _textField.delegate = self;
69 CGRect labelFrame = textFieldFrame;
70 labelFrame.origin.x = 0;
71 _heading = [[UILabel alloc] initWithFrame:labelFrame];
72 _heading.adjustsFontSizeToFitWidth = YES;
74 [self addSubview:_heading];
75 [self addSubview:_textField];
77 self.userInteractionEnabled = YES;
80 [[NSNotificationCenter defaultCenter] addObserver:self
81 selector:@selector(textChanged:)
82 name:UITextFieldTextDidChangeNotification
84 [[NSNotificationCenter defaultCenter] addObserver:self
85 selector:@selector(keyboardDidHide:)
86 name:UIKeyboardDidHideNotification
88 [[NSNotificationCenter defaultCenter] addObserver:self
89 selector:@selector(keyboardWillShow:)
90 name:UIKeyboardWillShowNotification
92 [[NSNotificationCenter defaultCenter] addObserver:self
93 selector:@selector(keyboardDidShow:)
94 name:UIKeyboardDidShowNotification
100 - (void)layoutSubviews
102 CGFloat headingW = 0;
103 if (_heading.text and _heading.text.length > 0)
105 CGSize headingSize = [_heading.text sizeWithFont:[UIFont systemFontOfSize:[UIFont systemFontSize]]];
106 headingW = MIN(self.bounds.size.width/2, headingSize.width+30);
108 CGFloat y = _kbHeight <= 0 ?
109 _textField.frame.origin.y :
110 MIN(self.bounds.size.height-_kbHeight, self.bounds.size.height/5*3) - INPUT_BOX_HEIGHT - SPACE_BETWEEN_INPUT_AND_KEYBOARD;
111 _heading.frame = CGRectMake(0, y, headingW, INPUT_BOX_HEIGHT);
112 _textField.frame = CGRectMake(headingW, y, self.bounds.size.width-headingW, INPUT_BOX_HEIGHT);
115 -(void)keyboardWillShow:(NSNotification *) notification{
116 NSDictionary* info = [notification userInfo];
117 CGRect kbRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
118 LOG(@"keyboardWillShow: keyboard frame: %@", NSStringFromCGRect(kbRect));
119 _kbHeight = kbRect.size.width;
120 [self setNeedsLayout];
121 _keyboardIsShowing = 1;
124 -(void)keyboardDidShow:(NSNotification *) notification{
125 LOG(@"keyboardDidShow: deactivated: %d", _deactivated);
126 _keyboardIsShowing = 2;
128 [self doDeactivate:nil];
131 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
134 [_textField resignFirstResponder];
137 - (BOOL)textFieldShouldEndEditing:(UITextField *)textField
139 LOG(@"%s: keyboard IsShowing %d", __PRETTY_FUNCTION__, _keyboardIsShowing);
140 // Do not break the keyboard show up process, else we will lost
141 // keyboard did hide notifaction.
142 return _keyboardIsShowing != 1;
145 - (void)textFieldDidEndEditing:(UITextField *)textField
151 -(BOOL)textFieldShouldReturn:(UITextField *)textField{
154 [_textField resignFirstResponder];
158 - (void)keyboardDidHide:(id)sender
162 _keyboardIsShowing = 0;
164 if (_textField.editing)
166 LOG(@"kb hide when editing, it could be a language switch");
173 - (void) doActivate:(NSDictionary *)dict
176 [g_xbmcController activateKeyboard:self];
177 [_textField becomeFirstResponder];
178 [self setNeedsLayout];
179 keyboardFinishedEvent.Reset();
185 if([NSThread currentThread] != [NSThread mainThread])
187 [self performSelectorOnMainThread:@selector(doActivate:) withObject:nil waitUntilDone:YES];
191 // this would be fatal! We never should be called from the ios mainthread
195 // emulate a modale dialog here
196 // we are waiting on the user finishing the keyboard
197 // and have to process our app while doing that
198 // basicall what our GUIDialog does if called modal
199 while(!keyboardFinishedEvent.WaitMSec(500) && !g_application.m_bStop)
201 if (NULL != _canceled && *_canceled)
206 // if we are not in xbmc main thread, ProcessRenderLoop() is nop.
207 g_windowManager.ProcessRenderLoop();
211 - (void) doDeactivate:(NSDictionary *)dict
213 LOG(@"%s: keyboard IsShowing %d", __PRETTY_FUNCTION__, _keyboardIsShowing);
216 // Do not break keyboard show up process, if so there's a bug of ios4 will not
217 // notify us keyboard hide.
218 if (_keyboardIsShowing == 1)
221 // invalidate our callback object
224 _iosKeyboard->invalidateCallback();
227 // give back the control to whoever
228 [_textField resignFirstResponder];
230 // allways calld in the mainloop context
231 // detach the keyboard view from our main controller
232 [g_xbmcController deactivateKeyboard:self];
234 // until keyboard did hide, we let the calling thread break loop
235 if (0 == _keyboardIsShowing)
237 // no more notification we want to receive.
238 [[NSNotificationCenter defaultCenter] removeObserver: self];
240 keyboardFinishedEvent.Set();
247 if([NSThread currentThread] != [NSThread mainThread])
249 [self performSelectorOnMainThread:@selector(doDeactivate:) withObject:nil waitUntilDone:YES];
253 [self doDeactivate:nil];
257 - (void) setHeading:(NSString *)heading
259 if (heading && heading.length > 0) {
260 _heading.text = [NSString stringWithFormat:@" %@:", heading];
267 - (void) setDefault:(NSString *)defaultText
269 [_textField setText:defaultText];
270 [self textChanged:nil];
273 - (void) setHidden:(BOOL)hidden
275 [_textField setSecureTextEntry:hidden];
278 - (void) textChanged:(NSNotification*)aNotification; {
279 if (![self.text isEqualToString:_textField.text])
281 [self.text setString:_textField.text];
284 _iosKeyboard->fireCallback([self.text UTF8String]);
289 - (void) setCancelFlag:(bool *)cancelFlag
291 _canceled = cancelFlag;