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 3// found in the LICENSE file. 4 5#ifndef CHROME_BROWSER_UI_LIBGTK2UI_X11_INPUT_METHOD_CONTEXT_IMPL_GTK2_H_ 6#define CHROME_BROWSER_UI_LIBGTK2UI_X11_INPUT_METHOD_CONTEXT_IMPL_GTK2_H_ 7 8#include <vector> 9 10#include "base/containers/hash_tables.h" 11#include "base/event_types.h" 12#include "base/gtest_prod_util.h" 13#include "base/strings/string16.h" 14#include "ui/base/glib/glib_integers.h" 15#include "ui/base/glib/glib_signal.h" 16#include "ui/base/ime/linux/linux_input_method_context.h" 17#include "ui/gfx/rect.h" 18 19typedef union _GdkEvent GdkEvent; 20typedef struct _GdkDrawable GdkWindow; 21typedef struct _GtkIMContext GtkIMContext; 22 23namespace libgtk2ui { 24 25// An implementation of LinuxInputMethodContext which is based on X11 event loop 26// and uses GtkIMContext(gtk-immodule) as a bridge from/to underlying IMEs. 27class X11InputMethodContextImplGtk2 : public ui::LinuxInputMethodContext { 28 public: 29 explicit X11InputMethodContextImplGtk2( 30 ui::LinuxInputMethodContextDelegate* delegate); 31 virtual ~X11InputMethodContextImplGtk2(); 32 33 // Overriden from ui::LinuxInputMethodContext 34 virtual bool DispatchKeyEvent(const ui::KeyEvent& key_event) OVERRIDE; 35 virtual void Reset() OVERRIDE; 36 virtual void OnTextInputTypeChanged(ui::TextInputType text_input_type) 37 OVERRIDE; 38 virtual void OnCaretBoundsChanged(const gfx::Rect& caret_bounds) OVERRIDE; 39 40 private: 41 // Resets the cache of X modifier keycodes. 42 // TODO(yukishiino): We should call this method whenever X keyboard mapping 43 // changes, for example when a user switched to another keyboard layout. 44 void ResetXModifierKeycodesCache(); 45 46 // Constructs a GdkEventKey from a XKeyEvent and returns it. Otherwise, 47 // returns NULL. The returned GdkEvent must be freed by gdk_event_free. 48 GdkEvent* GdkEventFromNativeEvent(const base::NativeEvent& native_event); 49 50 // Returns true if the hardware |keycode| is assigned to a modifier key. 51 bool IsKeycodeModifierKey(unsigned int keycode) const; 52 53 // Returns true if one of |keycodes| is pressed. |keybits| is a bit vector 54 // returned by XQueryKeymap, and |num_keys| is the number of keys in 55 // |keybits|. 56 bool IsAnyOfKeycodesPressed(const std::vector<int>& keycodes, 57 const char* keybits, 58 int num_keys) const; 59 60 // GtkIMContext event handlers. They are shared among |gtk_context_simple_| 61 // and |gtk_multicontext_|. 62 CHROMEG_CALLBACK_1(X11InputMethodContextImplGtk2, void, OnCommit, 63 GtkIMContext*, gchar*); 64 CHROMEG_CALLBACK_0(X11InputMethodContextImplGtk2, void, OnPreeditChanged, 65 GtkIMContext*); 66 CHROMEG_CALLBACK_0(X11InputMethodContextImplGtk2, void, OnPreeditEnd, 67 GtkIMContext*); 68 CHROMEG_CALLBACK_0(X11InputMethodContextImplGtk2, void, OnPreeditStart, 69 GtkIMContext*); 70 71 // A set of callback functions. Must not be NULL. 72 ui::LinuxInputMethodContextDelegate* delegate_; 73 74 // IME's input context used for TEXT_INPUT_TYPE_NONE and 75 // TEXT_INPUT_TYPE_PASSWORD. 76 GtkIMContext* gtk_context_simple_; 77 // IME's input context used for the other text input types. 78 GtkIMContext* gtk_multicontext_; 79 80 // An alias to |gtk_context_simple_| or |gtk_multicontext_| depending on the 81 // text input type. Can be NULL when it's not focused. 82 GtkIMContext* gtk_context_; 83 84 // Last set client window. 85 GdkWindow* gdk_last_set_client_window_; 86 87 // Last known caret bounds relative to the screen coordinates. 88 gfx::Rect last_caret_bounds_; 89 90 // A set of hardware keycodes of modifier keys. 91 base::hash_set<unsigned int> modifier_keycodes_; 92 93 // A list of keycodes of each modifier key. 94 std::vector<int> meta_keycodes_; 95 std::vector<int> super_keycodes_; 96 std::vector<int> hyper_keycodes_; 97 98 // The helper class to trap GTK+'s "commit" signal for direct input key 99 // events. 100 // 101 // gtk_im_context_filter_keypress() emits "commit" signal in order to insert 102 // a character which is not actually processed by a IME. This behavior seems, 103 // in Javascript world, that a keydown event with keycode = VKEY_PROCESSKEY 104 // (= 229) is fired. So we have to trap such "commit" signal for direct input 105 // key events. This class helps to trap such events. 106 class GtkCommitSignalTrap { 107 public: 108 GtkCommitSignalTrap(); 109 110 // Enables the trap which monitors a direct input key event of |keyval|. 111 void StartTrap(guint keyval); 112 113 // Disables the trap. 114 void StopTrap(); 115 116 // Checks if the committed |text| has come from a direct input key event, 117 // and returns true in that case. Once it's trapped, IsSignalCaught() 118 // returns true. 119 // Must be called at most once between StartTrap() and StopTrap(). 120 bool Trap(const base::string16& text); 121 122 // Returns true if a direct input key event is detected. 123 bool IsSignalCaught() const { return is_signal_caught_; } 124 125 private: 126 bool is_trap_enabled_; 127 guint gdk_event_key_keyval_; 128 bool is_signal_caught_; 129 130 DISALLOW_COPY_AND_ASSIGN(GtkCommitSignalTrap); 131 }; 132 133 GtkCommitSignalTrap commit_signal_trap_; 134 135 FRIEND_TEST_ALL_PREFIXES(X11InputMethodContextImplGtk2FriendTest, 136 GtkCommitSignalTrap); 137 138 DISALLOW_COPY_AND_ASSIGN(X11InputMethodContextImplGtk2); 139}; 140 141} // namespace libgtk2ui 142 143#endif // CHROME_BROWSER_UI_LIBGTK2UI_X11_INPUT_METHOD_CONTEXT_IMPL_GTK2_H_ 144