OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/renderer_host/gtk_key_bindings_handler.h" | 5 #include "chrome/browser/ui/libgtk2ui/gtk2_key_bindings_handler.h" |
6 | 6 |
7 #include <gdk/gdkkeysyms.h> | 7 #include <gdk/gdkkeysyms.h> |
8 #include <X11/Xlib.h> | |
9 #include <X11/XKBlib.h> | |
8 | 10 |
9 #include <string> | 11 #include <string> |
10 | 12 |
11 #include "base/logging.h" | 13 #include "base/logging.h" |
12 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
15 #include "chrome/browser/ui/libgtk2ui/gtk2_util.h" | |
13 #include "content/public/browser/native_web_keyboard_event.h" | 16 #include "content/public/browser/native_web_keyboard_event.h" |
17 #include "ui/base/x/x11_util.h" | |
18 #include "ui/events/event.h" | |
14 | 19 |
15 namespace content { | 20 namespace libgtk2ui { |
16 | 21 |
17 GtkKeyBindingsHandler::GtkKeyBindingsHandler(GtkWidget* parent_widget) | 22 Gtk2KeyBindingsHandler::Gtk2KeyBindingsHandler() |
18 : handler_(CreateNewHandler()) { | 23 : fake_window_(gtk_offscreen_window_new()), |
19 DCHECK(GTK_IS_FIXED(parent_widget)); | 24 handler_(CreateNewHandler()), |
20 // We need add the |handler_| object into gtk widget hierarchy, so that | 25 has_xkb_(false) { |
21 // gtk_bindings_activate_event() can find correct display and keymaps from | 26 gtk_container_add(GTK_CONTAINER(fake_window_), handler_.get()); |
22 // the |handler_| object. | 27 |
23 gtk_fixed_put(GTK_FIXED(parent_widget), handler_.get(), -1, -1); | 28 int opcode, event, error; |
29 int major = XkbMajorVersion; | |
30 int minor = XkbMinorVersion; | |
31 if (XkbQueryExtension(gfx::GetXDisplay(), &opcode, &event, &error, | |
32 &major, &minor)) | |
33 has_xkb_ = true; | |
24 } | 34 } |
25 | 35 |
26 GtkKeyBindingsHandler::~GtkKeyBindingsHandler() { | 36 Gtk2KeyBindingsHandler::~Gtk2KeyBindingsHandler() { |
27 handler_.Destroy(); | 37 handler_.Destroy(); |
38 gtk_widget_destroy(fake_window_); | |
28 } | 39 } |
29 | 40 |
30 bool GtkKeyBindingsHandler::Match(const NativeWebKeyboardEvent& wke, | 41 bool Gtk2KeyBindingsHandler::Match(const content::NativeWebKeyboardEvent& wke, |
31 EditCommands* edit_commands) { | 42 content::EditCommands* edit_commands) { |
32 if (wke.type == blink::WebInputEvent::Char || !wke.os_event) | 43 if (wke.type == blink::WebInputEvent::Char || !wke.os_event) |
33 return false; | 44 return false; |
34 | 45 |
46 GdkEventKey gdk_event; | |
47 BuildGdkEventKeyFromXEvent(wke.os_event->native_event(), &gdk_event); | |
48 | |
35 edit_commands_.clear(); | 49 edit_commands_.clear(); |
36 // If this key event matches a predefined key binding, corresponding signal | 50 // If this key event matches a predefined key binding, corresponding signal |
37 // will be emitted. | 51 // will be emitted. |
38 gtk_bindings_activate_event(GTK_OBJECT(handler_.get()), &wke.os_event->key); | 52 gtk_bindings_activate_event(GTK_OBJECT(handler_.get()), &gdk_event); |
39 | 53 |
40 bool matched = !edit_commands_.empty(); | 54 bool matched = !edit_commands_.empty(); |
41 if (edit_commands) | 55 if (edit_commands) |
42 edit_commands->swap(edit_commands_); | 56 edit_commands->swap(edit_commands_); |
43 return matched; | 57 return matched; |
44 } | 58 } |
45 | 59 |
46 GtkWidget* GtkKeyBindingsHandler::CreateNewHandler() { | 60 GtkWidget* Gtk2KeyBindingsHandler::CreateNewHandler() { |
47 Handler* handler = | 61 Handler* handler = |
48 static_cast<Handler*>(g_object_new(HandlerGetType(), NULL)); | 62 static_cast<Handler*>(g_object_new(HandlerGetType(), NULL)); |
49 | 63 |
50 handler->owner = this; | 64 handler->owner = this; |
51 | 65 |
52 // We don't need to show the |handler| object on screen, so set its size to | 66 // We don't need to show the |handler| object on screen, so set its size to |
53 // zero. | 67 // zero. |
54 gtk_widget_set_size_request(GTK_WIDGET(handler), 0, 0); | 68 gtk_widget_set_size_request(GTK_WIDGET(handler), 0, 0); |
55 | 69 |
56 // Prevents it from handling any events by itself. | 70 // Prevents it from handling any events by itself. |
57 gtk_widget_set_sensitive(GTK_WIDGET(handler), FALSE); | 71 gtk_widget_set_sensitive(GTK_WIDGET(handler), FALSE); |
58 gtk_widget_set_events(GTK_WIDGET(handler), 0); | 72 gtk_widget_set_events(GTK_WIDGET(handler), 0); |
59 gtk_widget_set_can_focus(GTK_WIDGET(handler), TRUE); | 73 gtk_widget_set_can_focus(GTK_WIDGET(handler), TRUE); |
60 | 74 |
61 return GTK_WIDGET(handler); | 75 return GTK_WIDGET(handler); |
62 } | 76 } |
63 | 77 |
64 void GtkKeyBindingsHandler::EditCommandMatched( | 78 void Gtk2KeyBindingsHandler::EditCommandMatched( |
65 const std::string& name, const std::string& value) { | 79 const std::string& name, const std::string& value) { |
66 edit_commands_.push_back(EditCommand(name, value)); | 80 edit_commands_.push_back(content::EditCommand(name, value)); |
67 } | 81 } |
68 | 82 |
69 void GtkKeyBindingsHandler::HandlerInit(Handler *self) { | 83 void Gtk2KeyBindingsHandler::BuildGdkEventKeyFromXEvent( |
84 const base::NativeEvent& xevent, | |
85 GdkEventKey* gdk_event) { | |
86 GdkKeymap *keymap = gdk_keymap_get_for_display(gdk_display_get_default()); | |
87 GdkModifierType consumed, state; | |
88 | |
89 gdk_event->type = xevent->xany.type == KeyPress ? | |
90 GDK_KEY_PRESS : GDK_KEY_RELEASE; | |
91 gdk_event->time = xevent->xkey.time; | |
92 gdk_event->state = static_cast<GdkModifierType>(xevent->xkey.state); | |
93 gdk_event->hardware_keycode = xevent->xkey.keycode; | |
94 | |
95 if (has_xkb_) { | |
96 gdk_event->group = XkbGroupForCoreState(xevent->xkey.state); | |
97 } else { | |
98 // TODO(erg): I don't understand what this is for. I read through parts of | |
99 // gdkevent-x11.c. Just calling XkbGroupForCoreState() if we have XKB is | |
100 // simple enough, but I don't understand X11 input handling enough to know | |
101 // what this is for, and reading through what GDK does to try to calculate | |
102 // this was not enlightening. | |
103 // | |
104 // Also, does anyone actually have servers that don't support XKB at this | |
105 // point? | |
Elliot Glaysher
2014/03/26 21:42:41
piman, do you have any thoughts on what this is su
piman
2014/03/26 23:44:26
My reading of it:
GDK installs in the core keymap
| |
106 NOTIMPLEMENTED(); | |
107 gdk_event->group = 0; | |
108 } | |
109 | |
110 gdk_event->keyval = GDK_VoidSymbol; | |
111 gdk_keymap_translate_keyboard_state( | |
112 keymap, | |
113 gdk_event->hardware_keycode, | |
114 static_cast<GdkModifierType>(gdk_event->state), | |
115 gdk_event->group, | |
116 &gdk_event->keyval, | |
117 NULL, NULL, &consumed); | |
118 | |
119 state = static_cast<GdkModifierType>(gdk_event->state & ~consumed); | |
120 gdk_keymap_add_virtual_modifiers(keymap, &state); | |
121 gdk_event->state |= state; | |
122 } | |
123 | |
124 void Gtk2KeyBindingsHandler::HandlerInit(Handler *self) { | |
70 self->owner = NULL; | 125 self->owner = NULL; |
71 } | 126 } |
72 | 127 |
73 void GtkKeyBindingsHandler::HandlerClassInit(HandlerClass *klass) { | 128 void Gtk2KeyBindingsHandler::HandlerClassInit(HandlerClass *klass) { |
74 GtkTextViewClass* text_view_class = GTK_TEXT_VIEW_CLASS(klass); | 129 GtkTextViewClass* text_view_class = GTK_TEXT_VIEW_CLASS(klass); |
75 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass); | 130 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass); |
76 | 131 |
77 // Overrides all virtual methods related to editor key bindings. | 132 // Overrides all virtual methods related to editor key bindings. |
78 text_view_class->backspace = BackSpace; | 133 text_view_class->backspace = BackSpace; |
79 text_view_class->copy_clipboard = CopyClipboard; | 134 text_view_class->copy_clipboard = CopyClipboard; |
80 text_view_class->cut_clipboard = CutClipboard; | 135 text_view_class->cut_clipboard = CutClipboard; |
81 text_view_class->delete_from_cursor = DeleteFromCursor; | 136 text_view_class->delete_from_cursor = DeleteFromCursor; |
82 text_view_class->insert_at_cursor = InsertAtCursor; | 137 text_view_class->insert_at_cursor = InsertAtCursor; |
83 text_view_class->move_cursor = MoveCursor; | 138 text_view_class->move_cursor = MoveCursor; |
(...skipping 16 matching lines...) Expand all Loading... | |
100 | 155 |
101 g_signal_override_class_handler("select-all", | 156 g_signal_override_class_handler("select-all", |
102 G_TYPE_FROM_CLASS(klass), | 157 G_TYPE_FROM_CLASS(klass), |
103 G_CALLBACK(SelectAll)); | 158 G_CALLBACK(SelectAll)); |
104 | 159 |
105 g_signal_override_class_handler("toggle-cursor-visible", | 160 g_signal_override_class_handler("toggle-cursor-visible", |
106 G_TYPE_FROM_CLASS(klass), | 161 G_TYPE_FROM_CLASS(klass), |
107 G_CALLBACK(ToggleCursorVisible)); | 162 G_CALLBACK(ToggleCursorVisible)); |
108 } | 163 } |
109 | 164 |
110 GType GtkKeyBindingsHandler::HandlerGetType() { | 165 GType Gtk2KeyBindingsHandler::HandlerGetType() { |
111 static volatile gsize type_id_volatile = 0; | 166 static volatile gsize type_id_volatile = 0; |
112 if (g_once_init_enter(&type_id_volatile)) { | 167 if (g_once_init_enter(&type_id_volatile)) { |
113 GType type_id = g_type_register_static_simple( | 168 GType type_id = g_type_register_static_simple( |
114 GTK_TYPE_TEXT_VIEW, | 169 GTK_TYPE_TEXT_VIEW, |
115 g_intern_static_string("GtkKeyBindingsHandler"), | 170 g_intern_static_string("Gtk2KeyBindingsHandler"), |
116 sizeof(HandlerClass), | 171 sizeof(HandlerClass), |
117 reinterpret_cast<GClassInitFunc>(HandlerClassInit), | 172 reinterpret_cast<GClassInitFunc>(HandlerClassInit), |
118 sizeof(Handler), | 173 sizeof(Handler), |
119 reinterpret_cast<GInstanceInitFunc>(HandlerInit), | 174 reinterpret_cast<GInstanceInitFunc>(HandlerInit), |
120 static_cast<GTypeFlags>(0)); | 175 static_cast<GTypeFlags>(0)); |
121 g_once_init_leave(&type_id_volatile, type_id); | 176 g_once_init_leave(&type_id_volatile, type_id); |
122 } | 177 } |
123 return type_id_volatile; | 178 return type_id_volatile; |
124 } | 179 } |
125 | 180 |
126 GtkKeyBindingsHandler* GtkKeyBindingsHandler::GetHandlerOwner( | 181 Gtk2KeyBindingsHandler* Gtk2KeyBindingsHandler::GetHandlerOwner( |
127 GtkTextView* text_view) { | 182 GtkTextView* text_view) { |
128 Handler* handler = G_TYPE_CHECK_INSTANCE_CAST( | 183 Handler* handler = G_TYPE_CHECK_INSTANCE_CAST( |
129 text_view, HandlerGetType(), Handler); | 184 text_view, HandlerGetType(), Handler); |
130 DCHECK(handler); | 185 DCHECK(handler); |
131 return handler->owner; | 186 return handler->owner; |
132 } | 187 } |
133 | 188 |
134 void GtkKeyBindingsHandler::BackSpace(GtkTextView* text_view) { | 189 void Gtk2KeyBindingsHandler::BackSpace(GtkTextView* text_view) { |
135 GetHandlerOwner(text_view) | 190 GetHandlerOwner(text_view) |
136 ->EditCommandMatched("DeleteBackward", std::string()); | 191 ->EditCommandMatched("DeleteBackward", std::string()); |
137 } | 192 } |
138 | 193 |
139 void GtkKeyBindingsHandler::CopyClipboard(GtkTextView* text_view) { | 194 void Gtk2KeyBindingsHandler::CopyClipboard(GtkTextView* text_view) { |
140 GetHandlerOwner(text_view)->EditCommandMatched("Copy", std::string()); | 195 GetHandlerOwner(text_view)->EditCommandMatched("Copy", std::string()); |
141 } | 196 } |
142 | 197 |
143 void GtkKeyBindingsHandler::CutClipboard(GtkTextView* text_view) { | 198 void Gtk2KeyBindingsHandler::CutClipboard(GtkTextView* text_view) { |
144 GetHandlerOwner(text_view)->EditCommandMatched("Cut", std::string()); | 199 GetHandlerOwner(text_view)->EditCommandMatched("Cut", std::string()); |
145 } | 200 } |
146 | 201 |
147 void GtkKeyBindingsHandler::DeleteFromCursor( | 202 void Gtk2KeyBindingsHandler::DeleteFromCursor( |
148 GtkTextView* text_view, GtkDeleteType type, gint count) { | 203 GtkTextView* text_view, GtkDeleteType type, gint count) { |
149 if (!count) | 204 if (!count) |
150 return; | 205 return; |
151 | 206 |
152 const char *commands[3] = { NULL, NULL, NULL }; | 207 const char *commands[3] = { NULL, NULL, NULL }; |
153 switch (type) { | 208 switch (type) { |
154 case GTK_DELETE_CHARS: | 209 case GTK_DELETE_CHARS: |
155 commands[0] = (count > 0 ? "DeleteForward" : "DeleteBackward"); | 210 commands[0] = (count > 0 ? "DeleteForward" : "DeleteBackward"); |
156 break; | 211 break; |
157 case GTK_DELETE_WORD_ENDS: | 212 case GTK_DELETE_WORD_ENDS: |
(...skipping 22 matching lines...) Expand all Loading... | |
180 break; | 235 break; |
181 case GTK_DELETE_PARAGRAPHS: | 236 case GTK_DELETE_PARAGRAPHS: |
182 commands[0] = "MoveToBeginningOfParagraph"; | 237 commands[0] = "MoveToBeginningOfParagraph"; |
183 commands[1] = "DeleteToEndOfParagraph"; | 238 commands[1] = "DeleteToEndOfParagraph"; |
184 break; | 239 break; |
185 default: | 240 default: |
186 // GTK_DELETE_WHITESPACE has no corresponding editor command. | 241 // GTK_DELETE_WHITESPACE has no corresponding editor command. |
187 return; | 242 return; |
188 } | 243 } |
189 | 244 |
190 GtkKeyBindingsHandler* owner = GetHandlerOwner(text_view); | 245 Gtk2KeyBindingsHandler* owner = GetHandlerOwner(text_view); |
191 if (count < 0) | 246 if (count < 0) |
192 count = -count; | 247 count = -count; |
193 for (; count > 0; --count) { | 248 for (; count > 0; --count) { |
194 for (const char* const* p = commands; *p; ++p) | 249 for (const char* const* p = commands; *p; ++p) |
195 owner->EditCommandMatched(*p, std::string()); | 250 owner->EditCommandMatched(*p, std::string()); |
196 } | 251 } |
197 } | 252 } |
198 | 253 |
199 void GtkKeyBindingsHandler::InsertAtCursor(GtkTextView* text_view, | 254 void Gtk2KeyBindingsHandler::InsertAtCursor(GtkTextView* text_view, |
200 const gchar* str) { | 255 const gchar* str) { |
201 if (str && *str) | 256 if (str && *str) |
202 GetHandlerOwner(text_view)->EditCommandMatched("InsertText", str); | 257 GetHandlerOwner(text_view)->EditCommandMatched("InsertText", str); |
203 } | 258 } |
204 | 259 |
205 void GtkKeyBindingsHandler::MoveCursor( | 260 void Gtk2KeyBindingsHandler::MoveCursor( |
206 GtkTextView* text_view, GtkMovementStep step, gint count, | 261 GtkTextView* text_view, GtkMovementStep step, gint count, |
207 gboolean extend_selection) { | 262 gboolean extend_selection) { |
208 if (!count) | 263 if (!count) |
209 return; | 264 return; |
210 | 265 |
211 std::string command; | 266 std::string command; |
212 switch (step) { | 267 switch (step) { |
213 case GTK_MOVEMENT_LOGICAL_POSITIONS: | 268 case GTK_MOVEMENT_LOGICAL_POSITIONS: |
214 command = (count > 0 ? "MoveForward" : "MoveBackward"); | 269 command = (count > 0 ? "MoveForward" : "MoveBackward"); |
215 break; | 270 break; |
(...skipping 19 matching lines...) Expand all Loading... | |
235 case GTK_MOVEMENT_BUFFER_ENDS: | 290 case GTK_MOVEMENT_BUFFER_ENDS: |
236 command = (count > 0 ? "MoveToEndOfDocument" : | 291 command = (count > 0 ? "MoveToEndOfDocument" : |
237 "MoveToBeginningOfDocument"); | 292 "MoveToBeginningOfDocument"); |
238 break; | 293 break; |
239 default: | 294 default: |
240 // GTK_MOVEMENT_PARAGRAPHS and GTK_MOVEMENT_HORIZONTAL_PAGES have | 295 // GTK_MOVEMENT_PARAGRAPHS and GTK_MOVEMENT_HORIZONTAL_PAGES have |
241 // no corresponding editor commands. | 296 // no corresponding editor commands. |
242 return; | 297 return; |
243 } | 298 } |
244 | 299 |
245 GtkKeyBindingsHandler* owner = GetHandlerOwner(text_view); | 300 Gtk2KeyBindingsHandler* owner = GetHandlerOwner(text_view); |
246 if (extend_selection) | 301 if (extend_selection) |
247 command.append("AndModifySelection"); | 302 command.append("AndModifySelection"); |
248 if (count < 0) | 303 if (count < 0) |
249 count = -count; | 304 count = -count; |
250 for (; count > 0; --count) | 305 for (; count > 0; --count) |
251 owner->EditCommandMatched(command, std::string()); | 306 owner->EditCommandMatched(command, std::string()); |
252 } | 307 } |
253 | 308 |
254 void GtkKeyBindingsHandler::MoveViewport( | 309 void Gtk2KeyBindingsHandler::MoveViewport( |
255 GtkTextView* text_view, GtkScrollStep step, gint count) { | 310 GtkTextView* text_view, GtkScrollStep step, gint count) { |
256 // Not supported by webkit. | 311 // Not supported by webkit. |
257 } | 312 } |
258 | 313 |
259 void GtkKeyBindingsHandler::PasteClipboard(GtkTextView* text_view) { | 314 void Gtk2KeyBindingsHandler::PasteClipboard(GtkTextView* text_view) { |
260 GetHandlerOwner(text_view)->EditCommandMatched("Paste", std::string()); | 315 GetHandlerOwner(text_view)->EditCommandMatched("Paste", std::string()); |
261 } | 316 } |
262 | 317 |
263 void GtkKeyBindingsHandler::SelectAll(GtkTextView* text_view, gboolean select) { | 318 void Gtk2KeyBindingsHandler::SelectAll(GtkTextView* text_view, |
319 gboolean select) { | |
264 if (select) | 320 if (select) |
265 GetHandlerOwner(text_view)->EditCommandMatched("SelectAll", std::string()); | 321 GetHandlerOwner(text_view)->EditCommandMatched("SelectAll", std::string()); |
266 else | 322 else |
267 GetHandlerOwner(text_view)->EditCommandMatched("Unselect", std::string()); | 323 GetHandlerOwner(text_view)->EditCommandMatched("Unselect", std::string()); |
268 } | 324 } |
269 | 325 |
270 void GtkKeyBindingsHandler::SetAnchor(GtkTextView* text_view) { | 326 void Gtk2KeyBindingsHandler::SetAnchor(GtkTextView* text_view) { |
271 GetHandlerOwner(text_view)->EditCommandMatched("SetMark", std::string()); | 327 GetHandlerOwner(text_view)->EditCommandMatched("SetMark", std::string()); |
272 } | 328 } |
273 | 329 |
274 void GtkKeyBindingsHandler::ToggleCursorVisible(GtkTextView* text_view) { | 330 void Gtk2KeyBindingsHandler::ToggleCursorVisible(GtkTextView* text_view) { |
275 // Not supported by webkit. | 331 // Not supported by webkit. |
276 } | 332 } |
277 | 333 |
278 void GtkKeyBindingsHandler::ToggleOverwrite(GtkTextView* text_view) { | 334 void Gtk2KeyBindingsHandler::ToggleOverwrite(GtkTextView* text_view) { |
279 // Not supported by webkit. | 335 // Not supported by webkit. |
280 } | 336 } |
281 | 337 |
282 gboolean GtkKeyBindingsHandler::ShowHelp(GtkWidget* widget, | 338 gboolean Gtk2KeyBindingsHandler::ShowHelp(GtkWidget* widget, |
283 GtkWidgetHelpType arg1) { | 339 GtkWidgetHelpType arg1) { |
284 // Just for disabling the default handler. | 340 // Just for disabling the default handler. |
285 return FALSE; | 341 return FALSE; |
286 } | 342 } |
287 | 343 |
288 void GtkKeyBindingsHandler::MoveFocus(GtkWidget* widget, | 344 void Gtk2KeyBindingsHandler::MoveFocus(GtkWidget* widget, |
289 GtkDirectionType arg1) { | 345 GtkDirectionType arg1) { |
290 // Just for disabling the default handler. | 346 // Just for disabling the default handler. |
291 } | 347 } |
292 | 348 |
293 } // namespace content | 349 } // namespace libgtk2ui |
OLD | NEW |