mirror of https://gitee.com/openkylin/fcitx5.git
Optimize the support for virtual keyboard
1. There are two kinds of virtual keyboard at least. 2. The input method engine may support one or two function mode: full or limited. a) The full function mode is the default function mode. All the input method engine which does not implement InputMethodEngineV4 or its ascendants supports the full function mode. b) The limited function mode is a dedicated function mode which is used for the true virtual keyboard. The input method engine which implements InputMethodEngineV4 or its ascendants should tell fcitx which function mode it supports. That is, it may support full function mode or limited function mode or both. 3. The two different virtual keyboard use different function mode of input method engine. The virtual keyboard should tell fcitx which function mode it needs. Fcitx will decide which function mode is used. For example, if the virtual keyboard tells fcitx that it needs limited function mode, but the input method engine does not support that mode, then fcitx will use full function mode for compitibility reason.
This commit is contained in:
parent
bbae9fc7f6
commit
ab01c802e8
|
@ -319,6 +319,12 @@ bool InputContext::keyEvent(KeyEvent &event) {
|
|||
return result;
|
||||
}
|
||||
|
||||
bool InputContext::isFunctionModeSupported(FunctionMode functionMode) {
|
||||
FCITX_D();
|
||||
|
||||
return d->isFunctionModeSupported(functionMode);
|
||||
}
|
||||
|
||||
bool InputContext::virtualKeyboardEvent(VirtualKeyboardEvent &event) {
|
||||
FCITX_D();
|
||||
RETURN_IF_HAS_NO_FOCUS(false);
|
||||
|
|
|
@ -41,6 +41,8 @@ class InputPanel;
|
|||
class StatusArea;
|
||||
typedef std::function<bool(InputContext *ic)> InputContextVisitor;
|
||||
|
||||
enum class FunctionMode : uint32_t { Full = 1 << 0, Limited = 1 << 1 };
|
||||
|
||||
/**
|
||||
* An input context represents a client of Fcitx. It can be a Window, or a text
|
||||
* field depending on the application.
|
||||
|
@ -133,6 +135,8 @@ public:
|
|||
/// Send a key event to current input context.
|
||||
bool keyEvent(KeyEvent &event);
|
||||
|
||||
bool isFunctionModeSupported(FunctionMode functionMode);
|
||||
|
||||
/**
|
||||
* Send a virtual keyboard event to current input context.
|
||||
*
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <fcitx/inputcontext.h>
|
||||
#include <fcitx/inputcontextmanager.h>
|
||||
#include <fcitx/inputcontextproperty.h>
|
||||
#include <fcitx/inputmethodengine.h>
|
||||
#include <fcitx/inputpanel.h>
|
||||
#include <fcitx/instance.h>
|
||||
#include <fcitx/statusarea.h>
|
||||
|
@ -132,6 +133,14 @@ public:
|
|||
|
||||
InputContextProperty *property(int slot) { return properties_[slot].get(); }
|
||||
|
||||
bool isFunctionModeSupported(FunctionMode functionMode) {
|
||||
FCITX_Q();
|
||||
|
||||
auto *instance = manager_.instance();
|
||||
auto *engine = instance->inputMethodEngine(q);
|
||||
return engine->isFunctionModeSupported(functionMode);
|
||||
}
|
||||
|
||||
InputContextManager &manager_;
|
||||
FocusGroup *group_;
|
||||
InputPanel inputPanel_;
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*
|
||||
*/
|
||||
#include "inputmethodengine.h"
|
||||
#include "inputcontext.h"
|
||||
#include "inputpanel.h"
|
||||
|
||||
namespace fcitx {
|
||||
|
@ -28,18 +27,43 @@ std::string InputMethodEngine::subModeLabel(const InputMethodEntry &entry,
|
|||
|
||||
void InputMethodEngine::virtualKeyboardEvent(
|
||||
const InputMethodEntry &entry, VirtualKeyboardEvent &virtualKeyboardEvent) {
|
||||
if (auto *this4 = dynamic_cast<InputMethodEngineV4 *>(this)) {
|
||||
this4->virtualKeyboardEventImpl(entry, virtualKeyboardEvent);
|
||||
} else if (auto virtualKeyEvent = virtualKeyboardEvent.toKeyEvent()) {
|
||||
keyEvent(entry, *virtualKeyEvent);
|
||||
// TODO: revisit the default action.
|
||||
if (virtualKeyEvent->accepted()) {
|
||||
virtualKeyboardEvent.accept();
|
||||
} else if (virtualKeyboardEvent.text() != "") {
|
||||
virtualKeyboardEvent.inputContext()->commitString(
|
||||
virtualKeyboardEvent.text());
|
||||
}
|
||||
auto *this4 = dynamic_cast<InputMethodEngineV4 *>(this);
|
||||
if (this4 == nullptr) {
|
||||
FCITX_WARN() << "InputMethodEngine::virtualKeyboardEvent is called."
|
||||
<< "But there is no valid InputMethodEngineV4 instance."
|
||||
<< "So it returns early.";
|
||||
return;
|
||||
}
|
||||
|
||||
this4->virtualKeyboardEventImpl(entry, virtualKeyboardEvent);
|
||||
}
|
||||
|
||||
FunctionMode InputMethodEngine::getFunctionMode() const {
|
||||
const auto *this4 = dynamic_cast<const InputMethodEngineV4 *>(this);
|
||||
if (this4 == nullptr) {
|
||||
return FunctionMode::Full;
|
||||
}
|
||||
|
||||
return this4->getFunctionModeImpl();
|
||||
}
|
||||
|
||||
void InputMethodEngine::setFunctionMode(FunctionMode functionMode) {
|
||||
auto *this4 = dynamic_cast<InputMethodEngineV4 *>(this);
|
||||
if (this4 == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
this4->setFunctionModeImpl(functionMode);
|
||||
}
|
||||
|
||||
bool InputMethodEngine::isFunctionModeSupported(
|
||||
FunctionMode functionMode) const {
|
||||
const auto *this4 = dynamic_cast<const InputMethodEngineV4 *>(this);
|
||||
if (this4 == nullptr) {
|
||||
return FunctionMode::Full == functionMode;
|
||||
}
|
||||
|
||||
return this4->isFunctionModeSupportedImpl(functionMode);
|
||||
}
|
||||
|
||||
void defaultInvokeActionBehavior(InvokeActionEvent &event) {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <fcitx/event.h>
|
||||
#include <fcitx/inputmethodentry.h>
|
||||
#include "fcitxcore_export.h"
|
||||
#include "inputcontext.h"
|
||||
|
||||
namespace fcitx {
|
||||
|
||||
|
@ -182,6 +183,12 @@ public:
|
|||
*/
|
||||
void virtualKeyboardEvent(const InputMethodEntry &entry,
|
||||
VirtualKeyboardEvent &VirtualKeyboardEvent);
|
||||
|
||||
FunctionMode getFunctionMode() const;
|
||||
|
||||
void setFunctionMode(FunctionMode functionMode);
|
||||
|
||||
bool isFunctionModeSupported(FunctionMode functionMode) const;
|
||||
};
|
||||
|
||||
class FCITXCORE_EXPORT InputMethodEngineV2 : public InputMethodEngine {
|
||||
|
@ -207,6 +214,13 @@ public:
|
|||
virtual void
|
||||
virtualKeyboardEventImpl(const InputMethodEntry &entry,
|
||||
VirtualKeyboardEvent &VirtualKeyboardEvent) = 0;
|
||||
|
||||
virtual FunctionMode getFunctionModeImpl() const = 0;
|
||||
|
||||
virtual void setFunctionModeImpl(FunctionMode functionMode) = 0;
|
||||
|
||||
virtual bool
|
||||
isFunctionModeSupportedImpl(FunctionMode functionMode) const = 0;
|
||||
};
|
||||
|
||||
} // namespace fcitx
|
||||
|
|
|
@ -897,18 +897,24 @@ Instance::Instance(int argc, char **argv) {
|
|||
}
|
||||
inputState->hideInputMethodInfo();
|
||||
}));
|
||||
d->eventWatchers_.emplace_back(
|
||||
watchEvent(EventType::InputContextKeyEvent,
|
||||
EventWatcherPhase::InputMethod, [this](Event &event) {
|
||||
auto &keyEvent = static_cast<KeyEvent &>(event);
|
||||
auto *ic = keyEvent.inputContext();
|
||||
auto *engine = inputMethodEngine(ic);
|
||||
const auto *entry = inputMethodEntry(ic);
|
||||
if (!engine || !entry) {
|
||||
return;
|
||||
}
|
||||
engine->keyEvent(*entry, keyEvent);
|
||||
}));
|
||||
d->eventWatchers_.emplace_back(watchEvent(
|
||||
EventType::InputContextKeyEvent, EventWatcherPhase::InputMethod,
|
||||
[this](Event &event) {
|
||||
auto &keyEvent = static_cast<KeyEvent &>(event);
|
||||
auto *ic = keyEvent.inputContext();
|
||||
auto *engine = inputMethodEngine(ic);
|
||||
const auto *entry = inputMethodEntry(ic);
|
||||
if (!engine || !entry ||
|
||||
!engine->isFunctionModeSupported(FunctionMode::Full)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (engine->getFunctionMode() != FunctionMode::Full) {
|
||||
engine->setFunctionMode(FunctionMode::Full);
|
||||
}
|
||||
|
||||
engine->keyEvent(*entry, keyEvent);
|
||||
}));
|
||||
d->eventWatchers_.emplace_back(watchEvent(
|
||||
EventType::InputContextVirtualKeyboardEvent,
|
||||
EventWatcherPhase::InputMethod, [this](Event &event) {
|
||||
|
@ -916,9 +922,15 @@ Instance::Instance(int argc, char **argv) {
|
|||
auto *ic = keyEvent.inputContext();
|
||||
auto *engine = inputMethodEngine(ic);
|
||||
const auto *entry = inputMethodEntry(ic);
|
||||
if (!engine || !entry) {
|
||||
if (!engine || !entry ||
|
||||
!engine->isFunctionModeSupported(FunctionMode::Limited)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (engine->getFunctionMode() != FunctionMode::Limited) {
|
||||
engine->setFunctionMode(FunctionMode::Limited);
|
||||
}
|
||||
|
||||
engine->virtualKeyboardEvent(*entry, keyEvent);
|
||||
}));
|
||||
d->eventWatchers_.emplace_back(watchEvent(
|
||||
|
|
|
@ -77,6 +77,10 @@ public:
|
|||
void processKeyEvent(uint32_t keyval, uint32_t keycode, uint32_t state,
|
||||
bool isRelease, uint32_t time);
|
||||
|
||||
void processKeyEventV2(uint32_t keyval, uint32_t keycode, uint32_t state,
|
||||
bool isRelease, uint32_t time,
|
||||
uint32_t functionMode);
|
||||
|
||||
void processVisibilityEvent(bool /*visible*/) {}
|
||||
|
||||
void selectCandidate(int index) {
|
||||
|
@ -126,9 +130,18 @@ public:
|
|||
private:
|
||||
PageableCandidateList *getPageableCandidateList();
|
||||
|
||||
static bool isFunctionModeValid(uint32_t functionMode);
|
||||
static bool shouldProcessKeyEvent(InputContext *inputContext,
|
||||
uint32_t functionMode);
|
||||
static bool shouldProcessVirtualKeyboardEvent(InputContext *inputContext,
|
||||
FunctionMode functionMode);
|
||||
|
||||
private:
|
||||
FCITX_OBJECT_VTABLE_METHOD(processKeyEvent, "ProcessKeyEvent", "uuubu", "");
|
||||
|
||||
FCITX_OBJECT_VTABLE_METHOD(processKeyEventV2, "ProcessKeyEventV2", "uuubuu",
|
||||
"");
|
||||
|
||||
FCITX_OBJECT_VTABLE_METHOD(processVisibilityEvent, "ProcessVisibilityEvent",
|
||||
"b", "");
|
||||
|
||||
|
@ -143,9 +156,45 @@ private:
|
|||
VirtualKeyboard *parent_;
|
||||
};
|
||||
|
||||
// static
|
||||
bool VirtualKeyboardBackend::isFunctionModeValid(uint32_t functionMode) {
|
||||
return functionMode == static_cast<uint32_t>(FunctionMode::Full) ||
|
||||
functionMode == static_cast<uint32_t>(FunctionMode::Limited);
|
||||
}
|
||||
|
||||
// static
|
||||
bool VirtualKeyboardBackend::shouldProcessKeyEvent(InputContext *inputContext,
|
||||
uint32_t functionMode) {
|
||||
if (!isFunctionModeValid(functionMode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (shouldProcessVirtualKeyboardEvent(
|
||||
inputContext, static_cast<FunctionMode>(functionMode))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return inputContext->isFunctionModeSupported(FunctionMode::Full);
|
||||
}
|
||||
|
||||
// static
|
||||
bool VirtualKeyboardBackend::shouldProcessVirtualKeyboardEvent(
|
||||
InputContext *inputContext, FunctionMode functionMode) {
|
||||
return functionMode == FunctionMode::Limited &&
|
||||
inputContext->isFunctionModeSupported(FunctionMode::Limited);
|
||||
}
|
||||
|
||||
void VirtualKeyboardBackend::processKeyEvent(uint32_t keyval, uint32_t keycode,
|
||||
uint32_t state, bool isRelease,
|
||||
uint32_t time) {
|
||||
processKeyEventV2(keyval, keycode, state, isRelease, time,
|
||||
static_cast<uint32_t>(FunctionMode::Full));
|
||||
}
|
||||
|
||||
void VirtualKeyboardBackend::processKeyEventV2(uint32_t keyval,
|
||||
uint32_t keycode, uint32_t state,
|
||||
bool isRelease, uint32_t time,
|
||||
uint32_t functionMode) {
|
||||
auto *inputContext = parent_->instance()->mostRecentInputContext();
|
||||
if (inputContext == nullptr || !inputContext->hasFocus()) {
|
||||
// TODO: when keyboard is shown but no focused ic, send fake key via
|
||||
|
@ -153,10 +202,21 @@ void VirtualKeyboardBackend::processKeyEvent(uint32_t keyval, uint32_t keycode,
|
|||
return;
|
||||
}
|
||||
|
||||
if (!shouldProcessKeyEvent(inputContext, functionMode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
VirtualKeyboardEvent event(inputContext, isRelease, time);
|
||||
event.setKey(Key(static_cast<KeySym>(keyval), KeyStates(state), keycode));
|
||||
|
||||
auto eventConsumed = inputContext->virtualKeyboardEvent(event);
|
||||
auto eventConsumed = false;
|
||||
if (shouldProcessVirtualKeyboardEvent(
|
||||
inputContext, static_cast<FunctionMode>(functionMode))) {
|
||||
eventConsumed = inputContext->virtualKeyboardEvent(event);
|
||||
} else {
|
||||
eventConsumed = inputContext->keyEvent(*event.toKeyEvent());
|
||||
}
|
||||
|
||||
if (eventConsumed) {
|
||||
return;
|
||||
}
|
||||
|
@ -270,7 +330,12 @@ void VirtualKeyboard::resume() {
|
|||
}));
|
||||
eventHandlers_.emplace_back(instance_->watchEvent(
|
||||
EventType::InputContextKeyEvent, EventWatcherPhase::PreInputMethod,
|
||||
[this](Event &) {
|
||||
[this](Event &event) {
|
||||
const auto &keyEvent = static_cast<KeyEvent &>(event);
|
||||
if (keyEvent.origKey().states().test(KeyState::Virtual)) {
|
||||
return;
|
||||
}
|
||||
|
||||
instance_->setInputMethodMode(InputMethodMode::PhysicalKeyboard);
|
||||
}));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue