blob: 70872d8efb8ea838cc607d4cc693084dc5a5d7bb [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/services/editing/ios/keyboard_impl.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include <UIKit/UIKit.h>
#include <unicode/utf16.h>
static inline UIKeyboardType ToUIKeyboardType(::editing::KeyboardType type) {
using Type = ::editing::KeyboardType;
switch (type) {
case Type::TEXT:
return UIKeyboardTypeDefault;
case Type::NUMBER:
return UIKeyboardTypeDecimalPad;
case Type::PHONE:
return UIKeyboardTypePhonePad;
default:
break;
}
return UIKeyboardTypeDefault;
}
@interface KeyboardClient : UIView<UIKeyInput>
- (void)setClient:(::editing::KeyboardClientPtr)client;
- (void)setEditingState:(::editing::EditingStatePtr)state;
- (void)show;
- (void)hide;
@end
@implementation KeyboardClient {
::editing::KeyboardClientPtr _client;
::editing::EditingStatePtr _state;
base::string16 _text;
}
@synthesize keyboardType = _keyboardType;
- (UITextAutocorrectionType)autocorrectionType {
return UITextAutocorrectionTypeNo;
}
- (void)setClient:(::editing::KeyboardClientPtr)client {
_client = client.Pass();
}
- (void)setEditingState:(::editing::EditingStatePtr)state {
_state = state.Pass();
_text = base::UTF8ToUTF16(_state->text.To<std::string>());
}
- (void)show {
NSAssert([UIApplication sharedApplication].keyWindow != nullptr,
@"The application must have a key window since the keyboard client "
@"must be part of the responder chain to function");
[[UIApplication sharedApplication].keyWindow addSubview:self];
[self becomeFirstResponder];
}
- (void)hide {
[self resignFirstResponder];
[self removeFromSuperview];
}
#pragma mark - UIResponder Overrides
- (BOOL)canBecomeFirstResponder {
return YES;
}
#pragma mark - UIKeyInput Overrides
// TODO(abarth): We should implement UITextInput for more features.
- (BOOL)hasText {
return YES;
}
- (void)insertText:(NSString*)text {
int start = std::max(0, std::min(_state->selection_base, _state->selection_extent));
int end = std::max(0, std::max(_state->selection_base, _state->selection_extent));
int len = end - start;
_text.replace(start, len, base::SysNSStringToUTF16(text));
int caret = start + text.length;
_state->selection_base = caret;
_state->selection_extent = caret;
_state->selection_affinity = ::editing::TextAffinity::UPSTREAM;
_state->selection_is_directional = false;
_state->composing_base = 0;
_state->composing_extent = 0;
_state->text = base::UTF16ToUTF8(_text);
_client->UpdateEditingState(_state.Clone());
}
- (void)deleteBackward {
int start = std::max(0, std::min(_state->selection_base, _state->selection_extent));
int end = std::max(0, std::max(_state->selection_base, _state->selection_extent));
int len = end - start;
if (len > 0) {
_text.erase(start, len);
} else if (start > 0) {
start -= 1;
len = 1;
if (start > 0 &&
UTF16_IS_LEAD(_text[start - 1]) &&
UTF16_IS_TRAIL(_text[start])) {
start -= 1;
len += 1;
}
_text.erase(start, len);
}
_state->selection_base = start;
_state->selection_extent = start;
_state->selection_affinity = ::editing::TextAffinity::DOWNSTREAM;
_state->selection_is_directional = false;
_state->composing_base = 0;
_state->composing_extent = 0;
_state->text = base::UTF16ToUTF8(_text);
_client->UpdateEditingState(_state.Clone());
}
@end
namespace sky {
namespace services {
namespace editing {
KeyboardImpl::KeyboardImpl(
mojo::InterfaceRequest<::editing::Keyboard> request)
: binding_(this, request.Pass()), client_([[KeyboardClient alloc] init]) {}
KeyboardImpl::~KeyboardImpl() {
[client_ hide];
[client_ release];
}
void KeyboardImpl::SetClient(mojo::InterfaceHandle<::editing::KeyboardClient> client,
::editing::KeyboardConfigurationPtr config) {
client_.keyboardType = ToUIKeyboardType(config->type);
[client_ setClient: ::editing::KeyboardClientPtr::Create(client.Pass())];
}
void KeyboardImpl::SetEditingState(::editing::EditingStatePtr state) {
[client_ setEditingState:state.Pass()];
}
void KeyboardImpl::Show() {
[client_ show];
}
void KeyboardImpl::Hide() {
[client_ hide];
}
} // namespace editing
} // namespace services
} // namespace sky