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 // UITextBorderStyleRoundedRect; - with round rect we can't control backgroundcolor
65 _textField.borderStyle = UITextBorderStyleNone;
66 _textField.returnKeyType = UIReturnKeyDone;
67 _textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
68 _textField.backgroundColor = [UIColor whiteColor];
69 _textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
70 _textField.delegate = self;
72 CGRect labelFrame = textFieldFrame;
73 labelFrame.origin.x = 0;
74 _heading = [[UITextField alloc] initWithFrame:labelFrame];
75 _heading.borderStyle = UITextBorderStyleNone;
76 _heading.backgroundColor = [UIColor whiteColor];
77 _heading.adjustsFontSizeToFitWidth = YES;
78 _heading.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
79 _heading.enabled = NO;
81 [self addSubview:_heading];
82 [self addSubview:_textField];
84 self.userInteractionEnabled = YES;
87 [[NSNotificationCenter defaultCenter] addObserver:self
88 selector:@selector(textChanged:)
89 name:UITextFieldTextDidChangeNotification
91 [[NSNotificationCenter defaultCenter] addObserver:self
92 selector:@selector(keyboardDidHide:)
93 name:UIKeyboardDidHideNotification
95 [[NSNotificationCenter defaultCenter] addObserver:self
96 selector:@selector(keyboardWillShow:)
97 name:UIKeyboardWillShowNotification
99 [[NSNotificationCenter defaultCenter] addObserver:self
100 selector:@selector(keyboardDidShow:)
101 name:UIKeyboardDidShowNotification
107 - (void)layoutSubviews
109 CGFloat headingW = 0;
110 if (_heading.text and _heading.text.length > 0)
112 CGSize headingSize = [_heading.text sizeWithFont:[UIFont systemFontOfSize:[UIFont systemFontSize]]];
113 headingW = MIN(self.bounds.size.width/2, headingSize.width+30);
115 CGFloat y = _kbHeight <= 0 ?
116 _textField.frame.origin.y :
117 MIN(self.bounds.size.height-_kbHeight, self.bounds.size.height/5*3) - INPUT_BOX_HEIGHT - SPACE_BETWEEN_INPUT_AND_KEYBOARD;
118 _heading.frame = CGRectMake(0, y, headingW, INPUT_BOX_HEIGHT);
119 _textField.frame = CGRectMake(headingW, y, self.bounds.size.width-headingW, INPUT_BOX_HEIGHT);
122 -(void)keyboardWillShow:(NSNotification *) notification{
123 NSDictionary* info = [notification userInfo];
124 CGRect kbRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
125 LOG(@"keyboardWillShow: keyboard frame: %@", NSStringFromCGRect(kbRect));
126 _kbHeight = kbRect.size.width;
127 [self setNeedsLayout];
128 _keyboardIsShowing = 1;
131 -(void)keyboardDidShow:(NSNotification *) notification{
132 LOG(@"keyboardDidShow: deactivated: %d", _deactivated);
133 _keyboardIsShowing = 2;
135 [self doDeactivate:nil];
138 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
141 [_textField resignFirstResponder];
144 - (BOOL)textFieldShouldEndEditing:(UITextField *)textField
146 LOG(@"%s: keyboard IsShowing %d", __PRETTY_FUNCTION__, _keyboardIsShowing);
147 // Do not break the keyboard show up process, else we will lost
148 // keyboard did hide notifaction.
149 return _keyboardIsShowing != 1;
152 - (void)textFieldDidEndEditing:(UITextField *)textField
158 -(BOOL)textFieldShouldReturn:(UITextField *)textField{
161 [_textField resignFirstResponder];
165 - (void)keyboardDidHide:(id)sender
169 _keyboardIsShowing = 0;
171 if (_textField.editing)
173 LOG(@"kb hide when editing, it could be a language switch");
180 - (void) doActivate:(NSDictionary *)dict
183 [g_xbmcController activateKeyboard:self];
184 [_textField becomeFirstResponder];
185 [self setNeedsLayout];
186 keyboardFinishedEvent.Reset();
192 if([NSThread currentThread] != [NSThread mainThread])
194 [self performSelectorOnMainThread:@selector(doActivate:) withObject:nil waitUntilDone:YES];
198 // this would be fatal! We never should be called from the ios mainthread
202 // emulate a modale dialog here
203 // we are waiting on the user finishing the keyboard
204 // and have to process our app while doing that
205 // basicall what our GUIDialog does if called modal
206 while(!keyboardFinishedEvent.WaitMSec(500) && !g_application.m_bStop)
208 if (NULL != _canceled && *_canceled)
213 // if we are not in xbmc main thread, ProcessRenderLoop() is nop.
214 g_windowManager.ProcessRenderLoop();
218 - (void) doDeactivate:(NSDictionary *)dict
220 LOG(@"%s: keyboard IsShowing %d", __PRETTY_FUNCTION__, _keyboardIsShowing);
223 // Do not break keyboard show up process, if so there's a bug of ios4 will not
224 // notify us keyboard hide.
225 if (_keyboardIsShowing == 1)
228 // invalidate our callback object
231 _iosKeyboard->invalidateCallback();
234 // give back the control to whoever
235 [_textField resignFirstResponder];
237 // allways calld in the mainloop context
238 // detach the keyboard view from our main controller
239 [g_xbmcController deactivateKeyboard:self];
241 // until keyboard did hide, we let the calling thread break loop
242 if (0 == _keyboardIsShowing)
244 // no more notification we want to receive.
245 [[NSNotificationCenter defaultCenter] removeObserver: self];
247 keyboardFinishedEvent.Set();
254 if([NSThread currentThread] != [NSThread mainThread])
256 [self performSelectorOnMainThread:@selector(doDeactivate:) withObject:nil waitUntilDone:YES];
260 [self doDeactivate:nil];
264 - (void) setKeyboardText:(NSString*)aText closeKeyboard:(BOOL)closeKeyboard
266 LOG(@"%s: %@, %d", __PRETTY_FUNCTION__, aText, closeKeyboard);
267 if([NSThread currentThread] != [NSThread mainThread])
269 [self performSelectorOnMainThread:@selector(setDefault:) withObject:aText waitUntilDone:YES];
273 [self setDefault:aText];
282 - (void) setHeading:(NSString *)heading
284 if (heading && heading.length > 0) {
285 _heading.text = [NSString stringWithFormat:@" %@:", heading];
292 - (void) setDefault:(NSString *)defaultText
294 [_textField setText:defaultText];
295 [self textChanged:nil];
298 - (void) setHidden:(BOOL)hidden
300 [_textField setSecureTextEntry:hidden];
303 - (void) textChanged:(NSNotification*)aNotification; {
304 if (![self.text isEqualToString:_textField.text])
306 [self.text setString:_textField.text];
309 _iosKeyboard->fireCallback([self.text UTF8String]);
314 - (void) setCancelFlag:(bool *)cancelFlag
316 _canceled = cancelFlag;