2018-11-30 22:52:05 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2010-03-19 07:21:16 +03:00
|
|
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
|
|
*/
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2010-03-19 07:21:16 +03:00
|
|
|
|
2015-07-27 02:23:04 +03:00
|
|
|
#ifndef IMContextWrapper_h_
|
|
|
|
#define IMContextWrapper_h_
|
2010-03-19 07:21:16 +03:00
|
|
|
|
|
|
|
#include <gdk/gdk.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
#include "nsString.h"
|
2014-03-04 17:48:27 +04:00
|
|
|
#include "nsCOMPtr.h"
|
2010-03-19 07:21:16 +03:00
|
|
|
#include "nsTArray.h"
|
2011-11-27 15:51:52 +04:00
|
|
|
#include "nsIWidget.h"
|
2015-06-11 13:50:15 +03:00
|
|
|
#include "mozilla/CheckedInt.h"
|
2013-09-25 15:21:19 +04:00
|
|
|
#include "mozilla/EventForwards.h"
|
2016-03-16 07:47:49 +03:00
|
|
|
#include "mozilla/TextEventDispatcherListener.h"
|
2015-06-11 13:50:15 +03:00
|
|
|
#include "WritingModes.h"
|
2010-03-19 07:21:16 +03:00
|
|
|
|
|
|
|
class nsWindow;
|
|
|
|
|
2015-07-27 02:23:04 +03:00
|
|
|
namespace mozilla {
|
|
|
|
namespace widget {
|
2011-11-27 15:51:52 +04:00
|
|
|
|
Bug 1505147 - nsWindow::OnKeyPressEvent() shouldn't dispatch eKeyDown event when IMContextWrapper::OnKeyEvent() has already dispatched it for the event r=m_kato
Currently, IMContextWrapper::OnKeyEvent() assumes that IME won't synthesize
keyboard event asynchronously again in some cases. For example, one of the
cases is that user inputs text with a dead key sequence. However, IME may
synthesize key event asynchronously only in a few cases even in a dead key
sequence. Unfortunately, for not losing a chance to dispatch eKeyDown/eKeyUp
event, we need to keep dispatching eKeyDown or eKeyUp event when we receive
original event in dead key sequence. However, according to this bug, we need to
stop dispatching eKeyDown and eKeyUp events when we receive unexpected
async synthesized key event.
If IMContextWrapper::OnKeyEvent() needs to return whether it (has already)
dispatched an eKeyDown or eKeyUp and whether it was consumed, then,
nsWindow can stop dispatching redundant eKeyDown and eKeyUp events.
So, this patch makes IMContextWrapper::OnKeyEvent() return
KeyHandlingState enum class instead of just a bool value to notify the caller
of detail of the event status. And also makes each caller of nsWindow not
dispatch eKeyDown nor eKeyUp event when it returns
KeyHandlingState::eNotHandledButDispatched or
KeyHandlingState::eNotHandledButConsumed.
Differential Revision: https://phabricator.services.mozilla.com/D12517
--HG--
extra : moz-landing-system : lando
2018-11-26 06:26:39 +03:00
|
|
|
/**
|
|
|
|
* KeyHandlingState is result of IMContextWrapper::OnKeyEvent().
|
|
|
|
*/
|
|
|
|
enum class KeyHandlingState {
|
|
|
|
// The native key event has not been handled by IMContextWrapper.
|
|
|
|
eNotHandled,
|
|
|
|
// The native key event was handled by IMContextWrapper.
|
|
|
|
eHandled,
|
|
|
|
// The native key event has not been handled by IMContextWrapper,
|
|
|
|
// but eKeyDown or eKeyUp event has been dispatched.
|
|
|
|
eNotHandledButEventDispatched,
|
|
|
|
// The native key event has not been handled by IMContextWrapper,
|
|
|
|
// but eKeyDown or eKeyUp event has been dispatched and consumed.
|
|
|
|
eNotHandledButEventConsumed,
|
|
|
|
};
|
|
|
|
|
2016-03-16 07:47:49 +03:00
|
|
|
class IMContextWrapper final : public TextEventDispatcherListener {
|
|
|
|
public:
|
|
|
|
// TextEventDispatcherListener implementation
|
|
|
|
NS_DECL_ISUPPORTS
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-03-16 07:47:49 +03:00
|
|
|
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
|
|
|
|
const IMENotification& aNotification) override;
|
2017-04-11 15:24:55 +03:00
|
|
|
NS_IMETHOD_(IMENotificationRequests) GetIMENotificationRequests() override;
|
2016-03-16 07:47:49 +03:00
|
|
|
NS_IMETHOD_(void)
|
|
|
|
OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher) override;
|
|
|
|
NS_IMETHOD_(void)
|
|
|
|
WillDispatchKeyboardEvent(TextEventDispatcher* aTextEventDispatcher,
|
|
|
|
WidgetKeyboardEvent& aKeyboardEvent,
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t aIndexOfKeypress, void* aData) override;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
|
|
public:
|
2010-03-19 07:21:16 +03:00
|
|
|
// aOwnerWindow is a pointer of the owner window. When aOwnerWindow is
|
|
|
|
// destroyed, the related IME contexts are released (i.e., IME cannot be
|
|
|
|
// used with the instance after that).
|
2015-07-27 02:23:04 +03:00
|
|
|
explicit IMContextWrapper(nsWindow* aOwnerWindow);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-07-13 12:12:53 +03:00
|
|
|
// Called when the process is being shut down.
|
|
|
|
static void Shutdown();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-01-14 16:40:08 +03:00
|
|
|
// "Enabled" means the users can use all IMEs.
|
|
|
|
// I.e., the focus is in the normal editors.
|
2014-11-10 12:07:44 +03:00
|
|
|
bool IsEnabled() const;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
// OnFocusWindow is a notification that aWindow is going to be focused.
|
|
|
|
void OnFocusWindow(nsWindow* aWindow);
|
|
|
|
// OnBlurWindow is a notification that aWindow is going to be unfocused.
|
|
|
|
void OnBlurWindow(nsWindow* aWindow);
|
|
|
|
// OnDestroyWindow is a notification that aWindow is going to be destroyed.
|
|
|
|
void OnDestroyWindow(nsWindow* aWindow);
|
|
|
|
// OnFocusChangeInGecko is a notification that an editor gets focus.
|
2011-09-29 10:19:26 +04:00
|
|
|
void OnFocusChangeInGecko(bool aFocus);
|
2016-03-16 07:47:49 +03:00
|
|
|
// OnSelectionChange is a notification that selection (caret) is changed
|
2011-01-14 16:40:08 +03:00
|
|
|
// in the focused editor.
|
2016-03-16 07:47:49 +03:00
|
|
|
void OnSelectionChange(nsWindow* aCaller,
|
2015-06-11 13:50:15 +03:00
|
|
|
const IMENotification& aIMENotification);
|
2015-06-11 13:50:15 +03:00
|
|
|
// OnThemeChanged is called when desktop theme is changed.
|
2015-07-27 02:23:04 +03:00
|
|
|
static void OnThemeChanged();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
|
|
/**
|
2018-02-22 14:56:08 +03:00
|
|
|
* OnKeyEvent() is called when aWindow gets a native key press event or a
|
|
|
|
* native key release event. If this returns true, the key event was
|
|
|
|
* filtered by IME. Otherwise, this returns false.
|
|
|
|
* NOTE: When the native key press event starts composition, this returns
|
|
|
|
* true but dispatches an eKeyDown event or eKeyUp event before
|
|
|
|
* dispatching composition events or content command event.
|
2018-11-30 13:46:48 +03:00
|
|
|
*
|
2018-02-22 14:56:08 +03:00
|
|
|
* @param aWindow A window on which user operate the
|
2018-11-30 13:46:48 +03:00
|
|
|
* key.
|
2018-02-22 14:56:08 +03:00
|
|
|
* @param aEvent A native key press or release
|
2018-11-30 13:46:48 +03:00
|
|
|
* event.
|
2018-02-22 14:56:08 +03:00
|
|
|
* @param aKeyboardEventWasDispatched true if eKeyDown or eKeyUp event
|
|
|
|
* for aEvent has already been
|
|
|
|
* dispatched. In this case,
|
|
|
|
* this class doesn't dispatch
|
|
|
|
* keyboard event anymore.
|
2018-11-30 13:46:48 +03:00
|
|
|
*/
|
Bug 1505147 - nsWindow::OnKeyPressEvent() shouldn't dispatch eKeyDown event when IMContextWrapper::OnKeyEvent() has already dispatched it for the event r=m_kato
Currently, IMContextWrapper::OnKeyEvent() assumes that IME won't synthesize
keyboard event asynchronously again in some cases. For example, one of the
cases is that user inputs text with a dead key sequence. However, IME may
synthesize key event asynchronously only in a few cases even in a dead key
sequence. Unfortunately, for not losing a chance to dispatch eKeyDown/eKeyUp
event, we need to keep dispatching eKeyDown or eKeyUp event when we receive
original event in dead key sequence. However, according to this bug, we need to
stop dispatching eKeyDown and eKeyUp events when we receive unexpected
async synthesized key event.
If IMContextWrapper::OnKeyEvent() needs to return whether it (has already)
dispatched an eKeyDown or eKeyUp and whether it was consumed, then,
nsWindow can stop dispatching redundant eKeyDown and eKeyUp events.
So, this patch makes IMContextWrapper::OnKeyEvent() return
KeyHandlingState enum class instead of just a bool value to notify the caller
of detail of the event status. And also makes each caller of nsWindow not
dispatch eKeyDown nor eKeyUp event when it returns
KeyHandlingState::eNotHandledButDispatched or
KeyHandlingState::eNotHandledButConsumed.
Differential Revision: https://phabricator.services.mozilla.com/D12517
--HG--
extra : moz-landing-system : lando
2018-11-26 06:26:39 +03:00
|
|
|
KeyHandlingState OnKeyEvent(nsWindow* aWindow, GdkEventKey* aEvent,
|
|
|
|
bool aKeyboardEventWasDispatched = false);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
// IME related nsIWidget methods.
|
2014-09-26 04:05:13 +04:00
|
|
|
nsresult EndIMEComposition(nsWindow* aCaller);
|
2011-11-27 15:51:52 +04:00
|
|
|
void SetInputContext(nsWindow* aCaller, const InputContext* aContext,
|
|
|
|
const InputContextAction* aAction);
|
|
|
|
InputContext GetInputContext();
|
2014-01-16 14:04:48 +04:00
|
|
|
void OnUpdateComposition();
|
2015-06-11 13:50:15 +03:00
|
|
|
void OnLayoutChange();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-03-16 07:47:49 +03:00
|
|
|
TextEventDispatcher* GetTextEventDispatcher();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-03-16 07:47:49 +03:00
|
|
|
// TODO: Typically, new IM comes every several years. And now, our code
|
|
|
|
// becomes really IM behavior dependent. So, perhaps, we need prefs
|
Bug 1443421 - part 1: Make IMContextWrapper not dispatch eKeyDown and eKeyUp event if the native key event is being handled by other IME process r=m_kato
ibus and fcitx have asynchronous key event handling mode and it's enabled in
default settings. That is, when they receive a key event from application via
a call of gtk_im_context_filter_keypress(), they may post the key event
information to other IME process, then does nothing but store the copy of the
event with gdk_event_copy() and returns true for the result of
gtk_im_context_filter_keypress(). When the other IME process handles the
event, returns the result to them in our process. Then, they send the stored
key event to us again. Finally, they actually handles the event in our process
actually.
Therefore, we may receive every key event twice. So, this causes dispatching
eKeyDown event and eKeyUp event twice. Preceding key event is always marked
as "processed by IME" since gtk_im_context_filter_keypress() returns true
temporarily and following key event is dispatched as expected. So, we need
to ignore the first event only when gtk_im_context_filter_keypress() returns
true but the event is posted to different process.
Unfortunately, we cannot know if the key event is actually posted to different
process directly. However, we can know if active IM is ibus, fcitx or another
one and if ibus or fcitx is in asynchronous key handling mode.
The former information is provided by gtk_im_multicontext_get_context_id().
It returns a string which is set to the IM multicontext instance by creator.
We'll get "ibus" if IM is ibus, get "fcitx" if IM is fcitx.
The latter information is not provided. However, they consider the mode from
env value. ibus checks IBUS_ENABLE_SYNC_MODE. fcitx checks both
IBUS_ENABLE_SYNC_MODE and FCITX_ENABLE_SYNC_MODE.
Additionally, we can know if received key event has already been posted to
other IME process. They use undefined bit of GdkEventKey::state to store
if the key event has already been posted (1 << 25, they called "ignored" flag).
Although their approach is really hacky but we can refer the information at
least for now.
Finally, when we guess a key event is posted to other IME process, let's
IMContextWrapper::OnKeyEvent() not dispatch eKeyDown nor eKeyUp event.
Note that if it's handled synchronously as unexpected, it may causes
dispatching one or more composition events and/or delete content event.
So, in such case, we dispatch a keyboard event for processing key event
anyway. There is only once case we'll fail to dispatch keyboard event.
If we receive signals to dispatch composition events or delete content
command event when IM receives the result from other IME process but
it doesn't send the key event to us. This will be fixed by the following
patch.
MozReview-Commit-ID: 94PrlnmQ3uJ
--HG--
extra : rebase_source : fc31b0293ff0f0688dd39b0094fdf8f98b6c64d3
2018-03-08 18:46:52 +03:00
|
|
|
// to control related flags for IM developers.
|
2016-03-16 07:47:49 +03:00
|
|
|
enum class IMContextID : uint8_t {
|
2018-11-30 13:46:48 +03:00
|
|
|
eFcitx,
|
|
|
|
eIBus,
|
|
|
|
eIIIMF,
|
|
|
|
eScim,
|
|
|
|
eUim,
|
Bug 1443421 - part 1: Make IMContextWrapper not dispatch eKeyDown and eKeyUp event if the native key event is being handled by other IME process r=m_kato
ibus and fcitx have asynchronous key event handling mode and it's enabled in
default settings. That is, when they receive a key event from application via
a call of gtk_im_context_filter_keypress(), they may post the key event
information to other IME process, then does nothing but store the copy of the
event with gdk_event_copy() and returns true for the result of
gtk_im_context_filter_keypress(). When the other IME process handles the
event, returns the result to them in our process. Then, they send the stored
key event to us again. Finally, they actually handles the event in our process
actually.
Therefore, we may receive every key event twice. So, this causes dispatching
eKeyDown event and eKeyUp event twice. Preceding key event is always marked
as "processed by IME" since gtk_im_context_filter_keypress() returns true
temporarily and following key event is dispatched as expected. So, we need
to ignore the first event only when gtk_im_context_filter_keypress() returns
true but the event is posted to different process.
Unfortunately, we cannot know if the key event is actually posted to different
process directly. However, we can know if active IM is ibus, fcitx or another
one and if ibus or fcitx is in asynchronous key handling mode.
The former information is provided by gtk_im_multicontext_get_context_id().
It returns a string which is set to the IM multicontext instance by creator.
We'll get "ibus" if IM is ibus, get "fcitx" if IM is fcitx.
The latter information is not provided. However, they consider the mode from
env value. ibus checks IBUS_ENABLE_SYNC_MODE. fcitx checks both
IBUS_ENABLE_SYNC_MODE and FCITX_ENABLE_SYNC_MODE.
Additionally, we can know if received key event has already been posted to
other IME process. They use undefined bit of GdkEventKey::state to store
if the key event has already been posted (1 << 25, they called "ignored" flag).
Although their approach is really hacky but we can refer the information at
least for now.
Finally, when we guess a key event is posted to other IME process, let's
IMContextWrapper::OnKeyEvent() not dispatch eKeyDown nor eKeyUp event.
Note that if it's handled synchronously as unexpected, it may causes
dispatching one or more composition events and/or delete content event.
So, in such case, we dispatch a keyboard event for processing key event
anyway. There is only once case we'll fail to dispatch keyboard event.
If we receive signals to dispatch composition events or delete content
command event when IM receives the result from other IME process but
it doesn't send the key event to us. This will be fixed by the following
patch.
MozReview-Commit-ID: 94PrlnmQ3uJ
--HG--
extra : rebase_source : fc31b0293ff0f0688dd39b0094fdf8f98b6c64d3
2018-03-08 18:46:52 +03:00
|
|
|
eUnknown,
|
2016-03-16 07:47:49 +03:00
|
|
|
};
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-03-16 07:47:49 +03:00
|
|
|
static const char* GetIMContextIDName(IMContextID aIMContextID) {
|
2010-03-19 07:21:16 +03:00
|
|
|
switch (aIMContextID) {
|
Bug 1443421 - part 1: Make IMContextWrapper not dispatch eKeyDown and eKeyUp event if the native key event is being handled by other IME process r=m_kato
ibus and fcitx have asynchronous key event handling mode and it's enabled in
default settings. That is, when they receive a key event from application via
a call of gtk_im_context_filter_keypress(), they may post the key event
information to other IME process, then does nothing but store the copy of the
event with gdk_event_copy() and returns true for the result of
gtk_im_context_filter_keypress(). When the other IME process handles the
event, returns the result to them in our process. Then, they send the stored
key event to us again. Finally, they actually handles the event in our process
actually.
Therefore, we may receive every key event twice. So, this causes dispatching
eKeyDown event and eKeyUp event twice. Preceding key event is always marked
as "processed by IME" since gtk_im_context_filter_keypress() returns true
temporarily and following key event is dispatched as expected. So, we need
to ignore the first event only when gtk_im_context_filter_keypress() returns
true but the event is posted to different process.
Unfortunately, we cannot know if the key event is actually posted to different
process directly. However, we can know if active IM is ibus, fcitx or another
one and if ibus or fcitx is in asynchronous key handling mode.
The former information is provided by gtk_im_multicontext_get_context_id().
It returns a string which is set to the IM multicontext instance by creator.
We'll get "ibus" if IM is ibus, get "fcitx" if IM is fcitx.
The latter information is not provided. However, they consider the mode from
env value. ibus checks IBUS_ENABLE_SYNC_MODE. fcitx checks both
IBUS_ENABLE_SYNC_MODE and FCITX_ENABLE_SYNC_MODE.
Additionally, we can know if received key event has already been posted to
other IME process. They use undefined bit of GdkEventKey::state to store
if the key event has already been posted (1 << 25, they called "ignored" flag).
Although their approach is really hacky but we can refer the information at
least for now.
Finally, when we guess a key event is posted to other IME process, let's
IMContextWrapper::OnKeyEvent() not dispatch eKeyDown nor eKeyUp event.
Note that if it's handled synchronously as unexpected, it may causes
dispatching one or more composition events and/or delete content event.
So, in such case, we dispatch a keyboard event for processing key event
anyway. There is only once case we'll fail to dispatch keyboard event.
If we receive signals to dispatch composition events or delete content
command event when IM receives the result from other IME process but
it doesn't send the key event to us. This will be fixed by the following
patch.
MozReview-Commit-ID: 94PrlnmQ3uJ
--HG--
extra : rebase_source : fc31b0293ff0f0688dd39b0094fdf8f98b6c64d3
2018-03-08 18:46:52 +03:00
|
|
|
case IMContextID::eFcitx:
|
|
|
|
return "eFcitx";
|
|
|
|
case IMContextID::eIBus:
|
|
|
|
return "eIBus";
|
|
|
|
case IMContextID::eIIIMF:
|
|
|
|
return "eIIIMF";
|
|
|
|
case IMContextID::eScim:
|
|
|
|
return "eScim";
|
|
|
|
case IMContextID::eUim:
|
|
|
|
return "eUim";
|
2018-11-30 13:46:48 +03:00
|
|
|
default:
|
2010-03-19 07:21:16 +03:00
|
|
|
return "eUnknown";
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2010-03-19 07:21:16 +03:00
|
|
|
* GetIMName() returns IM name associated with mContext. If the context is
|
|
|
|
* xim, this look for actual engine from XMODIFIERS environment variable.
|
2018-11-30 13:46:48 +03:00
|
|
|
*/
|
2010-03-19 07:21:16 +03:00
|
|
|
nsDependentCSubstring GetIMName() const;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-12-28 10:02:05 +03:00
|
|
|
/**
|
|
|
|
* GetWaitingSynthesizedKeyPressHardwareKeyCode() returns hardware_keycode
|
|
|
|
* value of last handled GDK_KEY_PRESS event which is probable handled by
|
|
|
|
* IME asynchronously and we have not received synthesized GDK_KEY_PRESS
|
|
|
|
* event yet.
|
|
|
|
*/
|
|
|
|
static guint16 GetWaitingSynthesizedKeyPressHardwareKeyCode() {
|
|
|
|
return sWaitingSynthesizedKeyPressHardwareKeyCode;
|
|
|
|
}
|
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
protected:
|
|
|
|
~IMContextWrapper();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
// Owner of an instance of this class. This should be top level window.
|
|
|
|
// The owner window must release the contexts when it's destroyed because
|
|
|
|
// the IME contexts need the native window. If OnDestroyWindow() is called
|
|
|
|
// with the owner window, it'll release IME contexts. Otherwise, it'll
|
2014-09-26 04:05:13 +04:00
|
|
|
// just clean up any existing composition if it's related to the destroying
|
|
|
|
// child window.
|
2010-03-19 07:21:16 +03:00
|
|
|
nsWindow* mOwnerWindow;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-26 04:05:13 +04:00
|
|
|
// A last focused window in this class's context.
|
|
|
|
nsWindow* mLastFocusedWindow;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-26 04:05:13 +04:00
|
|
|
// Actual context. This is used for handling the user's input.
|
2014-11-10 12:07:44 +03:00
|
|
|
GtkIMContext* mContext;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-26 04:05:13 +04:00
|
|
|
// mSimpleContext is used for the password field and
|
|
|
|
// the |ime-mode: disabled;| editors if sUseSimpleContext is true.
|
|
|
|
// These editors disable IME. But dead keys should work. Fortunately,
|
2015-06-11 13:50:15 +03:00
|
|
|
// the simple IM context of GTK2 support only them.
|
|
|
|
GtkIMContext* mSimpleContext;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-06-11 13:50:15 +03:00
|
|
|
// mDummyContext is a dummy context and will be used in Focus()
|
2018-07-13 12:12:53 +03:00
|
|
|
// when the state of mEnabled means disabled. This context's IME state is
|
|
|
|
// always "closed", so it closes IME forcedly.
|
2014-11-10 12:07:44 +03:00
|
|
|
GtkIMContext* mDummyContext;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-07-13 12:12:53 +03:00
|
|
|
// mComposingContext is not nullptr while one of mContext, mSimpleContext
|
|
|
|
// and mDummyContext has composition.
|
|
|
|
// XXX: We don't assume that two or more context have composition same time.
|
|
|
|
GtkIMContext* mComposingContext;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-07-13 12:12:53 +03:00
|
|
|
// IME enabled state and other things defined in InputContext.
|
2010-03-19 07:21:16 +03:00
|
|
|
// Use following helper methods if you don't need the detail of the status.
|
2011-11-27 15:51:52 +04:00
|
|
|
InputContext mInputContext;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
// mCompositionStart is the start offset of the composition string in the
|
|
|
|
// current content. When <textarea> or <input> have focus, it means offset
|
|
|
|
// from the first character of them. When a HTML editor has focus, it
|
|
|
|
// means offset from the first character of the root element of the editor.
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t mCompositionStart;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-09-22 13:17:40 +04:00
|
|
|
// mDispatchedCompositionString is the latest composition string which
|
|
|
|
// was dispatched by compositionupdate event.
|
|
|
|
nsString mDispatchedCompositionString;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-07-13 12:12:53 +03:00
|
|
|
// mSelectedStringRemovedByComposition is the selected string which was
|
|
|
|
// removed by first compositionchange event.
|
2017-06-27 12:46:08 +03:00
|
|
|
nsString mSelectedStringRemovedByComposition;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
// OnKeyEvent() temporarily sets mProcessingKeyEvent to the given native
|
2017-06-27 12:46:08 +03:00
|
|
|
// event.
|
2010-03-19 07:21:16 +03:00
|
|
|
GdkEventKey* mProcessingKeyEvent;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
|
|
/**
|
Bug 1443421 - part 2: IMContextWrapper should dispatch eKeyDown or eKeyUp event as "processed by IME" even when IM sent some signals without sending key event again r=m_kato
ibus and fcitx usually post key event to other IME process, then, if it causes
some signals to updating composition string, they may not send the posted
key event to us again. Then, IMContextWrapper dispatches neither eKeyDown nor
eKeyUp event since mProcessingKeyEvent becomes non-nullptr only while
OnKeyEvent() is called. So, IMContextWrapper need to store key event if
OnKeyEvent() assumes that given key event is posted to different process.
Then, if IMContextWrapper receives some signals, it should dispatch eKeyDown
and eKeyUp event with stored key event.
Note that we cannot compare the pointer of first event and following event
directly even though usually both events are same address as far as I checked
because according to the source code of ibus, fcitx and GDK, they use
gdk_event_copy() to keep storing original event. According to the document of
the API, it might just increment refcount. However, the actual implementation
of the API always creates another instance and return it. So, it might be
used same address by arena allocation or something accidentally. Anyway,
we shouldn't compare them. Instead, we need to compare each information of
two key events. Unfortunately, we also cannot compare them simply. Both
ibus and fcitx set unused bits of GdkEventKey::state to true when they send
back the event to us. Therefore, we should compare some of or all of the
members by ourselves. I think that matching time must be enough in most
cases since its value of native key events are properly set. However, for
safer code, this patch also checks type, keyval and part of state.
MozReview-Commit-ID: FZSwN61v0Sd
--HG--
extra : rebase_source : e57a654392f476f5ec52d82bdd238eed2eb91e83
2018-03-09 06:39:40 +03:00
|
|
|
* GdkEventKeyQueue stores *copy* of GdkEventKey instances. However, this
|
|
|
|
* must be safe to our usecase since it has |time| and the value should not
|
|
|
|
* be same as older event.
|
2018-11-30 13:46:48 +03:00
|
|
|
*/
|
Bug 1443421 - part 2: IMContextWrapper should dispatch eKeyDown or eKeyUp event as "processed by IME" even when IM sent some signals without sending key event again r=m_kato
ibus and fcitx usually post key event to other IME process, then, if it causes
some signals to updating composition string, they may not send the posted
key event to us again. Then, IMContextWrapper dispatches neither eKeyDown nor
eKeyUp event since mProcessingKeyEvent becomes non-nullptr only while
OnKeyEvent() is called. So, IMContextWrapper need to store key event if
OnKeyEvent() assumes that given key event is posted to different process.
Then, if IMContextWrapper receives some signals, it should dispatch eKeyDown
and eKeyUp event with stored key event.
Note that we cannot compare the pointer of first event and following event
directly even though usually both events are same address as far as I checked
because according to the source code of ibus, fcitx and GDK, they use
gdk_event_copy() to keep storing original event. According to the document of
the API, it might just increment refcount. However, the actual implementation
of the API always creates another instance and return it. So, it might be
used same address by arena allocation or something accidentally. Anyway,
we shouldn't compare them. Instead, we need to compare each information of
two key events. Unfortunately, we also cannot compare them simply. Both
ibus and fcitx set unused bits of GdkEventKey::state to true when they send
back the event to us. Therefore, we should compare some of or all of the
members by ourselves. I think that matching time must be enough in most
cases since its value of native key events are properly set. However, for
safer code, this patch also checks type, keyval and part of state.
MozReview-Commit-ID: FZSwN61v0Sd
--HG--
extra : rebase_source : e57a654392f476f5ec52d82bdd238eed2eb91e83
2018-03-09 06:39:40 +03:00
|
|
|
class GdkEventKeyQueue final {
|
2018-11-30 13:46:48 +03:00
|
|
|
public:
|
2018-07-13 12:12:53 +03:00
|
|
|
~GdkEventKeyQueue() { Clear(); }
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-07-13 12:12:53 +03:00
|
|
|
void Clear() {
|
Bug 1443421 - part 2: IMContextWrapper should dispatch eKeyDown or eKeyUp event as "processed by IME" even when IM sent some signals without sending key event again r=m_kato
ibus and fcitx usually post key event to other IME process, then, if it causes
some signals to updating composition string, they may not send the posted
key event to us again. Then, IMContextWrapper dispatches neither eKeyDown nor
eKeyUp event since mProcessingKeyEvent becomes non-nullptr only while
OnKeyEvent() is called. So, IMContextWrapper need to store key event if
OnKeyEvent() assumes that given key event is posted to different process.
Then, if IMContextWrapper receives some signals, it should dispatch eKeyDown
and eKeyUp event with stored key event.
Note that we cannot compare the pointer of first event and following event
directly even though usually both events are same address as far as I checked
because according to the source code of ibus, fcitx and GDK, they use
gdk_event_copy() to keep storing original event. According to the document of
the API, it might just increment refcount. However, the actual implementation
of the API always creates another instance and return it. So, it might be
used same address by arena allocation or something accidentally. Anyway,
we shouldn't compare them. Instead, we need to compare each information of
two key events. Unfortunately, we also cannot compare them simply. Both
ibus and fcitx set unused bits of GdkEventKey::state to true when they send
back the event to us. Therefore, we should compare some of or all of the
members by ourselves. I think that matching time must be enough in most
cases since its value of native key events are properly set. However, for
safer code, this patch also checks type, keyval and part of state.
MozReview-Commit-ID: FZSwN61v0Sd
--HG--
extra : rebase_source : e57a654392f476f5ec52d82bdd238eed2eb91e83
2018-03-09 06:39:40 +03:00
|
|
|
if (!mEvents.IsEmpty()) {
|
|
|
|
RemoveEventsAt(0, mEvents.Length());
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
2010-03-19 07:21:16 +03:00
|
|
|
|
2018-02-22 14:56:08 +03:00
|
|
|
/**
|
|
|
|
* PutEvent() puts new event into the queue.
|
|
|
|
*/
|
Bug 1505147 - nsWindow::OnKeyPressEvent() shouldn't dispatch eKeyDown event when IMContextWrapper::OnKeyEvent() has already dispatched it for the event r=m_kato
Currently, IMContextWrapper::OnKeyEvent() assumes that IME won't synthesize
keyboard event asynchronously again in some cases. For example, one of the
cases is that user inputs text with a dead key sequence. However, IME may
synthesize key event asynchronously only in a few cases even in a dead key
sequence. Unfortunately, for not losing a chance to dispatch eKeyDown/eKeyUp
event, we need to keep dispatching eKeyDown or eKeyUp event when we receive
original event in dead key sequence. However, according to this bug, we need to
stop dispatching eKeyDown and eKeyUp events when we receive unexpected
async synthesized key event.
If IMContextWrapper::OnKeyEvent() needs to return whether it (has already)
dispatched an eKeyDown or eKeyUp and whether it was consumed, then,
nsWindow can stop dispatching redundant eKeyDown and eKeyUp events.
So, this patch makes IMContextWrapper::OnKeyEvent() return
KeyHandlingState enum class instead of just a bool value to notify the caller
of detail of the event status. And also makes each caller of nsWindow not
dispatch eKeyDown nor eKeyUp event when it returns
KeyHandlingState::eNotHandledButDispatched or
KeyHandlingState::eNotHandledButConsumed.
Differential Revision: https://phabricator.services.mozilla.com/D12517
--HG--
extra : moz-landing-system : lando
2018-11-26 06:26:39 +03:00
|
|
|
void PutEvent(const GdkEventKey* aEvent) {
|
2016-03-16 07:47:49 +03:00
|
|
|
GdkEventKey* newEvent = reinterpret_cast<GdkEventKey*>(
|
Bug 1443421 - part 1: Make IMContextWrapper not dispatch eKeyDown and eKeyUp event if the native key event is being handled by other IME process r=m_kato
ibus and fcitx have asynchronous key event handling mode and it's enabled in
default settings. That is, when they receive a key event from application via
a call of gtk_im_context_filter_keypress(), they may post the key event
information to other IME process, then does nothing but store the copy of the
event with gdk_event_copy() and returns true for the result of
gtk_im_context_filter_keypress(). When the other IME process handles the
event, returns the result to them in our process. Then, they send the stored
key event to us again. Finally, they actually handles the event in our process
actually.
Therefore, we may receive every key event twice. So, this causes dispatching
eKeyDown event and eKeyUp event twice. Preceding key event is always marked
as "processed by IME" since gtk_im_context_filter_keypress() returns true
temporarily and following key event is dispatched as expected. So, we need
to ignore the first event only when gtk_im_context_filter_keypress() returns
true but the event is posted to different process.
Unfortunately, we cannot know if the key event is actually posted to different
process directly. However, we can know if active IM is ibus, fcitx or another
one and if ibus or fcitx is in asynchronous key handling mode.
The former information is provided by gtk_im_multicontext_get_context_id().
It returns a string which is set to the IM multicontext instance by creator.
We'll get "ibus" if IM is ibus, get "fcitx" if IM is fcitx.
The latter information is not provided. However, they consider the mode from
env value. ibus checks IBUS_ENABLE_SYNC_MODE. fcitx checks both
IBUS_ENABLE_SYNC_MODE and FCITX_ENABLE_SYNC_MODE.
Additionally, we can know if received key event has already been posted to
other IME process. They use undefined bit of GdkEventKey::state to store
if the key event has already been posted (1 << 25, they called "ignored" flag).
Although their approach is really hacky but we can refer the information at
least for now.
Finally, when we guess a key event is posted to other IME process, let's
IMContextWrapper::OnKeyEvent() not dispatch eKeyDown nor eKeyUp event.
Note that if it's handled synchronously as unexpected, it may causes
dispatching one or more composition events and/or delete content event.
So, in such case, we dispatch a keyboard event for processing key event
anyway. There is only once case we'll fail to dispatch keyboard event.
If we receive signals to dispatch composition events or delete content
command event when IM receives the result from other IME process but
it doesn't send the key event to us. This will be fixed by the following
patch.
MozReview-Commit-ID: 94PrlnmQ3uJ
--HG--
extra : rebase_source : fc31b0293ff0f0688dd39b0094fdf8f98b6c64d3
2018-03-08 18:46:52 +03:00
|
|
|
gdk_event_copy(reinterpret_cast<const GdkEvent*>(aEvent)));
|
|
|
|
newEvent->state &= GDK_MODIFIER_MASK;
|
|
|
|
mEvents.AppendElement(newEvent);
|
|
|
|
}
|
|
|
|
|
2018-06-20 08:55:46 +03:00
|
|
|
/**
|
|
|
|
* RemoveEvent() removes oldest same event and its preceding events
|
|
|
|
* from the queue.
|
|
|
|
*/
|
2010-03-19 07:21:16 +03:00
|
|
|
void RemoveEvent(const GdkEventKey* aEvent) {
|
|
|
|
size_t index = IndexOf(aEvent);
|
2018-12-26 11:17:32 +03:00
|
|
|
if (NS_WARN_IF(index == GdkEventKeyQueue::NoIndex())) {
|
2010-03-19 07:21:16 +03:00
|
|
|
return;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2017-06-27 12:46:08 +03:00
|
|
|
RemoveEventsAt(0, index + 1);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2010-03-19 07:21:16 +03:00
|
|
|
|
Bug 1443421 - part 2: IMContextWrapper should dispatch eKeyDown or eKeyUp event as "processed by IME" even when IM sent some signals without sending key event again r=m_kato
ibus and fcitx usually post key event to other IME process, then, if it causes
some signals to updating composition string, they may not send the posted
key event to us again. Then, IMContextWrapper dispatches neither eKeyDown nor
eKeyUp event since mProcessingKeyEvent becomes non-nullptr only while
OnKeyEvent() is called. So, IMContextWrapper need to store key event if
OnKeyEvent() assumes that given key event is posted to different process.
Then, if IMContextWrapper receives some signals, it should dispatch eKeyDown
and eKeyUp event with stored key event.
Note that we cannot compare the pointer of first event and following event
directly even though usually both events are same address as far as I checked
because according to the source code of ibus, fcitx and GDK, they use
gdk_event_copy() to keep storing original event. According to the document of
the API, it might just increment refcount. However, the actual implementation
of the API always creates another instance and return it. So, it might be
used same address by arena allocation or something accidentally. Anyway,
we shouldn't compare them. Instead, we need to compare each information of
two key events. Unfortunately, we also cannot compare them simply. Both
ibus and fcitx set unused bits of GdkEventKey::state to true when they send
back the event to us. Therefore, we should compare some of or all of the
members by ourselves. I think that matching time must be enough in most
cases since its value of native key events are properly set. However, for
safer code, this patch also checks type, keyval and part of state.
MozReview-Commit-ID: FZSwN61v0Sd
--HG--
extra : rebase_source : e57a654392f476f5ec52d82bdd238eed2eb91e83
2018-03-09 06:39:40 +03:00
|
|
|
/**
|
|
|
|
* FirstEvent() returns oldest event in the queue.
|
|
|
|
*/
|
|
|
|
GdkEventKey* GetFirstEvent() const {
|
|
|
|
if (mEvents.IsEmpty()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return mEvents[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsEmpty() const { return mEvents.IsEmpty(); }
|
|
|
|
|
2018-12-26 11:17:32 +03:00
|
|
|
static size_t NoIndex() { return nsTArray<GdkEventKey*>::NoIndex; }
|
|
|
|
size_t Length() const { return mEvents.Length(); }
|
2015-06-11 13:50:15 +03:00
|
|
|
size_t IndexOf(const GdkEventKey* aEvent) const {
|
|
|
|
static_assert(!(GDK_MODIFIER_MASK & (1 << 24)),
|
|
|
|
"We assumes 25th bit is used by some IM, but used by GDK");
|
|
|
|
static_assert(!(GDK_MODIFIER_MASK & (1 << 25)),
|
|
|
|
"We assumes 26th bit is used by some IM, but used by GDK");
|
|
|
|
for (size_t i = 0; i < mEvents.Length(); i++) {
|
Bug 1443421 - part 2: IMContextWrapper should dispatch eKeyDown or eKeyUp event as "processed by IME" even when IM sent some signals without sending key event again r=m_kato
ibus and fcitx usually post key event to other IME process, then, if it causes
some signals to updating composition string, they may not send the posted
key event to us again. Then, IMContextWrapper dispatches neither eKeyDown nor
eKeyUp event since mProcessingKeyEvent becomes non-nullptr only while
OnKeyEvent() is called. So, IMContextWrapper need to store key event if
OnKeyEvent() assumes that given key event is posted to different process.
Then, if IMContextWrapper receives some signals, it should dispatch eKeyDown
and eKeyUp event with stored key event.
Note that we cannot compare the pointer of first event and following event
directly even though usually both events are same address as far as I checked
because according to the source code of ibus, fcitx and GDK, they use
gdk_event_copy() to keep storing original event. According to the document of
the API, it might just increment refcount. However, the actual implementation
of the API always creates another instance and return it. So, it might be
used same address by arena allocation or something accidentally. Anyway,
we shouldn't compare them. Instead, we need to compare each information of
two key events. Unfortunately, we also cannot compare them simply. Both
ibus and fcitx set unused bits of GdkEventKey::state to true when they send
back the event to us. Therefore, we should compare some of or all of the
members by ourselves. I think that matching time must be enough in most
cases since its value of native key events are properly set. However, for
safer code, this patch also checks type, keyval and part of state.
MozReview-Commit-ID: FZSwN61v0Sd
--HG--
extra : rebase_source : e57a654392f476f5ec52d82bdd238eed2eb91e83
2018-03-09 06:39:40 +03:00
|
|
|
GdkEventKey* event = mEvents[i];
|
2015-06-11 13:50:15 +03:00
|
|
|
// It must be enough to compare only type, time, keyval and
|
Bug 1443421 - part 2: IMContextWrapper should dispatch eKeyDown or eKeyUp event as "processed by IME" even when IM sent some signals without sending key event again r=m_kato
ibus and fcitx usually post key event to other IME process, then, if it causes
some signals to updating composition string, they may not send the posted
key event to us again. Then, IMContextWrapper dispatches neither eKeyDown nor
eKeyUp event since mProcessingKeyEvent becomes non-nullptr only while
OnKeyEvent() is called. So, IMContextWrapper need to store key event if
OnKeyEvent() assumes that given key event is posted to different process.
Then, if IMContextWrapper receives some signals, it should dispatch eKeyDown
and eKeyUp event with stored key event.
Note that we cannot compare the pointer of first event and following event
directly even though usually both events are same address as far as I checked
because according to the source code of ibus, fcitx and GDK, they use
gdk_event_copy() to keep storing original event. According to the document of
the API, it might just increment refcount. However, the actual implementation
of the API always creates another instance and return it. So, it might be
used same address by arena allocation or something accidentally. Anyway,
we shouldn't compare them. Instead, we need to compare each information of
two key events. Unfortunately, we also cannot compare them simply. Both
ibus and fcitx set unused bits of GdkEventKey::state to true when they send
back the event to us. Therefore, we should compare some of or all of the
members by ourselves. I think that matching time must be enough in most
cases since its value of native key events are properly set. However, for
safer code, this patch also checks type, keyval and part of state.
MozReview-Commit-ID: FZSwN61v0Sd
--HG--
extra : rebase_source : e57a654392f476f5ec52d82bdd238eed2eb91e83
2018-03-09 06:39:40 +03:00
|
|
|
// part of state. Note that we cannot compaire two events
|
2015-06-11 13:50:15 +03:00
|
|
|
// simply since IME may have changed unused bits of state.
|
Bug 1443421 - part 2: IMContextWrapper should dispatch eKeyDown or eKeyUp event as "processed by IME" even when IM sent some signals without sending key event again r=m_kato
ibus and fcitx usually post key event to other IME process, then, if it causes
some signals to updating composition string, they may not send the posted
key event to us again. Then, IMContextWrapper dispatches neither eKeyDown nor
eKeyUp event since mProcessingKeyEvent becomes non-nullptr only while
OnKeyEvent() is called. So, IMContextWrapper need to store key event if
OnKeyEvent() assumes that given key event is posted to different process.
Then, if IMContextWrapper receives some signals, it should dispatch eKeyDown
and eKeyUp event with stored key event.
Note that we cannot compare the pointer of first event and following event
directly even though usually both events are same address as far as I checked
because according to the source code of ibus, fcitx and GDK, they use
gdk_event_copy() to keep storing original event. According to the document of
the API, it might just increment refcount. However, the actual implementation
of the API always creates another instance and return it. So, it might be
used same address by arena allocation or something accidentally. Anyway,
we shouldn't compare them. Instead, we need to compare each information of
two key events. Unfortunately, we also cannot compare them simply. Both
ibus and fcitx set unused bits of GdkEventKey::state to true when they send
back the event to us. Therefore, we should compare some of or all of the
members by ourselves. I think that matching time must be enough in most
cases since its value of native key events are properly set. However, for
safer code, this patch also checks type, keyval and part of state.
MozReview-Commit-ID: FZSwN61v0Sd
--HG--
extra : rebase_source : e57a654392f476f5ec52d82bdd238eed2eb91e83
2018-03-09 06:39:40 +03:00
|
|
|
if (event->time == aEvent->time) {
|
|
|
|
if (NS_WARN_IF(event->type != aEvent->type) ||
|
|
|
|
NS_WARN_IF(event->keyval != aEvent->keyval) ||
|
2015-06-11 13:50:15 +03:00
|
|
|
NS_WARN_IF(event->state != (aEvent->state & GDK_MODIFIER_MASK))) {
|
Bug 1443421 - part 2: IMContextWrapper should dispatch eKeyDown or eKeyUp event as "processed by IME" even when IM sent some signals without sending key event again r=m_kato
ibus and fcitx usually post key event to other IME process, then, if it causes
some signals to updating composition string, they may not send the posted
key event to us again. Then, IMContextWrapper dispatches neither eKeyDown nor
eKeyUp event since mProcessingKeyEvent becomes non-nullptr only while
OnKeyEvent() is called. So, IMContextWrapper need to store key event if
OnKeyEvent() assumes that given key event is posted to different process.
Then, if IMContextWrapper receives some signals, it should dispatch eKeyDown
and eKeyUp event with stored key event.
Note that we cannot compare the pointer of first event and following event
directly even though usually both events are same address as far as I checked
because according to the source code of ibus, fcitx and GDK, they use
gdk_event_copy() to keep storing original event. According to the document of
the API, it might just increment refcount. However, the actual implementation
of the API always creates another instance and return it. So, it might be
used same address by arena allocation or something accidentally. Anyway,
we shouldn't compare them. Instead, we need to compare each information of
two key events. Unfortunately, we also cannot compare them simply. Both
ibus and fcitx set unused bits of GdkEventKey::state to true when they send
back the event to us. Therefore, we should compare some of or all of the
members by ourselves. I think that matching time must be enough in most
cases since its value of native key events are properly set. However, for
safer code, this patch also checks type, keyval and part of state.
MozReview-Commit-ID: FZSwN61v0Sd
--HG--
extra : rebase_source : e57a654392f476f5ec52d82bdd238eed2eb91e83
2018-03-09 06:39:40 +03:00
|
|
|
continue;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2015-06-11 13:50:15 +03:00
|
|
|
}
|
|
|
|
return i;
|
2012-03-09 08:27:51 +04:00
|
|
|
}
|
2018-12-26 11:17:32 +03:00
|
|
|
return GdkEventKeyQueue::NoIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsTArray<GdkEventKey*> mEvents;
|
|
|
|
|
|
|
|
void RemoveEventsAt(size_t aStart, size_t aCount) {
|
|
|
|
for (size_t i = aStart; i < aStart + aCount; i++) {
|
|
|
|
gdk_event_free(reinterpret_cast<GdkEvent*>(mEvents[i]));
|
|
|
|
}
|
|
|
|
mEvents.RemoveElementsAt(aStart, aCount);
|
2012-03-09 08:27:51 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
};
|
Bug 1443421 - part 2: IMContextWrapper should dispatch eKeyDown or eKeyUp event as "processed by IME" even when IM sent some signals without sending key event again r=m_kato
ibus and fcitx usually post key event to other IME process, then, if it causes
some signals to updating composition string, they may not send the posted
key event to us again. Then, IMContextWrapper dispatches neither eKeyDown nor
eKeyUp event since mProcessingKeyEvent becomes non-nullptr only while
OnKeyEvent() is called. So, IMContextWrapper need to store key event if
OnKeyEvent() assumes that given key event is posted to different process.
Then, if IMContextWrapper receives some signals, it should dispatch eKeyDown
and eKeyUp event with stored key event.
Note that we cannot compare the pointer of first event and following event
directly even though usually both events are same address as far as I checked
because according to the source code of ibus, fcitx and GDK, they use
gdk_event_copy() to keep storing original event. According to the document of
the API, it might just increment refcount. However, the actual implementation
of the API always creates another instance and return it. So, it might be
used same address by arena allocation or something accidentally. Anyway,
we shouldn't compare them. Instead, we need to compare each information of
two key events. Unfortunately, we also cannot compare them simply. Both
ibus and fcitx set unused bits of GdkEventKey::state to true when they send
back the event to us. Therefore, we should compare some of or all of the
members by ourselves. I think that matching time must be enough in most
cases since its value of native key events are properly set. However, for
safer code, this patch also checks type, keyval and part of state.
MozReview-Commit-ID: FZSwN61v0Sd
--HG--
extra : rebase_source : e57a654392f476f5ec52d82bdd238eed2eb91e83
2018-03-09 06:39:40 +03:00
|
|
|
// OnKeyEvent() append mPostingKeyEvents when it believes that a key event
|
|
|
|
// is posted to other IME process.
|
|
|
|
GdkEventKeyQueue mPostingKeyEvents;
|
2012-03-09 08:27:51 +04:00
|
|
|
|
2018-12-28 10:02:05 +03:00
|
|
|
static guint16 sWaitingSynthesizedKeyPressHardwareKeyCode;
|
|
|
|
|
2015-03-19 19:52:24 +03:00
|
|
|
struct Range {
|
|
|
|
uint32_t mOffset;
|
|
|
|
uint32_t mLength;
|
|
|
|
|
|
|
|
Range() : mOffset(UINT32_MAX), mLength(UINT32_MAX) {}
|
|
|
|
|
2012-03-09 08:27:51 +04:00
|
|
|
bool IsValid() const { return mOffset != UINT32_MAX; }
|
|
|
|
void Clear() {
|
2014-10-07 14:01:49 +04:00
|
|
|
mOffset = UINT32_MAX;
|
|
|
|
mLength = UINT32_MAX;
|
2012-03-09 08:27:51 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
};
|
|
|
|
|
2014-10-23 21:17:15 +04:00
|
|
|
// current target offset and length of IME composition
|
2015-06-11 13:50:15 +03:00
|
|
|
Range mCompositionTargetRange;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-10-23 21:17:15 +04:00
|
|
|
// mCompositionState indicates current status of composition.
|
Bug 1443421 - part 1: Make IMContextWrapper not dispatch eKeyDown and eKeyUp event if the native key event is being handled by other IME process r=m_kato
ibus and fcitx have asynchronous key event handling mode and it's enabled in
default settings. That is, when they receive a key event from application via
a call of gtk_im_context_filter_keypress(), they may post the key event
information to other IME process, then does nothing but store the copy of the
event with gdk_event_copy() and returns true for the result of
gtk_im_context_filter_keypress(). When the other IME process handles the
event, returns the result to them in our process. Then, they send the stored
key event to us again. Finally, they actually handles the event in our process
actually.
Therefore, we may receive every key event twice. So, this causes dispatching
eKeyDown event and eKeyUp event twice. Preceding key event is always marked
as "processed by IME" since gtk_im_context_filter_keypress() returns true
temporarily and following key event is dispatched as expected. So, we need
to ignore the first event only when gtk_im_context_filter_keypress() returns
true but the event is posted to different process.
Unfortunately, we cannot know if the key event is actually posted to different
process directly. However, we can know if active IM is ibus, fcitx or another
one and if ibus or fcitx is in asynchronous key handling mode.
The former information is provided by gtk_im_multicontext_get_context_id().
It returns a string which is set to the IM multicontext instance by creator.
We'll get "ibus" if IM is ibus, get "fcitx" if IM is fcitx.
The latter information is not provided. However, they consider the mode from
env value. ibus checks IBUS_ENABLE_SYNC_MODE. fcitx checks both
IBUS_ENABLE_SYNC_MODE and FCITX_ENABLE_SYNC_MODE.
Additionally, we can know if received key event has already been posted to
other IME process. They use undefined bit of GdkEventKey::state to store
if the key event has already been posted (1 << 25, they called "ignored" flag).
Although their approach is really hacky but we can refer the information at
least for now.
Finally, when we guess a key event is posted to other IME process, let's
IMContextWrapper::OnKeyEvent() not dispatch eKeyDown nor eKeyUp event.
Note that if it's handled synchronously as unexpected, it may causes
dispatching one or more composition events and/or delete content event.
So, in such case, we dispatch a keyboard event for processing key event
anyway. There is only once case we'll fail to dispatch keyboard event.
If we receive signals to dispatch composition events or delete content
command event when IM receives the result from other IME process but
it doesn't send the key event to us. This will be fixed by the following
patch.
MozReview-Commit-ID: 94PrlnmQ3uJ
--HG--
extra : rebase_source : fc31b0293ff0f0688dd39b0094fdf8f98b6c64d3
2018-03-08 18:46:52 +03:00
|
|
|
enum eCompositionState : uint8_t {
|
2012-03-09 08:27:51 +04:00
|
|
|
eCompositionState_NotComposing,
|
|
|
|
eCompositionState_CompositionStartDispatched,
|
2014-10-23 21:17:15 +04:00
|
|
|
eCompositionState_CompositionChangeEventDispatched
|
2018-11-30 13:46:48 +03:00
|
|
|
};
|
2012-03-09 08:27:51 +04:00
|
|
|
eCompositionState mCompositionState;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-03-19 19:52:24 +03:00
|
|
|
bool IsComposing() const {
|
2012-03-09 08:27:51 +04:00
|
|
|
return (mCompositionState != eCompositionState_NotComposing);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-10-23 21:17:15 +04:00
|
|
|
bool IsComposingOn(GtkIMContext* aContext) const {
|
|
|
|
return IsComposing() && mComposingContext == aContext;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-10-23 21:17:15 +04:00
|
|
|
bool IsComposingOnCurrentContext() const {
|
2014-11-10 12:07:44 +03:00
|
|
|
return IsComposingOn(GetCurrentContext());
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2012-03-09 08:27:51 +04:00
|
|
|
bool EditorHasCompositionString() {
|
2014-10-23 21:17:15 +04:00
|
|
|
return (mCompositionState ==
|
|
|
|
eCompositionState_CompositionChangeEventDispatched);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-10-23 21:17:15 +04:00
|
|
|
* Checks if aContext is valid context for handling composition.
|
2018-11-30 13:46:48 +03:00
|
|
|
*
|
2014-11-10 12:07:43 +03:00
|
|
|
* @param aContext An IM context which is specified by native
|
2014-10-23 21:17:15 +04:00
|
|
|
* composition events.
|
|
|
|
* @return true if the context is valid context for
|
|
|
|
* handling composition. Otherwise, false.
|
|
|
|
*/
|
|
|
|
bool IsValidContext(GtkIMContext* aContext) const;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2012-03-09 08:27:51 +04:00
|
|
|
const char* GetCompositionStateName() {
|
|
|
|
switch (mCompositionState) {
|
|
|
|
case eCompositionState_NotComposing:
|
|
|
|
return "NotComposing";
|
|
|
|
case eCompositionState_CompositionStartDispatched:
|
|
|
|
return "CompositionStartDispatched";
|
2014-10-07 14:01:49 +04:00
|
|
|
case eCompositionState_CompositionChangeEventDispatched:
|
|
|
|
return "CompositionChangeEventDispatched";
|
2012-03-09 08:27:51 +04:00
|
|
|
default:
|
|
|
|
return "InvaildState";
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2012-03-09 08:27:51 +04:00
|
|
|
|
Bug 1443421 - part 1: Make IMContextWrapper not dispatch eKeyDown and eKeyUp event if the native key event is being handled by other IME process r=m_kato
ibus and fcitx have asynchronous key event handling mode and it's enabled in
default settings. That is, when they receive a key event from application via
a call of gtk_im_context_filter_keypress(), they may post the key event
information to other IME process, then does nothing but store the copy of the
event with gdk_event_copy() and returns true for the result of
gtk_im_context_filter_keypress(). When the other IME process handles the
event, returns the result to them in our process. Then, they send the stored
key event to us again. Finally, they actually handles the event in our process
actually.
Therefore, we may receive every key event twice. So, this causes dispatching
eKeyDown event and eKeyUp event twice. Preceding key event is always marked
as "processed by IME" since gtk_im_context_filter_keypress() returns true
temporarily and following key event is dispatched as expected. So, we need
to ignore the first event only when gtk_im_context_filter_keypress() returns
true but the event is posted to different process.
Unfortunately, we cannot know if the key event is actually posted to different
process directly. However, we can know if active IM is ibus, fcitx or another
one and if ibus or fcitx is in asynchronous key handling mode.
The former information is provided by gtk_im_multicontext_get_context_id().
It returns a string which is set to the IM multicontext instance by creator.
We'll get "ibus" if IM is ibus, get "fcitx" if IM is fcitx.
The latter information is not provided. However, they consider the mode from
env value. ibus checks IBUS_ENABLE_SYNC_MODE. fcitx checks both
IBUS_ENABLE_SYNC_MODE and FCITX_ENABLE_SYNC_MODE.
Additionally, we can know if received key event has already been posted to
other IME process. They use undefined bit of GdkEventKey::state to store
if the key event has already been posted (1 << 25, they called "ignored" flag).
Although their approach is really hacky but we can refer the information at
least for now.
Finally, when we guess a key event is posted to other IME process, let's
IMContextWrapper::OnKeyEvent() not dispatch eKeyDown nor eKeyUp event.
Note that if it's handled synchronously as unexpected, it may causes
dispatching one or more composition events and/or delete content event.
So, in such case, we dispatch a keyboard event for processing key event
anyway. There is only once case we'll fail to dispatch keyboard event.
If we receive signals to dispatch composition events or delete content
command event when IM receives the result from other IME process but
it doesn't send the key event to us. This will be fixed by the following
patch.
MozReview-Commit-ID: 94PrlnmQ3uJ
--HG--
extra : rebase_source : fc31b0293ff0f0688dd39b0094fdf8f98b6c64d3
2018-03-08 18:46:52 +03:00
|
|
|
// mIMContextID indicates the ID of mContext. This is actually indicates
|
|
|
|
// IM which user selected.
|
|
|
|
IMContextID mIMContextID;
|
|
|
|
|
2015-06-11 13:50:15 +03:00
|
|
|
struct Selection final {
|
2017-06-27 12:46:08 +03:00
|
|
|
nsString mString;
|
2015-06-11 13:50:15 +03:00
|
|
|
uint32_t mOffset;
|
2015-07-27 02:23:04 +03:00
|
|
|
WritingMode mWritingMode;
|
2015-06-11 13:50:15 +03:00
|
|
|
|
|
|
|
Selection() : mOffset(UINT32_MAX) {}
|
|
|
|
|
|
|
|
void Clear() {
|
2017-06-27 12:46:08 +03:00
|
|
|
mString.Truncate();
|
2015-06-11 13:50:15 +03:00
|
|
|
mOffset = UINT32_MAX;
|
2015-07-27 02:23:04 +03:00
|
|
|
mWritingMode = WritingMode();
|
2015-06-11 13:50:15 +03:00
|
|
|
}
|
Bug 1376407 - part2: Emulate selection when committing composition as collapsed to the end of composition r=m_kato
When you start new composition during converting with Mozc in e10s mode, the following things occur:
1. Mozc commits previous composition.
2. Gecko dispatches eCompositionCommit event.
3. Mozc sets new composition string (skipping composition start signal).
4. Gecko dispatches eCompositionStart and eCompositionChange event.
5. Selection is changed asynchronously.
6. Gecko sets position of IME windows.
At #4, Gecko stores start of composition as selection start, then, trying to adjust it at #5. However, new selection is caret position in new composition string. Therefore, it's not used for the adjustment. This causes that stored composition start offset is always the start of the previous composition (if the previous patch didn't change EnsureToCacheSelection() behavior). So, IMContextWrapper needs to compute proper composition start offset in this case.
The simplest fix is, modifying selection at #2 as which will be occurred in focused editor. So, this patch makes the selection cache collapsed to the end of committing string.
Note that actual selection may be different if JS changes selection and/or the text in the focused editor. However, it doesn't matter. IMContextWrapper should behave as expected while current composition is active.
MozReview-Commit-ID: 221mDUd8yRP
--HG--
extra : rebase_source : 571b2de85ed6ea1fdadea73b7f95507937cc60e9
2017-06-27 13:11:25 +03:00
|
|
|
void CollapseTo(uint32_t aOffset, const WritingMode& aWritingMode) {
|
|
|
|
mWritingMode = aWritingMode;
|
|
|
|
mOffset = aOffset;
|
|
|
|
mString.Truncate();
|
|
|
|
}
|
2015-06-11 13:50:15 +03:00
|
|
|
|
|
|
|
void Assign(const IMENotification& aIMENotification);
|
2015-07-27 02:23:04 +03:00
|
|
|
void Assign(const WidgetQueryContentEvent& aSelectedTextEvent);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-06-11 13:50:15 +03:00
|
|
|
bool IsValid() const { return mOffset != UINT32_MAX; }
|
2017-06-27 12:46:08 +03:00
|
|
|
bool Collapsed() const { return mString.IsEmpty(); }
|
|
|
|
uint32_t Length() const { return mString.Length(); }
|
2015-06-11 13:50:15 +03:00
|
|
|
uint32_t EndOffset() const {
|
|
|
|
if (NS_WARN_IF(!IsValid())) {
|
|
|
|
return UINT32_MAX;
|
|
|
|
}
|
2015-07-27 02:23:04 +03:00
|
|
|
CheckedInt<uint32_t> endOffset =
|
2017-06-27 12:46:08 +03:00
|
|
|
CheckedInt<uint32_t>(mOffset) + mString.Length();
|
2015-06-11 13:50:15 +03:00
|
|
|
if (NS_WARN_IF(!endOffset.isValid())) {
|
|
|
|
return UINT32_MAX;
|
|
|
|
}
|
|
|
|
return endOffset.value();
|
|
|
|
}
|
|
|
|
} mSelection;
|
|
|
|
bool EnsureToCacheSelection(nsAString* aSelectedString = nullptr);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
// mIsIMFocused is set to TRUE when we call gtk_im_context_focus_in(). And
|
|
|
|
// it's set to FALSE when we call gtk_im_context_focus_out().
|
2011-09-29 10:19:26 +04:00
|
|
|
bool mIsIMFocused;
|
2018-02-22 14:56:08 +03:00
|
|
|
// mFallbackToKeyEvent is set to false when this class starts to handle
|
|
|
|
// a native key event (at that time, mProcessingKeyEvent is set to the
|
|
|
|
// native event). If active IME just commits composition with a character
|
|
|
|
// which is produced by the key with current keyboard layout, this is set
|
|
|
|
// to true.
|
|
|
|
bool mFallbackToKeyEvent;
|
|
|
|
// mKeyboardEventWasDispatched is used by OnKeyEvent() and
|
|
|
|
// MaybeDispatchKeyEventAsProcessedByIME().
|
|
|
|
// MaybeDispatchKeyEventAsProcessedByIME() dispatches an eKeyDown or
|
|
|
|
// eKeyUp event event if the composition is caused by a native
|
|
|
|
// key press event. If this is true, a keyboard event has been dispatched
|
|
|
|
// for the native event. If so, MaybeDispatchKeyEventAsProcessedByIME()
|
|
|
|
// won't dispatch keyboard event anymore.
|
|
|
|
bool mKeyboardEventWasDispatched;
|
Bug 1505147 - nsWindow::OnKeyPressEvent() shouldn't dispatch eKeyDown event when IMContextWrapper::OnKeyEvent() has already dispatched it for the event r=m_kato
Currently, IMContextWrapper::OnKeyEvent() assumes that IME won't synthesize
keyboard event asynchronously again in some cases. For example, one of the
cases is that user inputs text with a dead key sequence. However, IME may
synthesize key event asynchronously only in a few cases even in a dead key
sequence. Unfortunately, for not losing a chance to dispatch eKeyDown/eKeyUp
event, we need to keep dispatching eKeyDown or eKeyUp event when we receive
original event in dead key sequence. However, according to this bug, we need to
stop dispatching eKeyDown and eKeyUp events when we receive unexpected
async synthesized key event.
If IMContextWrapper::OnKeyEvent() needs to return whether it (has already)
dispatched an eKeyDown or eKeyUp and whether it was consumed, then,
nsWindow can stop dispatching redundant eKeyDown and eKeyUp events.
So, this patch makes IMContextWrapper::OnKeyEvent() return
KeyHandlingState enum class instead of just a bool value to notify the caller
of detail of the event status. And also makes each caller of nsWindow not
dispatch eKeyDown nor eKeyUp event when it returns
KeyHandlingState::eNotHandledButDispatched or
KeyHandlingState::eNotHandledButConsumed.
Differential Revision: https://phabricator.services.mozilla.com/D12517
--HG--
extra : moz-landing-system : lando
2018-11-26 06:26:39 +03:00
|
|
|
// Whether the keyboard event which as dispatched at setting
|
|
|
|
// mKeyboardEventWasDispatched to true was consumed or not.
|
|
|
|
bool mKeyboardEventWasConsumed;
|
2015-03-17 10:07:02 +03:00
|
|
|
// mIsDeletingSurrounding is true while OnDeleteSurroundingNative() is
|
|
|
|
// trying to delete the surrounding text.
|
|
|
|
bool mIsDeletingSurrounding;
|
2015-06-11 13:50:15 +03:00
|
|
|
// mLayoutChanged is true after OnLayoutChange() is called. This is reset
|
2015-09-11 15:21:27 +03:00
|
|
|
// when eCompositionChange is being dispatched.
|
2015-06-11 13:50:15 +03:00
|
|
|
bool mLayoutChanged;
|
2015-06-26 10:08:29 +03:00
|
|
|
// mSetCursorPositionOnKeyEvent true when caret rect or position is updated
|
|
|
|
// with no composition. If true, we update candidate window position
|
|
|
|
// before key down
|
|
|
|
bool mSetCursorPositionOnKeyEvent;
|
2015-10-27 01:21:37 +03:00
|
|
|
// mPendingResettingIMContext becomes true if selection change notification
|
|
|
|
// is received during composition but the selection change occurred before
|
|
|
|
// starting the composition. In such case, we cannot notify IME of
|
|
|
|
// selection change during composition because we don't want to commit
|
|
|
|
// the composition in such case. However, we should notify IME of the
|
|
|
|
// selection change after the composition is committed.
|
|
|
|
bool mPendingResettingIMContext;
|
2016-09-15 16:36:23 +03:00
|
|
|
// mRetrieveSurroundingSignalReceived is true after "retrieve_surrounding"
|
|
|
|
// signal is received until selection is changed in Gecko.
|
|
|
|
bool mRetrieveSurroundingSignalReceived;
|
Bug 1443091 - IMContextWrapper should dispatch eKeyDown and eKeyUp event as "Dead" keys rather than "Process" if user pressed a dead key r=m_kato
On Linux, dead key is implemented with "table-based input methods" which are
available even on GtkIMContextSimple (i.e., available even in password fields).
Therefore, IMContextWrapper handles dead key sequence as usual composition of
IME. However, on the other platforms, we dispatch "Dead" eKeyDown and eKeyUp
events for dead key.
We started to mark keyboard events which are handled by IME as "processed by
IME" since bug 1343451, i.e., we started to set mKeyNameIndex to
KEY_NAME_INDEX_Process. However, we should keep previous behavior, i.e., keep
setting it to KEY_NAME_INDEX_Dead. Fortunately, GDK's key event tells us
whether the keyboard event is a dead key event with keysym. So, we can detect
if we're in a dead key sequence simply.
MozReview-Commit-ID: Dv336WptfXN
--HG--
extra : rebase_source : e8a7b5a7eb7c57e1e45de20ebebd56f88457cfc6
2018-03-05 16:03:58 +03:00
|
|
|
// mMaybeInDeadKeySequence is set to true when we detect a dead key press
|
|
|
|
// and set to false when we're sure dead key sequence has been finished.
|
|
|
|
// Note that we cannot detect which key event causes ending a dead key
|
|
|
|
// sequence. For example, when you press dead key grave with ibus Spanish
|
|
|
|
// keyboard layout, it just consumes the key event when we call
|
|
|
|
// gtk_im_context_filter_keypress(). Then, pressing "Escape" key cancels
|
|
|
|
// the dead key sequence but we don't receive any signal and it's consumed
|
|
|
|
// by gtk_im_context_filter_keypress() normally. On the other hand, when
|
|
|
|
// pressing "Shift" key causes exactly same behavior but dead key sequence
|
|
|
|
// isn't finished yet.
|
|
|
|
bool mMaybeInDeadKeySequence;
|
Bug 1443421 - part 1: Make IMContextWrapper not dispatch eKeyDown and eKeyUp event if the native key event is being handled by other IME process r=m_kato
ibus and fcitx have asynchronous key event handling mode and it's enabled in
default settings. That is, when they receive a key event from application via
a call of gtk_im_context_filter_keypress(), they may post the key event
information to other IME process, then does nothing but store the copy of the
event with gdk_event_copy() and returns true for the result of
gtk_im_context_filter_keypress(). When the other IME process handles the
event, returns the result to them in our process. Then, they send the stored
key event to us again. Finally, they actually handles the event in our process
actually.
Therefore, we may receive every key event twice. So, this causes dispatching
eKeyDown event and eKeyUp event twice. Preceding key event is always marked
as "processed by IME" since gtk_im_context_filter_keypress() returns true
temporarily and following key event is dispatched as expected. So, we need
to ignore the first event only when gtk_im_context_filter_keypress() returns
true but the event is posted to different process.
Unfortunately, we cannot know if the key event is actually posted to different
process directly. However, we can know if active IM is ibus, fcitx or another
one and if ibus or fcitx is in asynchronous key handling mode.
The former information is provided by gtk_im_multicontext_get_context_id().
It returns a string which is set to the IM multicontext instance by creator.
We'll get "ibus" if IM is ibus, get "fcitx" if IM is fcitx.
The latter information is not provided. However, they consider the mode from
env value. ibus checks IBUS_ENABLE_SYNC_MODE. fcitx checks both
IBUS_ENABLE_SYNC_MODE and FCITX_ENABLE_SYNC_MODE.
Additionally, we can know if received key event has already been posted to
other IME process. They use undefined bit of GdkEventKey::state to store
if the key event has already been posted (1 << 25, they called "ignored" flag).
Although their approach is really hacky but we can refer the information at
least for now.
Finally, when we guess a key event is posted to other IME process, let's
IMContextWrapper::OnKeyEvent() not dispatch eKeyDown nor eKeyUp event.
Note that if it's handled synchronously as unexpected, it may causes
dispatching one or more composition events and/or delete content event.
So, in such case, we dispatch a keyboard event for processing key event
anyway. There is only once case we'll fail to dispatch keyboard event.
If we receive signals to dispatch composition events or delete content
command event when IM receives the result from other IME process but
it doesn't send the key event to us. This will be fixed by the following
patch.
MozReview-Commit-ID: 94PrlnmQ3uJ
--HG--
extra : rebase_source : fc31b0293ff0f0688dd39b0094fdf8f98b6c64d3
2018-03-08 18:46:52 +03:00
|
|
|
// mIsIMInAsyncKeyHandlingMode is set to true if we know that IM handles
|
|
|
|
// key events asynchronously. I.e., filtered key event may come again
|
|
|
|
// later.
|
|
|
|
bool mIsIMInAsyncKeyHandlingMode;
|
Bug 1444572 - IMContextWrapper should dispatch fake eKeyDown event during composition if active IM is uim r=m_kato
uim is an old IM which uses key snooper to listen to key events rather than
via filter key event API which should be called by applications. It's still
used by Debian 9.x, so, we still need to support this.
Unfortunately, we cannot detect if uim actually uses key snooper because it's
switch by build option of uim. Currently, Debian builds uim as using key
snooper. So, we should assume uim uses key snooper always. On the other
hand, somebody *might* use uim built as not using key snooper, so, let's
decide if uim uses key snooper with new pref,
"intl.ime.hack.uim.using_key_snooper", but its default should be true.
Note that ibus and Fcitx also have the mode to use key snooper (perhaps for
backward compatibility with uim). However, it's not enabled in default
settings and even if it's enabled, Firefox is in whitelist in the default
settings of them for stop using key snooper. Therefore, we don't need to
support key snooper mode for them unless we'll get some requests to
support their key snooping mode.
MozReview-Commit-ID: 6fTsfKrHzvo
--HG--
extra : rebase_source : 8ddf4541db635246e6bb0ddc73b012c9be001c6d
2018-03-12 09:41:39 +03:00
|
|
|
// mIsKeySnooped is set to true if IM uses key snooper to listen key events.
|
|
|
|
// In such case, we won't receive key events if IME consumes the event.
|
|
|
|
bool mIsKeySnooped;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-07-27 02:23:04 +03:00
|
|
|
// sLastFocusedContext is a pointer to the last focused instance of this
|
|
|
|
// class. When a instance is destroyed and sLastFocusedContext refers it,
|
2010-03-19 07:21:16 +03:00
|
|
|
// this is cleared. So, this refers valid pointer always.
|
2015-07-27 02:23:04 +03:00
|
|
|
static IMContextWrapper* sLastFocusedContext;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-01-28 13:02:08 +04:00
|
|
|
// sUseSimpleContext indeicates if password editors and editors with
|
|
|
|
// |ime-mode: disabled;| should use GtkIMContextSimple.
|
|
|
|
// If true, they use GtkIMContextSimple. Otherwise, not.
|
|
|
|
static bool sUseSimpleContext;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
// Callback methods for native IME events. These methods should call
|
|
|
|
// the related instance methods simply.
|
2015-07-27 02:23:04 +03:00
|
|
|
static gboolean OnRetrieveSurroundingCallback(GtkIMContext* aContext,
|
|
|
|
IMContextWrapper* aModule);
|
|
|
|
static gboolean OnDeleteSurroundingCallback(GtkIMContext* aContext,
|
2010-03-19 07:21:16 +03:00
|
|
|
gint aOffset, gint aNChars,
|
2015-07-27 02:23:04 +03:00
|
|
|
IMContextWrapper* aModule);
|
|
|
|
static void OnCommitCompositionCallback(GtkIMContext* aContext,
|
|
|
|
const gchar* aString,
|
|
|
|
IMContextWrapper* aModule);
|
|
|
|
static void OnChangeCompositionCallback(GtkIMContext* aContext,
|
|
|
|
IMContextWrapper* aModule);
|
|
|
|
static void OnStartCompositionCallback(GtkIMContext* aContext,
|
|
|
|
IMContextWrapper* aModule);
|
|
|
|
static void OnEndCompositionCallback(GtkIMContext* aContext,
|
|
|
|
IMContextWrapper* aModule);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
// The instance methods for the native IME events.
|
2015-07-27 02:23:04 +03:00
|
|
|
gboolean OnRetrieveSurroundingNative(GtkIMContext* aContext);
|
|
|
|
gboolean OnDeleteSurroundingNative(GtkIMContext* aContext, gint aOffset,
|
|
|
|
gint aNChars);
|
|
|
|
void OnCommitCompositionNative(GtkIMContext* aContext, const gchar* aString);
|
|
|
|
void OnChangeCompositionNative(GtkIMContext* aContext);
|
|
|
|
void OnStartCompositionNative(GtkIMContext* aContext);
|
|
|
|
void OnEndCompositionNative(GtkIMContext* aContext);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-11-10 12:07:43 +03:00
|
|
|
/**
|
2014-11-10 12:07:44 +03:00
|
|
|
* GetCurrentContext() returns current IM context which is chosen with the
|
|
|
|
* enabled state.
|
2014-11-10 12:07:43 +03:00
|
|
|
* WARNING:
|
|
|
|
* When this class receives some signals for a composition after focus
|
|
|
|
* is moved in Gecko, the result of this may be different from given
|
|
|
|
* context by the signals.
|
|
|
|
*/
|
2014-11-10 12:07:44 +03:00
|
|
|
GtkIMContext* GetCurrentContext() const;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-11-10 12:07:44 +03:00
|
|
|
/**
|
|
|
|
* GetActiveContext() returns a composing context or current context.
|
|
|
|
*/
|
|
|
|
GtkIMContext* GetActiveContext() const {
|
|
|
|
return mComposingContext ? mComposingContext : GetCurrentContext();
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
// If the owner window and IM context have been destroyed, returns TRUE.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool IsDestroyed() { return !mOwnerWindow; }
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
// Sets focus to the instance of this class.
|
|
|
|
void Focus();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
// Steals focus from the instance of this class.
|
|
|
|
void Blur();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
// Initializes the instance.
|
|
|
|
void Init();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2017-09-04 14:18:43 +03:00
|
|
|
/**
|
|
|
|
* Reset the active context, i.e., if there is mComposingContext, reset it.
|
|
|
|
* Otherwise, reset current context. Note that all native composition
|
|
|
|
* events during calling this will be ignored.
|
|
|
|
*/
|
2010-03-19 07:21:16 +03:00
|
|
|
void ResetIME();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
// Gets the current composition string by the native APIs.
|
2014-10-23 21:17:15 +04:00
|
|
|
void GetCompositionString(GtkIMContext* aContext,
|
|
|
|
nsAString& aCompositionString);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-11-10 12:07:43 +03:00
|
|
|
/**
|
|
|
|
* Generates our text range array from current composition string.
|
|
|
|
*
|
|
|
|
* @param aContext A GtkIMContext which is being handled.
|
2015-08-19 10:37:39 +03:00
|
|
|
* @param aCompositionString The data to be dispatched with
|
|
|
|
* compositionchange event.
|
2014-11-10 12:07:43 +03:00
|
|
|
*/
|
2015-07-27 02:23:04 +03:00
|
|
|
already_AddRefed<TextRangeArray> CreateTextRangeArray(
|
2015-08-19 10:37:39 +03:00
|
|
|
GtkIMContext* aContext, const nsAString& aCompositionString);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-08-19 10:37:39 +03:00
|
|
|
/**
|
|
|
|
* SetTextRange() initializes aTextRange with aPangoAttrIter.
|
|
|
|
*
|
|
|
|
* @param aPangoAttrIter An iter which represents a clause of the
|
|
|
|
* composition string.
|
|
|
|
* @param aUTF8CompositionString The whole composition string (UTF-8).
|
2015-08-19 10:37:39 +03:00
|
|
|
* @param aUTF16CaretOffset The caret offset in the composition
|
|
|
|
* string encoded as UTF-16.
|
2015-08-19 10:37:39 +03:00
|
|
|
* @param aTextRange The result.
|
|
|
|
* @return true if this initializes aTextRange.
|
|
|
|
* Otherwise, false.
|
|
|
|
*/
|
|
|
|
bool SetTextRange(PangoAttrIterator* aPangoAttrIter,
|
|
|
|
const gchar* aUTF8CompositionString,
|
|
|
|
uint32_t aUTF16CaretOffset, TextRange& aTextRange) const;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-08-19 10:37:39 +03:00
|
|
|
/**
|
|
|
|
* ToNscolor() converts the PangoColor in aPangoAttrColor to nscolor.
|
|
|
|
*/
|
|
|
|
static nscolor ToNscolor(PangoAttrColor* aPangoAttrColor);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-11-10 12:07:43 +03:00
|
|
|
/**
|
2015-06-11 13:50:15 +03:00
|
|
|
* Move the candidate window with "fake" cursor position.
|
2014-11-10 12:07:43 +03:00
|
|
|
*
|
|
|
|
* @param aContext A GtkIMContext which is being handled.
|
|
|
|
*/
|
2015-06-11 13:50:15 +03:00
|
|
|
void SetCursorPosition(GtkIMContext* aContext);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
// Queries the current selection offset of the window.
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t GetSelectionOffset(nsWindow* aWindow);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-24 18:04:39 +03:00
|
|
|
// Get current paragraph text content and cursor position
|
2012-08-22 19:56:38 +04:00
|
|
|
nsresult GetCurrentParagraph(nsAString& aText, uint32_t& aCursorPos);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-11-10 12:07:43 +03:00
|
|
|
/**
|
|
|
|
* Delete text portion
|
|
|
|
*
|
|
|
|
* @param aContext A GtkIMContext which is being handled.
|
|
|
|
* @param aOffset Start offset of the range to delete.
|
|
|
|
* @param aNChars Count of characters to delete. It depends
|
|
|
|
* on |g_utf8_strlen()| what is one character.
|
|
|
|
*/
|
|
|
|
nsresult DeleteText(GtkIMContext* aContext, int32_t aOffset,
|
|
|
|
uint32_t aNChars);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
// Initializes the GUI event.
|
2015-07-27 02:23:04 +03:00
|
|
|
void InitEvent(WidgetGUIEvent& aEvent);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
// Called before destroying the context to work around some platform bugs.
|
2015-07-27 02:23:04 +03:00
|
|
|
void PrepareToDestroyContext(GtkIMContext* aContext);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-19 07:21:16 +03:00
|
|
|
/**
|
|
|
|
* WARNING:
|
|
|
|
* Following methods dispatch gecko events. Then, the focused widget
|
|
|
|
* can be destroyed, and also it can be stolen focus. If they returns
|
|
|
|
* FALSE, callers cannot continue the composition.
|
2018-02-22 14:56:08 +03:00
|
|
|
* - MaybeDispatchKeyEventAsProcessedByIME
|
2010-03-19 07:21:16 +03:00
|
|
|
* - DispatchCompositionStart
|
2014-10-07 14:01:49 +04:00
|
|
|
* - DispatchCompositionChangeEvent
|
2014-11-25 08:02:34 +03:00
|
|
|
* - DispatchCompositionCommitEvent
|
2010-03-19 07:21:16 +03:00
|
|
|
*/
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-02-22 14:56:08 +03:00
|
|
|
/**
|
|
|
|
* Dispatch an eKeyDown or eKeyUp event whose mKeyCode value is
|
|
|
|
* NS_VK_PROCESSKEY and mKeyNameIndex is KEY_NAME_INDEX_Process if
|
Bug 1443421 - part 2: IMContextWrapper should dispatch eKeyDown or eKeyUp event as "processed by IME" even when IM sent some signals without sending key event again r=m_kato
ibus and fcitx usually post key event to other IME process, then, if it causes
some signals to updating composition string, they may not send the posted
key event to us again. Then, IMContextWrapper dispatches neither eKeyDown nor
eKeyUp event since mProcessingKeyEvent becomes non-nullptr only while
OnKeyEvent() is called. So, IMContextWrapper need to store key event if
OnKeyEvent() assumes that given key event is posted to different process.
Then, if IMContextWrapper receives some signals, it should dispatch eKeyDown
and eKeyUp event with stored key event.
Note that we cannot compare the pointer of first event and following event
directly even though usually both events are same address as far as I checked
because according to the source code of ibus, fcitx and GDK, they use
gdk_event_copy() to keep storing original event. According to the document of
the API, it might just increment refcount. However, the actual implementation
of the API always creates another instance and return it. So, it might be
used same address by arena allocation or something accidentally. Anyway,
we shouldn't compare them. Instead, we need to compare each information of
two key events. Unfortunately, we also cannot compare them simply. Both
ibus and fcitx set unused bits of GdkEventKey::state to true when they send
back the event to us. Therefore, we should compare some of or all of the
members by ourselves. I think that matching time must be enough in most
cases since its value of native key events are properly set. However, for
safer code, this patch also checks type, keyval and part of state.
MozReview-Commit-ID: FZSwN61v0Sd
--HG--
extra : rebase_source : e57a654392f476f5ec52d82bdd238eed2eb91e83
2018-03-09 06:39:40 +03:00
|
|
|
* we're not in a dead key sequence, mProcessingKeyEvent is nullptr
|
|
|
|
* but mPostingKeyEvents is not empty or mProcessingKeyEvent is not
|
|
|
|
* nullptr and mKeyboardEventWasDispatched is still false. If this
|
|
|
|
* dispatches a keyboard event, this sets mKeyboardEventWasDispatched
|
|
|
|
* to true.
|
2018-02-22 14:56:08 +03:00
|
|
|
*
|
Bug 1444572 - IMContextWrapper should dispatch fake eKeyDown event during composition if active IM is uim r=m_kato
uim is an old IM which uses key snooper to listen to key events rather than
via filter key event API which should be called by applications. It's still
used by Debian 9.x, so, we still need to support this.
Unfortunately, we cannot detect if uim actually uses key snooper because it's
switch by build option of uim. Currently, Debian builds uim as using key
snooper. So, we should assume uim uses key snooper always. On the other
hand, somebody *might* use uim built as not using key snooper, so, let's
decide if uim uses key snooper with new pref,
"intl.ime.hack.uim.using_key_snooper", but its default should be true.
Note that ibus and Fcitx also have the mode to use key snooper (perhaps for
backward compatibility with uim). However, it's not enabled in default
settings and even if it's enabled, Firefox is in whitelist in the default
settings of them for stop using key snooper. Therefore, we don't need to
support key snooper mode for them unless we'll get some requests to
support their key snooping mode.
MozReview-Commit-ID: 6fTsfKrHzvo
--HG--
extra : rebase_source : 8ddf4541db635246e6bb0ddc73b012c9be001c6d
2018-03-12 09:41:39 +03:00
|
|
|
* @param aFollowingEvent The following event message.
|
2018-02-22 14:56:08 +03:00
|
|
|
* @return If the caller can continue to handle
|
|
|
|
* composition, returns true. Otherwise,
|
|
|
|
* false. For example, if focus is moved
|
|
|
|
* by dispatched keyboard event, returns
|
|
|
|
* false.
|
|
|
|
*/
|
Bug 1444572 - IMContextWrapper should dispatch fake eKeyDown event during composition if active IM is uim r=m_kato
uim is an old IM which uses key snooper to listen to key events rather than
via filter key event API which should be called by applications. It's still
used by Debian 9.x, so, we still need to support this.
Unfortunately, we cannot detect if uim actually uses key snooper because it's
switch by build option of uim. Currently, Debian builds uim as using key
snooper. So, we should assume uim uses key snooper always. On the other
hand, somebody *might* use uim built as not using key snooper, so, let's
decide if uim uses key snooper with new pref,
"intl.ime.hack.uim.using_key_snooper", but its default should be true.
Note that ibus and Fcitx also have the mode to use key snooper (perhaps for
backward compatibility with uim). However, it's not enabled in default
settings and even if it's enabled, Firefox is in whitelist in the default
settings of them for stop using key snooper. Therefore, we don't need to
support key snooper mode for them unless we'll get some requests to
support their key snooping mode.
MozReview-Commit-ID: 6fTsfKrHzvo
--HG--
extra : rebase_source : 8ddf4541db635246e6bb0ddc73b012c9be001c6d
2018-03-12 09:41:39 +03:00
|
|
|
bool MaybeDispatchKeyEventAsProcessedByIME(EventMessage aFollowingEvent);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-11-10 12:07:42 +03:00
|
|
|
/**
|
|
|
|
* Dispatches a composition start event.
|
|
|
|
*
|
2014-11-10 12:07:43 +03:00
|
|
|
* @param aContext A GtkIMContext which is being handled.
|
2014-11-10 12:07:42 +03:00
|
|
|
* @return true if the focused widget is neither
|
|
|
|
* destroyed nor changed. Otherwise, false.
|
|
|
|
*/
|
2014-11-10 12:07:43 +03:00
|
|
|
bool DispatchCompositionStart(GtkIMContext* aContext);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-11-10 12:07:42 +03:00
|
|
|
/**
|
|
|
|
* Dispatches a compositionchange event.
|
|
|
|
*
|
2014-11-10 12:07:43 +03:00
|
|
|
* @param aContext A GtkIMContext which is being handled.
|
2014-11-10 12:07:42 +03:00
|
|
|
* @param aCompositionString New composition string.
|
|
|
|
* @return true if the focused widget is neither
|
|
|
|
* destroyed nor changed. Otherwise, false.
|
|
|
|
*/
|
2014-11-10 12:07:43 +03:00
|
|
|
bool DispatchCompositionChangeEvent(GtkIMContext* aContext,
|
|
|
|
const nsAString& aCompositionString);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-11-10 12:07:42 +03:00
|
|
|
/**
|
2014-11-25 08:02:34 +03:00
|
|
|
* Dispatches a compositioncommit event or compositioncommitasis event.
|
2014-11-10 12:07:42 +03:00
|
|
|
*
|
2014-11-10 12:07:43 +03:00
|
|
|
* @param aContext A GtkIMContext which is being handled.
|
2014-11-25 08:02:34 +03:00
|
|
|
* @param aCommitString If this is nullptr, the composition will
|
|
|
|
* be committed with last dispatched data.
|
|
|
|
* Otherwise, the composition will be
|
|
|
|
* committed with this value.
|
2014-11-10 12:07:42 +03:00
|
|
|
* @return true if the focused widget is neither
|
|
|
|
* destroyed nor changed. Otherwise, false.
|
|
|
|
*/
|
2014-11-25 08:02:34 +03:00
|
|
|
bool DispatchCompositionCommitEvent(GtkIMContext* aContext,
|
|
|
|
const nsAString* aCommitString = nullptr);
|
2010-03-19 07:21:16 +03:00
|
|
|
};
|
|
|
|
|
2015-07-27 02:23:04 +03:00
|
|
|
} // namespace widget
|
|
|
|
} // namespace mozilla
|
|
|
|
|
|
|
|
#endif // #ifndef IMContextWrapper_h_
|