15 #include "focusgroup.h" 16 #include "inputcontext_p.h" 17 #include "inputcontextmanager.h" 26 bool shouldDisablePreeditByDefault(
const std::string &program) {
27 static const std::vector<std::regex> matchers = []() {
28 std::vector<std::regex> matchers;
29 const char *apps = getenv(
"FCITX_NO_PREEDIT_APPS");
31 apps = NO_PREEDIT_APPS;
34 for (
const auto &matcherString : matcherStrings) {
36 matchers.emplace_back(matcherString, std::regex::icase |
37 std::regex::extended |
45 return std::any_of(matchers.begin(), matchers.end(),
46 [&program](
const std::regex ®ex) {
47 return std::regex_match(program, regex);
52 InputContextPrivate::InputContextPrivate(InputContext *q,
53 InputContextManager &manager,
54 const std::string &program)
55 : QPtrHolder(q), manager_(manager), group_(nullptr), inputPanel_(q),
56 statusArea_(q), program_(program),
57 isPreeditEnabled_(manager.isPreeditEnabledByDefault() &&
58 !shouldDisablePreeditByDefault(program)) {}
60 #define RETURN_IF_HAS_NO_FOCUS(...) \ 67 InputContext::InputContext(InputContextManager &manager,
68 const std::string &program)
69 : d_ptr(
std::make_unique<InputContextPrivate>(this, manager, program)) {
70 manager.registerInputContext(*
this);
73 InputContext::~InputContext() { assert(d_ptr->destroyed_); }
84 assert(!d->destroyed_);
86 d->group_->removeInputContext(
this);
89 d->manager_.unregisterInputContext(*
this);
105 return d->group_ ? d->group_->display() :
"";
110 return d->cursorRect_;
120 auto *factory = d->manager_.factoryForName(name);
124 return d->manager_.property(*
this, factory);
130 return d->manager_.property(*
this, factory);
135 auto *factory = d->manager_.factoryForName(name);
139 updateProperty(factory);
144 auto *
property = d->manager_.property(*
this, factory);
145 if (!property->needCopy()) {
148 d->manager_.propagateProperty(*
this, factory);
151 bool InputContext::isVirtualKeyboardVisible()
const {
153 if (
auto *instance = d->manager_.instance()) {
154 return instance->userInterfaceManager().isVirtualKeyboardVisible();
159 void InputContext::showVirtualKeyboard()
const {
161 if (
auto *instance = d->manager_.instance()) {
162 return instance->userInterfaceManager().showVirtualKeyboard();
166 void InputContext::hideVirtualKeyboard()
const {
168 if (
auto *instance = d->manager_.instance()) {
169 return instance->userInterfaceManager().hideVirtualKeyboard();
173 bool InputContext::clientControlVirtualkeyboardShow()
const {
175 return d->clientControlVirtualkeyboardShow_;
178 void InputContext::setClientControlVirtualkeyboardShow(
bool show) {
180 d->clientControlVirtualkeyboardShow_ = show;
183 bool InputContext::clientControlVirtualkeyboardHide()
const {
185 return d->clientControlVirtualkeyboardHide_;
188 void InputContext::setClientControlVirtualkeyboardHide(
bool hide) {
190 d->clientControlVirtualkeyboardHide_ = hide;
194 if (!isPreeditEnabled) {
195 flag = flag.unset(CapabilityFlag::Preedit)
196 .unset(CapabilityFlag::FormattedPreedit);
203 if (d->capabilityFlags_ == flags) {
206 const auto oldFlags = capabilityFlags();
207 auto newFlags = calculateFlags(flags, d->isPreeditEnabled_);
208 if (oldFlags != newFlags) {
211 d->capabilityFlags_ = flags;
212 if (oldFlags != newFlags) {
219 return calculateFlags(d->capabilityFlags_, d->isPreeditEnabled_);
224 if (enable == d->isPreeditEnabled_) {
227 const auto oldFlags = capabilityFlags();
228 auto newFlags = calculateFlags(d->capabilityFlags_, enable);
229 if (oldFlags != newFlags) {
232 d->isPreeditEnabled_ = enable;
233 if (oldFlags != newFlags) {
240 return d->isPreeditEnabled_;
247 if (d->cursorRect_ == rect && d->scale_ == scale) {
250 d->cursorRect_ = rect;
259 d->group_->removeInputContext(
this);
263 d->group_->addInputContext(
this);
275 d->group_->setFocusedInputContext(
this);
284 if (d->group_->focusedInputContext() ==
this) {
285 d->group_->setFocusedInputContext(
nullptr);
297 void InputContext::setHasFocus(
bool hasFocus) {
299 if (hasFocus == d->hasFocus_) {
302 d->hasFocus_ = hasFocus;
303 d->manager_.notifyFocus(*
this, d->hasFocus_);
314 RETURN_IF_HAS_NO_FOCUS(
false);
315 decltype(std::chrono::steady_clock::now()) start;
317 if (::keyTrace().checkLogLevel(LogLevel::Debug)) {
318 start = std::chrono::steady_clock::now();
320 auto result = d->postEvent(event);
321 FCITX_KEYTRACE() <<
"KeyEvent handling time: " 322 << std::chrono::duration_cast<std::chrono::milliseconds>(
323 std::chrono::steady_clock::now() - start)
325 <<
"ms result:" << result;
331 RETURN_IF_HAS_NO_FOCUS(
false);
332 decltype(std::chrono::steady_clock::now()) start;
334 if (::keyTrace().checkLogLevel(LogLevel::Debug)) {
335 start = std::chrono::steady_clock::now();
337 auto result = d->postEvent(event);
338 FCITX_KEYTRACE() <<
"VirtualKeyboardEvent handling time: " 339 << std::chrono::duration_cast<std::chrono::milliseconds>(
340 std::chrono::steady_clock::now() - start)
342 <<
"ms result:" << result;
348 RETURN_IF_HAS_NO_FOCUS();
356 RETURN_IF_HAS_NO_FOCUS();
362 return d->surroundingText_;
367 return d->surroundingText_;
377 if (d->blockEventToClient_ == block) {
378 throw std::invalid_argument(
379 "setBlockEventToClient has invalid argument. Probably a bug in the " 382 d->blockEventToClient_ = block;
384 d->deliverBlockedEvents();
388 bool InputContext::hasPendingEvents()
const {
390 return !d->blockedEvents_.empty();
395 if (d->blockedEvents_.empty()) {
400 if (std::any_of(d->blockedEvents_.begin(), d->blockedEvents_.end(),
401 [](
const auto &event) {
402 return event->type() !=
403 EventType::InputContextUpdatePreedit;
411 return !inputPanel().clientPreedit().toString().empty();
416 if (
auto *instance = d->manager_.instance()) {
417 auto newString = instance->commitFilter(
this, text);
428 throw std::invalid_argument(text);
431 if (
auto *instance = d->manager_.instance()) {
432 auto newString = instance->commitFilter(
this, text);
441 deleteSurroundingTextImpl(offset, size);
451 if (!capabilityFlags().test(CapabilityFlag::Preedit)) {
455 const bool preeditIsEmpty = inputPanel().clientPreedit().empty();
456 if (preeditIsEmpty && d->lastPreeditUpdateIsEmpty_) {
459 d->lastPreeditUpdateIsEmpty_ = preeditIsEmpty;
471 return d->inputPanel_;
476 return d->inputPanel_;
481 return d->statusArea_;
486 return d->statusArea_;
491 InputContextV2::~InputContextV2() =
default;
493 InputContextEventBlocker::InputContextEventBlocker(
InputContext *inputContext)
494 : inputContext_(inputContext->watch()) {
498 InputContextEventBlocker::~InputContextEventBlocker() {
499 if (
auto *ic = inputContext_.get()) {
500 ic->setBlockEventToClient(
false);
void focusOut()
Called when input context losts the input focus.
CapabilityFlags capabilityFlags() const
Returns the current capability flags.
void deleteSurroundingText(int offset, unsigned int size)
Ask client to delete a range of surrounding text.
double scaleFactor() const
Return the client scale factor.
virtual void updateClientSideUIImpl()
Send the UI update to client.
void created()
Notifies the creation of input context.
const ICUUID & uuid() const
Returns the uuid of this input context.
size_t length(Iter start, Iter end)
Return the number UTF-8 characters in the string iterator range.
C++ Utility functions for handling utf8 strings.
void setEnablePreedit(bool enable)
Override the preedit hint from client.
std::vector< std::string > split(std::string_view str, std::string_view delim, SplitBehavior behavior)
Split the string by delim.
InputContextProperty * property(const std::string &name)
Returns the input context property by name.
bool hasFocus() const
Returns whether the input context holds the input focus.
void reset()
Called when input context state need to be reset.
Manager class for user interface.
void updateProperty(const std::string &name)
Notifies the change of a given input context property.
const std::string & program() const
Returns the program name of input context.
FocusGroup * focusGroup() const
Returns the current focus group of input context.
void setCapabilityFlags(CapabilityFlags flags)
Update the capability flags of the input context.
void updatePreedit()
Notifies client about changes in clientPreedit.
void destroy()
Notifies the destruction of the input context.
Class represents the current state of surrounding text of an input context.
void setCursorRect(Rect rect)
Update the current cursor rect of the input context.
void focusIn()
Called When input context gains the input focus.
std::string display() const
Returns the display server of the client.
Status area represent a list of actions and action may have sub actions.
Factory class for input context property.
bool keyEvent(KeyEvent &event)
Send a key event to current input context.
void setFocusGroup(FocusGroup *group)
Set the focus group of this input context.
InputPanel & inputPanel()
Returns the associated input panel.
void commitStringWithCursor(const std::string &text, size_t cursor)
Commit a string to application with a cursor location after commit.
std::string_view frontendName() const
Return the frontend name.
bool hasPendingEventsStrictOrder() const
Has pending event that need to use key order fix.
Class provides bit flag support for Enum.
Event for commit string with cursor.
StatusArea & statusArea()
Returns the associated StatusArea.
bool virtualKeyboardEvent(VirtualKeyboardEvent &event)
Send a virtual keyboard event to current input context.
SurroundingText & surroundingText()
Returns the mutable surrounding text of the input context.
An input context represents a client of Fcitx.
void updateUserInterface(UserInterfaceComponent component, bool immediate=false)
Notifies UI about changes in user interface.
void invokeAction(InvokeActionEvent &event)
Invoke an action on the preedit.
void updateSurroundingText()
Notifies the surrounding text modification from the client.
This is a class that designed to store state that is specific to certain input context.
void commitString(const std::string &text)
Commit a string to the client.
void forwardKey(const Key &rawKey, bool isRelease=false, int time=0)
Send a key event to client.
const Rect & cursorRect() const
Returns the cursor position of the client.
void setBlockEventToClient(bool block)
Prevent event deliver to input context, and re-send the event later.
bool isPreeditEnabled() const
Check if preedit is manually disabled.