11e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
21e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
31e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// found in the LICENSE file.
41e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
51e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#ifndef CHROME_BROWSER_UI_LIBGTK2UI_X11_INPUT_METHOD_CONTEXT_IMPL_GTK2_H_
61e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#define CHROME_BROWSER_UI_LIBGTK2UI_X11_INPUT_METHOD_CONTEXT_IMPL_GTK2_H_
71e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <vector>
9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/containers/hash_tables.h"
11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/event_types.h"
121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/gtest_prod_util.h"
131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/strings/string16.h"
141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ui/base/glib/glib_integers.h"
151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ui/base/glib/glib_signal.h"
161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ui/base/ime/linux/linux_input_method_context.h"
171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ui/gfx/rect.h"
181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef union _GdkEvent GdkEvent;
205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liutypedef struct _GdkDrawable GdkWindow;
211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)typedef struct _GtkIMContext GtkIMContext;
221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)namespace libgtk2ui {
241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// An implementation of LinuxInputMethodContext which is based on X11 event loop
261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// and uses GtkIMContext(gtk-immodule) as a bridge from/to underlying IMEs.
271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)class X11InputMethodContextImplGtk2 : public ui::LinuxInputMethodContext {
281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) public:
291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  explicit X11InputMethodContextImplGtk2(
301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      ui::LinuxInputMethodContextDelegate* delegate);
311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual ~X11InputMethodContextImplGtk2();
321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Overriden from ui::LinuxInputMethodContext
34a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual bool DispatchKeyEvent(const ui::KeyEvent& key_event) OVERRIDE;
351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual void Reset() OVERRIDE;
361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual void OnTextInputTypeChanged(ui::TextInputType text_input_type)
371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      OVERRIDE;
381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual void OnCaretBoundsChanged(const gfx::Rect& caret_bounds) OVERRIDE;
391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) private:
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Resets the cache of X modifier keycodes.
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // TODO(yukishiino): We should call this method whenever X keyboard mapping
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // changes, for example when a user switched to another keyboard layout.
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  void ResetXModifierKeycodesCache();
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Constructs a GdkEventKey from a XKeyEvent and returns it.  Otherwise,
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // returns NULL.  The returned GdkEvent must be freed by gdk_event_free.
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  GdkEvent* GdkEventFromNativeEvent(const base::NativeEvent& native_event);
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Returns true if the hardware |keycode| is assigned to a modifier key.
511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  bool IsKeycodeModifierKey(unsigned int keycode) const;
521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Returns true if one of |keycodes| is pressed.  |keybits| is a bit vector
54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // returned by XQueryKeymap, and |num_keys| is the number of keys in
55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // |keybits|.
56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool IsAnyOfKeycodesPressed(const std::vector<int>& keycodes,
57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                              const char* keybits,
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                              int num_keys) const;
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // GtkIMContext event handlers.  They are shared among |gtk_context_simple_|
611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // and |gtk_multicontext_|.
621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CHROMEG_CALLBACK_1(X11InputMethodContextImplGtk2, void, OnCommit,
631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                     GtkIMContext*, gchar*);
641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CHROMEG_CALLBACK_0(X11InputMethodContextImplGtk2, void, OnPreeditChanged,
651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                     GtkIMContext*);
661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CHROMEG_CALLBACK_0(X11InputMethodContextImplGtk2, void, OnPreeditEnd,
671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                     GtkIMContext*);
681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CHROMEG_CALLBACK_0(X11InputMethodContextImplGtk2, void, OnPreeditStart,
691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                     GtkIMContext*);
701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // A set of callback functions.  Must not be NULL.
721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ui::LinuxInputMethodContextDelegate* delegate_;
731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // IME's input context used for TEXT_INPUT_TYPE_NONE and
751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // TEXT_INPUT_TYPE_PASSWORD.
761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  GtkIMContext* gtk_context_simple_;
771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // IME's input context used for the other text input types.
781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  GtkIMContext* gtk_multicontext_;
791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // An alias to |gtk_context_simple_| or |gtk_multicontext_| depending on the
811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // text input type.  Can be NULL when it's not focused.
821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  GtkIMContext* gtk_context_;
831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Last set client window.
855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  GdkWindow* gdk_last_set_client_window_;
865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Last known caret bounds relative to the screen coordinates.
881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  gfx::Rect last_caret_bounds_;
891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // A set of hardware keycodes of modifier keys.
911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::hash_set<unsigned int> modifier_keycodes_;
921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // A list of keycodes of each modifier key.
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<int> meta_keycodes_;
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<int> super_keycodes_;
96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<int> hyper_keycodes_;
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // The helper class to trap GTK+'s "commit" signal for direct input key
991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // events.
1001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  //
1011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // gtk_im_context_filter_keypress() emits "commit" signal in order to insert
1021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // a character which is not actually processed by a IME.  This behavior seems,
1031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // in Javascript world, that a keydown event with keycode = VKEY_PROCESSKEY
1041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // (= 229) is fired.  So we have to trap such "commit" signal for direct input
1051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // key events.  This class helps to trap such events.
1061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  class GtkCommitSignalTrap {
1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)   public:
1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    GtkCommitSignalTrap();
1091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Enables the trap which monitors a direct input key event of |keyval|.
1111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    void StartTrap(guint keyval);
1121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Disables the trap.
1141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    void StopTrap();
1151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Checks if the committed |text| has come from a direct input key event,
1171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // and returns true in that case.  Once it's trapped, IsSignalCaught()
1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // returns true.
1191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Must be called at most once between StartTrap() and StopTrap().
1201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    bool Trap(const base::string16& text);
1211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Returns true if a direct input key event is detected.
1231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    bool IsSignalCaught() const { return is_signal_caught_; }
1241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)   private:
1261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    bool is_trap_enabled_;
1271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    guint gdk_event_key_keyval_;
1281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    bool is_signal_caught_;
1291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    DISALLOW_COPY_AND_ASSIGN(GtkCommitSignalTrap);
1311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  };
1321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  GtkCommitSignalTrap commit_signal_trap_;
1341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  FRIEND_TEST_ALL_PREFIXES(X11InputMethodContextImplGtk2FriendTest,
1361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                           GtkCommitSignalTrap);
1371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(X11InputMethodContextImplGtk2);
1391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)};
1401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}  // namespace libgtk2ui
1421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#endif  // CHROME_BROWSER_UI_LIBGTK2UI_X11_INPUT_METHOD_CONTEXT_IMPL_GTK2_H_
144