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(&params_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