Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/lib/fcitx-utils/misc_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ class OrderedSet {
using OrderList = std::list<T>;

public:
using iterator = typename OrderList::iterator;
using const_iterator = typename OrderList::const_iterator;

auto begin() { return order_.begin(); }

auto end() { return order_.end(); }
Expand Down Expand Up @@ -132,6 +135,11 @@ class OrderedSet {
return true;
}

iterator erase(const_iterator iter) {
dict_.erase(*iter);
return order_.erase(iter);
}

const OrderList &order() const { return order_; }

private:
Expand Down
92 changes: 69 additions & 23 deletions src/modules/clipboard/clipboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "fcitx-utils/event.h"
#include "fcitx-utils/eventloopinterface.h"
#include "fcitx-utils/i18n.h"
#include "fcitx-utils/inputbuffer.h"
#include "fcitx-utils/key.h"
#include "fcitx-utils/keysym.h"
#include "fcitx-utils/log.h"
Expand Down Expand Up @@ -70,13 +71,16 @@ FCITX_DEFINE_LOG_CATEGORY(clipboard_log, "clipboard");

class ClipboardState : public InputContextProperty {
public:
ClipboardState(Clipboard *q) : q_(q) {}
ClipboardState(Clipboard *q) : q_(q) { buffer_.setMaxSize(30); }

bool enabled_ = false;
Clipboard *q_;
InputBuffer buffer_;

void reset(InputContext *ic) {
enabled_ = false;
buffer_.clear();
buffer_.shrinkToFit();
ic->inputPanel().reset();
ic->updatePreedit();
ic->updateUserInterface(UserInterfaceComponent::InputPanel);
Expand Down Expand Up @@ -256,16 +260,15 @@ Clipboard::Clipboard(Instance *instance)

auto candidateList = inputContext->inputPanel().candidateList();
if (candidateList) {
int idx = keyEvent.key().digitSelection();
int idx = keyEvent.key().digitSelection(KeyState::Alt);
Comment thread
pslldq marked this conversation as resolved.
if (idx >= 0) {
keyEvent.accept();
if (idx < candidateList->size()) {
candidateList->candidate(idx).select(inputContext);
}
return;
}
if (keyEvent.key().check(FcitxKey_space) ||
keyEvent.key().check(FcitxKey_Return) ||
if (keyEvent.key().check(FcitxKey_Return) ||
keyEvent.key().check(FcitxKey_KP_Enter)) {
keyEvent.accept();
if (!candidateList->empty() &&
Expand Down Expand Up @@ -330,14 +333,44 @@ Clipboard::Clipboard(Instance *instance)
state->reset(inputContext);
return;
}
if (keyEvent.key().check(FcitxKey_Delete) ||
keyEvent.key().check(FcitxKey_BackSpace)) {
Comment thread
pslldq marked this conversation as resolved.
if (keyEvent.key().check(FcitxKey_Delete)) {
keyEvent.accept();
history_.clear();
primary_.clear();
state->reset(inputContext);
return;
}

if (keyEvent.key().check(FcitxKey_BackSpace)) {
event.accept();
if (state->buffer_.empty()) {
state->reset(inputContext);
} else {
if (state->buffer_.backspace()) {
if (state->buffer_.empty()) {
state->reset(inputContext);
} else {
updateUI(inputContext);
}
}
}
return;
}

// check compose first.
auto compose = instance_->processComposeString(
inputContext, keyEvent.key().sym());

// compose is invalid, ignore it.
if (!compose) {
return;
}

if (!compose->empty()) {
state->buffer_.type(*compose);
} else {
state->buffer_.type(Key::keySymToUnicode(keyEvent.key().sym()));
}
event.accept();

updateUI(inputContext);
Expand All @@ -364,20 +397,31 @@ void Clipboard::trigger(InputContext *inputContext) {
updateUI(inputContext);
}
void Clipboard::updateUI(InputContext *inputContext) {
auto *state = inputContext->propertyFor(&factory_);
inputContext->inputPanel().reset();

const auto &search = state->buffer_.userInput();

Text preedit;
preedit.append(search);
if (!state->buffer_.empty()) {
preedit.setCursor(state->buffer_.cursorByChar());
}
inputContext->inputPanel().setPreedit(preedit);

auto candidateList = std::make_unique<CommonCandidateList>();
candidateList->setPageSize(instance_->globalConfig().defaultPageSize());

// Append first item from history_.
auto iter = history_.begin();
if (iter != history_.end()) {
if (iter != history_.end() &&
iter->text.find(search) != std::string::npos) {
candidateList->append<ClipboardCandidateWord>(this, iter->text,
iter->passwordTimestamp);
iter++;
}
// Append primary_, but check duplication first.
if (!primary_.empty()) {
if (!primary_.empty() && primary_.text.find(search) != std::string::npos) {
if (!history_.contains(primary_)) {
candidateList->append<ClipboardCandidateWord>(
this, primary_.text, primary_.passwordTimestamp);
Expand All @@ -388,13 +432,15 @@ void Clipboard::updateUI(InputContext *inputContext) {
if (candidateList->totalSize() >= config_.numOfEntries.value()) {
break;
}
candidateList->append<ClipboardCandidateWord>(this, iter->text,
iter->passwordTimestamp);
if (iter->text.find(search) != std::string::npos) {
candidateList->append<ClipboardCandidateWord>(
this, iter->text, iter->passwordTimestamp);
}
}
candidateList->setSelectionKey(selectionKeys_);
candidateList->setLayoutHint(CandidateLayoutHint::Vertical);

Text auxUp(_("Clipboard (Press BackSpace/Delete to clear history):"));
Comment thread
pslldq marked this conversation as resolved.
Text auxUp(_("Clipboard (Press Delete to clear history):"));
if (!candidateList->totalSize()) {
Text auxDown(_("No clipboard history."));
inputContext->inputPanel().setAuxDown(auxDown);
Expand Down Expand Up @@ -494,20 +540,20 @@ void Clipboard::refreshPasswordTimer() {
minTimestamp = std::min(minTimestamp, primary_.passwordTimestamp);
}

// Not efficient, but we don't have lots of entries anyway.
std::unordered_set<ClipboardEntry> needRemove;
for (const auto &entry : history_) {
if (shouldClearPassword(entry, *config_.clearPasswordAfter)) {
needRemove.insert(entry);
} else if (entry.passwordTimestamp) {
minTimestamp = std::min(minTimestamp, entry.passwordTimestamp);
size_t erasedPasswords = 0;
for (auto iter = history_.begin(); iter != history_.end();) {
if (shouldClearPassword(*iter, *config_.clearPasswordAfter)) {
iter = history_.erase(iter);
++erasedPasswords;
continue;
}
if (iter->passwordTimestamp) {
minTimestamp = std::min(minTimestamp, iter->passwordTimestamp);
}
++iter;
}
FCITX_CLIPBOARD_DEBUG() << "Clear " << needRemove.size()
<< " password(s) in clipboard history.";
for (const auto &entry : needRemove) {
history_.remove(entry);
}
FCITX_CLIPBOARD_DEBUG()
<< "Erased " << erasedPasswords << " password(s) in clipboard history.";

if (minTimestamp != std::numeric_limits<uint64_t>::max()) {
clearPasswordTimer_->setTime(
Expand Down
5 changes: 2 additions & 3 deletions src/modules/clipboard/clipboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,8 @@ FCITX_CONFIGURATION(
KeyListConstrain()};
KeyListOption pastePrimaryKey{
this, "PastePrimaryKey", _("Paste Primary"), {}, KeyListConstrain()};
Option<int, IntConstrain> numOfEntries{this, "Number of entries",
_("Number of entries"), 5,
IntConstrain(3, 30)};
Option<int, IntConstrain> numOfEntries{
this, "Number of entries", _("Number of entries"), 5, IntConstrain(3)};
ConditionalHidden<isAndroid(),
OptionWithAnnotation<bool, ToolTipAnnotation>>
ignorePasswordFromPasswordManager{
Expand Down
Loading