1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "athena/virtual_keyboard/public/virtual_keyboard_bindings.h" 6 7#include "base/json/json_string_value_serializer.h" 8#include "base/logging.h" 9#include "base/macros.h" 10#include "base/strings/stringprintf.h" 11#include "base/strings/utf_string_conversions.h" 12#include "base/values.h" 13#include "content/public/common/bindings_policy.h" 14#include "content/public/renderer/render_frame.h" 15#include "content/public/renderer/render_view.h" 16#include "content/public/renderer/render_view_observer.h" 17#include "gin/handle.h" 18#include "gin/object_template_builder.h" 19#include "gin/wrappable.h" 20#include "third_party/WebKit/public/web/WebKit.h" 21#include "third_party/WebKit/public/web/WebLocalFrame.h" 22#include "ui/keyboard/keyboard_constants.h" 23 24namespace { 25 26struct VKEvent { 27 std::string event_type; 28 int char_value; 29 int key_code; 30 std::string key_name; 31 int modifiers; 32}; 33 34} // namespace 35 36namespace gin { 37 38template <> 39struct Converter<VKEvent> { 40 static bool FromV8(v8::Isolate* isolate, 41 v8::Handle<v8::Value> val, 42 VKEvent* event) { 43 if (!val->IsObject()) 44 return false; 45 v8::Handle<v8::Object> dict(v8::Handle<v8::Object>::Cast(val)); 46 47 if (!Converter<std::string>::FromV8( 48 isolate, 49 dict->Get(v8::String::NewFromUtf8(isolate, "type")), 50 &event->event_type)) 51 return false; 52 if (!Converter<int32_t>::FromV8( 53 isolate, 54 dict->Get(v8::String::NewFromUtf8(isolate, "charValue")), 55 &event->char_value)) 56 return false; 57 if (!Converter<int32_t>::FromV8( 58 isolate, 59 dict->Get(v8::String::NewFromUtf8(isolate, "keyCode")), 60 &event->key_code)) 61 return false; 62 if (!Converter<std::string>::FromV8( 63 isolate, 64 dict->Get(v8::String::NewFromUtf8(isolate, "keyName")), 65 &event->key_name)) 66 return false; 67 if (!Converter<int32_t>::FromV8( 68 isolate, 69 dict->Get(v8::String::NewFromUtf8(isolate, "modifiers")), 70 &event->modifiers)) 71 return false; 72 73 return true; 74 } 75}; 76 77} // namespace gin 78 79namespace athena { 80 81namespace { 82 83class VKBindings : public gin::Wrappable<VKBindings> { 84 public: 85 static gin::WrapperInfo kWrapperInfo; 86 87 static void Install(content::RenderView* render_view) { 88 blink::WebFrame* web_frame = 89 render_view->GetMainRenderFrame()->GetWebFrame(); 90 v8::Isolate* isolate = blink::mainThreadIsolate(); 91 v8::HandleScope handle_scope(isolate); 92 v8::Handle<v8::Context> context = web_frame->mainWorldScriptContext(); 93 if (context.IsEmpty()) 94 return; 95 96 v8::Context::Scope context_scope(context); 97 98 v8::Handle<v8::Object> global = context->Global(); 99 v8::Handle<v8::Object> chrome = 100 global->Get(gin::StringToV8(isolate, "chrome"))->ToObject(); 101 CHECK(!chrome.IsEmpty()); 102 103 gin::Handle<VKBindings> controller = 104 gin::CreateHandle(isolate, new VKBindings(render_view)); 105 if (controller.IsEmpty()) 106 return; 107 chrome->Set(gin::StringToSymbol(isolate, "virtualKeyboardPrivate"), 108 controller.ToV8()); 109 110 const std::string kInputBoxFocusedEvent = 111 "chrome.virtualKeyboardPrivate.onTextInputBoxFocused = {};" 112 "chrome.virtualKeyboardPrivate.onTextInputBoxFocused.addListener = " 113 " function(callback) { " 114 " window.setTimeout(function() {" 115 " callback({type: 'text'});" 116 " }, 100);" 117 " };"; 118 render_view->GetMainRenderFrame()->ExecuteJavaScript( 119 base::UTF8ToUTF16(kInputBoxFocusedEvent)); 120 } 121 122 private: 123 explicit VKBindings(content::RenderView* render_view) 124 : render_view_(render_view) {} 125 virtual ~VKBindings() {} 126 127 // gin::WrappableBase 128 virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder( 129 v8::Isolate* isolate) OVERRIDE { 130 return gin::Wrappable<VKBindings>::GetObjectTemplateBuilder(isolate) 131 .SetMethod("moveCursor", &VKBindings::NotImplemented) 132 .SetMethod("sendKeyEvent", &VKBindings::SendKeyEvent) 133 .SetMethod("hideKeyboard", &VKBindings::HideKeyboard) 134 .SetMethod("lockKeyboard", &VKBindings::NotImplemented) 135 .SetMethod("keyboardLoaded", &VKBindings::NotImplemented) 136 .SetMethod("getKeyboardConfig", &VKBindings::NotImplemented); 137 } 138 139 void SendKeyEvent(gin::Arguments* args) { 140 VKEvent event; 141 if (!args->GetNext(&event)) { 142 LOG(ERROR) << "Failed to get the type"; 143 return; 144 } 145 base::ListValue params; 146 params.Set(0, base::Value::CreateStringValue(event.event_type)); 147 params.Set(1, base::Value::CreateIntegerValue(event.char_value)); 148 params.Set(2, base::Value::CreateIntegerValue(event.key_code)); 149 params.Set(3, base::Value::CreateStringValue(event.key_name)); 150 params.Set(4, base::Value::CreateIntegerValue(event.modifiers)); 151 152 std::string params_json; 153 JSONStringValueSerializer serializer(¶ms_json); 154 if (!serializer.Serialize(params)) 155 return; 156 157 render_view_->GetMainRenderFrame()->ExecuteJavaScript( 158 base::UTF8ToUTF16("chrome.send('sendKeyEvent', " + params_json + ")")); 159 } 160 161 void HideKeyboard() { 162 render_view_->GetMainRenderFrame()->ExecuteJavaScript( 163 base::UTF8ToUTF16("chrome.send('hideKeyboard', [])")); 164 } 165 166 void NotImplemented(gin::Arguments* args) { NOTIMPLEMENTED(); } 167 168 content::RenderView* render_view_; 169 170 DISALLOW_COPY_AND_ASSIGN(VKBindings); 171}; 172 173gin::WrapperInfo VKBindings::kWrapperInfo = {gin::kEmbedderNativeGin}; 174 175class VirtualKeyboardBindingsImpl : public VirtualKeyboardBindings, 176 public content::RenderViewObserver { 177 public: 178 explicit VirtualKeyboardBindingsImpl(content::RenderView* render_view) 179 : content::RenderViewObserver(render_view) {} 180 181 virtual ~VirtualKeyboardBindingsImpl() {} 182 183 private: 184 // content::RenderViewObserver: 185 virtual void Navigate(const GURL& url) OVERRIDE { 186 bool enabled_bindings = render_view()->GetEnabledBindings(); 187 if (!(enabled_bindings & content::BINDINGS_POLICY_WEB_UI)) 188 return; 189 if (url.GetOrigin() == GURL(keyboard::kKeyboardURL)) 190 VKBindings::Install(render_view()); 191 } 192 DISALLOW_COPY_AND_ASSIGN(VirtualKeyboardBindingsImpl); 193}; 194 195} // namespace 196 197VirtualKeyboardBindings* VirtualKeyboardBindings::Create( 198 content::RenderView* render_view) { 199 return new VirtualKeyboardBindingsImpl(render_view); 200} 201 202} // namespace athena 203