Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Side by Side Diff: chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2.cc

Issue 335923004: aura-linux: Fixes super/hyper/meta key support. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2.h" 5 #include "chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2.h"
6 6
7 #include <gdk/gdk.h> 7 #include <gdk/gdk.h>
8 #include <gdk/gdkkeysyms.h> 8 #include <gdk/gdkkeysyms.h>
9 #include <gdk/gdkx.h> 9 #include <gdk/gdkx.h>
10 10
11 #include <gtk/gtk.h> 11 #include <gtk/gtk.h>
12 12
13 #include <X11/X.h> 13 #include <X11/X.h>
14 #include <X11/Xlib.h> 14 #include <X11/Xlib.h>
15 15
16 #include "base/event_types.h"
17 #include "base/message_loop/message_loop.h" 16 #include "base/message_loop/message_loop.h"
18 #include "base/strings/utf_string_conversions.h" 17 #include "base/strings/utf_string_conversions.h"
19 #include "ui/base/ime/composition_text.h" 18 #include "ui/base/ime/composition_text.h"
20 #include "ui/base/ime/composition_text_util_pango.h" 19 #include "ui/base/ime/composition_text_util_pango.h"
21 #include "ui/base/ime/text_input_client.h" 20 #include "ui/base/ime/text_input_client.h"
22 #include "ui/events/event.h" 21 #include "ui/events/event.h"
23 #include "ui/gfx/x/x11_types.h" 22 #include "ui/gfx/x/x11_types.h"
24 23
25 namespace {
26
27 // Constructs a GdkEventKey from a XKeyEvent and returns it. Otherwise,
28 // returns NULL. The returned GdkEvent must be freed by gdk_event_free.
29 GdkEvent* GdkEventFromXKeyEvent(XKeyEvent& xkey, bool is_modifier) {
30 DCHECK(xkey.type == KeyPress || xkey.type == KeyRelease);
31
32 // Get a GdkDisplay.
33 GdkDisplay* display = gdk_x11_lookup_xdisplay(xkey.display);
34 if (!display) {
35 // Fall back to the default display.
36 display = gdk_display_get_default();
37 }
38 if (!display) {
39 LOG(ERROR) << "Cannot get a GdkDisplay for a key event.";
40 return NULL;
41 }
42 // Get a keysym and group.
43 KeySym keysym = NoSymbol;
44 guint8 keyboard_group = 0;
45 XLookupString(&xkey, NULL, 0, &keysym, NULL);
46 GdkKeymap* keymap = gdk_keymap_get_for_display(display);
47 GdkKeymapKey* keys = NULL;
48 guint* keyvals = NULL;
49 gint n_entries = 0;
50 if (keymap &&
51 gdk_keymap_get_entries_for_keycode(keymap, xkey.keycode,
52 &keys, &keyvals, &n_entries)) {
53 for (gint i = 0; i < n_entries; ++i) {
54 if (keyvals[i] == keysym) {
55 keyboard_group = keys[i].group;
56 break;
57 }
58 }
59 }
60 g_free(keys);
61 keys = NULL;
62 g_free(keyvals);
63 keyvals = NULL;
64 // Get a GdkWindow.
65 GdkWindow* window = gdk_x11_window_lookup_for_display(display, xkey.window);
66 if (window)
67 g_object_ref(window);
68 else
69 window = gdk_x11_window_foreign_new_for_display(display, xkey.window);
70 if (!window) {
71 LOG(ERROR) << "Cannot get a GdkWindow for a key event.";
72 return NULL;
73 }
74
75 // Create a GdkEvent.
76 GdkEventType event_type = xkey.type == KeyPress ?
77 GDK_KEY_PRESS : GDK_KEY_RELEASE;
78 GdkEvent* event = gdk_event_new(event_type);
79 event->key.type = event_type;
80 event->key.window = window;
81 // GdkEventKey and XKeyEvent share the same definition for time and state.
82 event->key.send_event = xkey.send_event;
83 event->key.time = xkey.time;
84 event->key.state = xkey.state;
85 event->key.keyval = keysym;
86 event->key.length = 0;
87 event->key.string = NULL;
88 event->key.hardware_keycode = xkey.keycode;
89 event->key.group = keyboard_group;
90 event->key.is_modifier = is_modifier;
91 return event;
92 }
93
94 } // namespace
95
96 namespace libgtk2ui { 24 namespace libgtk2ui {
97 25
98 X11InputMethodContextImplGtk2::X11InputMethodContextImplGtk2( 26 X11InputMethodContextImplGtk2::X11InputMethodContextImplGtk2(
99 ui::LinuxInputMethodContextDelegate* delegate) 27 ui::LinuxInputMethodContextDelegate* delegate)
100 : delegate_(delegate), 28 : delegate_(delegate),
101 gtk_context_simple_(NULL), 29 gtk_context_simple_(NULL),
102 gtk_multicontext_(NULL), 30 gtk_multicontext_(NULL),
103 gtk_context_(NULL), 31 gtk_context_(NULL),
104 gdk_last_set_client_window_(NULL) { 32 gdk_last_set_client_window_(NULL) {
105 CHECK(delegate_); 33 CHECK(delegate_);
106 34
107 { 35 ResetXModifierKeycodesCache();
108 XModifierKeymap* keymap = XGetModifierMapping(gfx::GetXDisplay());
109 for (int i = 0; i < 8 * keymap->max_keypermod; ++i) {
110 if (keymap->modifiermap[i])
111 modifier_keycodes_.insert(keymap->modifiermap[i]);
112 }
113 XFreeModifiermap(keymap);
114 }
115 36
116 gtk_context_simple_ = gtk_im_context_simple_new(); 37 gtk_context_simple_ = gtk_im_context_simple_new();
117 gtk_multicontext_ = gtk_im_multicontext_new(); 38 gtk_multicontext_ = gtk_im_multicontext_new();
118 39
119 GtkIMContext* contexts[] = {gtk_context_simple_, gtk_multicontext_}; 40 GtkIMContext* contexts[] = {gtk_context_simple_, gtk_multicontext_};
120 for (size_t i = 0; i < arraysize(contexts); ++i) { 41 for (size_t i = 0; i < arraysize(contexts); ++i) {
121 g_signal_connect(contexts[i], "commit", 42 g_signal_connect(contexts[i], "commit",
122 G_CALLBACK(OnCommitThunk), this); 43 G_CALLBACK(OnCommitThunk), this);
123 g_signal_connect(contexts[i], "preedit-changed", 44 g_signal_connect(contexts[i], "preedit-changed",
124 G_CALLBACK(OnPreeditChangedThunk), this); 45 G_CALLBACK(OnPreeditChangedThunk), this);
(...skipping 24 matching lines...) Expand all
149 bool X11InputMethodContextImplGtk2::DispatchKeyEvent( 70 bool X11InputMethodContextImplGtk2::DispatchKeyEvent(
150 const ui::KeyEvent& key_event) { 71 const ui::KeyEvent& key_event) {
151 if (!key_event.HasNativeEvent()) 72 if (!key_event.HasNativeEvent())
152 return false; 73 return false;
153 74
154 // The caller must call Focus() first. 75 // The caller must call Focus() first.
155 if (!gtk_context_) 76 if (!gtk_context_)
156 return false; 77 return false;
157 78
158 // Translate a XKeyEvent to a GdkEventKey. 79 // Translate a XKeyEvent to a GdkEventKey.
159 const base::NativeEvent& native_key_event = key_event.native_event(); 80 GdkEvent* event = GdkEventFromNativeEvent(key_event.native_event());
160 GdkEvent* event = GdkEventFromXKeyEvent(
161 native_key_event->xkey,
162 IsKeycodeModifierKey(native_key_event->xkey.keycode));
163 if (!event) { 81 if (!event) {
164 LOG(ERROR) << "Cannot translate a XKeyEvent to a GdkEvent."; 82 LOG(ERROR) << "Cannot translate a XKeyEvent to a GdkEvent.";
165 return false; 83 return false;
166 } 84 }
167 85
168 // Set the client window and cursor location. 86 // Set the client window and cursor location.
169 if (event->key.window != gdk_last_set_client_window_) { 87 if (event->key.window != gdk_last_set_client_window_) {
170 gtk_im_context_set_client_window(gtk_context_, event->key.window); 88 gtk_im_context_set_client_window(gtk_context_, event->key.window);
171 gdk_last_set_client_window_ = event->key.window; 89 gdk_last_set_client_window_ = event->key.window;
172 } 90 }
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 // Remember the caret bounds so that we can set the cursor location later. 138 // Remember the caret bounds so that we can set the cursor location later.
221 // gtk_im_context_set_cursor_location() takes the location relative to the 139 // gtk_im_context_set_cursor_location() takes the location relative to the
222 // client window, which is unknown at this point. So we'll call 140 // client window, which is unknown at this point. So we'll call
223 // gtk_im_context_set_cursor_location() later in ProcessKeyEvent() where 141 // gtk_im_context_set_cursor_location() later in ProcessKeyEvent() where
224 // (and only where) we know the client window. 142 // (and only where) we know the client window.
225 last_caret_bounds_ = caret_bounds; 143 last_caret_bounds_ = caret_bounds;
226 } 144 }
227 145
228 // private: 146 // private:
229 147
148 void X11InputMethodContextImplGtk2::ResetXModifierKeycodesCache() {
149 modifier_keycodes_.clear();
150 meta_keycodes_.clear();
151 super_keycodes_.clear();
152 hyper_keycodes_.clear();
153
154 Display* display = gfx::GetXDisplay();
155 const XModifierKeymap* modmap = XGetModifierMapping(display);
156 int min_keycode = 0;
157 int max_keycode = 0;
158 int keysyms_per_keycode = 1;
159 XDisplayKeycodes(display, &min_keycode, &max_keycode);
160 const KeySym* keysyms = XGetKeyboardMapping(
161 display, min_keycode, max_keycode - min_keycode + 1,
162 &keysyms_per_keycode);
163 for (int i = 0; i < 8 * modmap->max_keypermod; ++i) {
164 const int keycode = modmap->modifiermap[i];
165 if (!keycode)
166 continue;
167 modifier_keycodes_.insert(keycode);
168
169 if (!keysyms)
170 continue;
171 for (int j = 0; j < keysyms_per_keycode; ++j) {
172 switch (keysyms[(keycode - min_keycode) * keysyms_per_keycode + j]) {
173 case XK_Meta_L:
174 case XK_Meta_R:
175 meta_keycodes_.push_back(keycode);
176 break;
177 case XK_Super_L:
178 case XK_Super_R:
179 super_keycodes_.push_back(keycode);
180 break;
181 case XK_Hyper_L:
182 case XK_Hyper_R:
183 hyper_keycodes_.push_back(keycode);
184 break;
185 }
186 }
187 }
188 XFree(const_cast<KeySym*>(keysyms));
189 XFreeModifiermap(const_cast<XModifierKeymap*>(modmap));
190 }
191
192 GdkEvent* X11InputMethodContextImplGtk2::GdkEventFromNativeEvent(
193 const base::NativeEvent& native_event) {
194 const XKeyEvent& xkey = native_event->xkey;
195 DCHECK(xkey.type == KeyPress || xkey.type == KeyRelease);
196
197 // Get a GdkDisplay.
198 GdkDisplay* display = gdk_x11_lookup_xdisplay(xkey.display);
199 if (!display) {
200 // Fall back to the default display.
201 display = gdk_display_get_default();
202 }
203 if (!display) {
204 LOG(ERROR) << "Cannot get a GdkDisplay for a key event.";
205 return NULL;
206 }
207 // Get a keysym and group.
208 KeySym keysym = NoSymbol;
209 guint8 keyboard_group = 0;
210 XLookupString(&native_event->xkey, NULL, 0, &keysym, NULL);
211 GdkKeymap* keymap = gdk_keymap_get_for_display(display);
212 GdkKeymapKey* keys = NULL;
213 guint* keyvals = NULL;
214 gint n_entries = 0;
215 if (keymap &&
216 gdk_keymap_get_entries_for_keycode(keymap, xkey.keycode,
217 &keys, &keyvals, &n_entries)) {
218 for (gint i = 0; i < n_entries; ++i) {
219 if (keyvals[i] == keysym) {
220 keyboard_group = keys[i].group;
221 break;
222 }
223 }
224 }
225 g_free(keys);
226 keys = NULL;
227 g_free(keyvals);
228 keyvals = NULL;
229 // Get a GdkWindow.
230 GdkWindow* window = gdk_x11_window_lookup_for_display(display, xkey.window);
231 if (window)
232 g_object_ref(window);
233 else
234 window = gdk_x11_window_foreign_new_for_display(display, xkey.window);
235 if (!window) {
236 LOG(ERROR) << "Cannot get a GdkWindow for a key event.";
237 return NULL;
238 }
239
240 // Create a GdkEvent.
241 GdkEventType event_type = xkey.type == KeyPress ?
242 GDK_KEY_PRESS : GDK_KEY_RELEASE;
243 GdkEvent* event = gdk_event_new(event_type);
244 event->key.type = event_type;
245 event->key.window = window;
246 // GdkEventKey and XKeyEvent share the same definition for time and state.
247 event->key.send_event = xkey.send_event;
248 event->key.time = xkey.time;
249 event->key.state = xkey.state;
250 event->key.keyval = keysym;
251 event->key.length = 0;
252 event->key.string = NULL;
253 event->key.hardware_keycode = xkey.keycode;
254 event->key.group = keyboard_group;
255 event->key.is_modifier = IsKeycodeModifierKey(xkey.keycode);
256
257 char keybits[32] = {0};
258 XQueryKeymap(xkey.display, keybits);
259 if (IsAnyOfKeycodesPressed(meta_keycodes_, keybits, sizeof keybits * 8))
260 event->key.state |= GDK_META_MASK;
261 if (IsAnyOfKeycodesPressed(super_keycodes_, keybits, sizeof keybits * 8))
262 event->key.state |= GDK_SUPER_MASK;
263 if (IsAnyOfKeycodesPressed(hyper_keycodes_, keybits, sizeof keybits * 8))
264 event->key.state |= GDK_HYPER_MASK;
265
266 return event;
267 }
268
230 bool X11InputMethodContextImplGtk2::IsKeycodeModifierKey( 269 bool X11InputMethodContextImplGtk2::IsKeycodeModifierKey(
231 unsigned int keycode) const { 270 unsigned int keycode) const {
232 return modifier_keycodes_.find(keycode) != modifier_keycodes_.end(); 271 return modifier_keycodes_.find(keycode) != modifier_keycodes_.end();
233 } 272 }
234 273
274 bool X11InputMethodContextImplGtk2::IsAnyOfKeycodesPressed(
275 const std::vector<int>& keycodes,
276 const char* keybits,
277 int num_keys) const {
278 for (size_t i = 0; i < keycodes.size(); ++i) {
279 const int keycode = keycodes[i];
280 if (keycode < 0 || num_keys <= keycode)
281 continue;
282 if (keybits[keycode / 8] & 1 << (keycode % 8))
283 return true;
284 }
285 return false;
286 }
287
235 // GtkIMContext event handlers. 288 // GtkIMContext event handlers.
236 289
237 void X11InputMethodContextImplGtk2::OnCommit(GtkIMContext* context, 290 void X11InputMethodContextImplGtk2::OnCommit(GtkIMContext* context,
238 gchar* text) { 291 gchar* text) {
239 if (context != gtk_context_) 292 if (context != gtk_context_)
240 return; 293 return;
241 294
242 const base::string16& text_in_utf16 = base::UTF8ToUTF16(text); 295 const base::string16& text_in_utf16 = base::UTF8ToUTF16(text);
243 // If an underlying IME is emitting the "commit" signal to insert a character 296 // If an underlying IME is emitting the "commit" signal to insert a character
244 // for a direct input key event, ignores the insertion of the character at 297 // for a direct input key event, ignores the insertion of the character at
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 text.length() == 1 && 360 text.length() == 1 &&
308 text[0] == gdk_keyval_to_unicode(gdk_event_key_keyval_)) { 361 text[0] == gdk_keyval_to_unicode(gdk_event_key_keyval_)) {
309 is_signal_caught_ = true; 362 is_signal_caught_ = true;
310 return true; 363 return true;
311 } else { 364 } else {
312 return false; 365 return false;
313 } 366 }
314 } 367 }
315 368
316 } // namespace libgtk2ui 369 } // namespace libgtk2ui
OLDNEW
« no previous file with comments | « chrome/browser/ui/libgtk2ui/x11_input_method_context_impl_gtk2.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698