Skip to content

Commit 7f9b056

Browse files
committed
refactor(editor): extract helper class key_binding_processor
1 parent 99573e3 commit 7f9b056

File tree

5 files changed

+151
-78
lines changed

5 files changed

+151
-78
lines changed

src/rime/common.h

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
// call a pointer to member function on this
3636
#define RIME_THIS_CALL(f) (this->*(f))
3737

38+
#define RIME_THIS_CALL_AS(T, f) ((T*)this->*(f))
39+
3840
namespace rime {
3941

4042
using std::function;

src/rime/gear/editor.cc

+9-71
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,19 @@
44
//
55
// 2011-10-23 GONG Chen <chen.sst@gmail.com>
66
//
7-
#include <cctype>
87
#include <rime/common.h>
9-
#include <rime/composition.h>
108
#include <rime/config.h>
119
#include <rime/context.h>
1210
#include <rime/engine.h>
1311
#include <rime/schema.h>
1412
#include <rime/key_table.h>
1513
#include <rime/gear/editor.h>
14+
#include <rime/gear/key_binding_processor.h>
1615
#include <rime/gear/translator_commons.h>
1716

1817
namespace rime {
1918

20-
static struct EditorActionDef {
21-
const char* name;
22-
Editor::HandlerPtr action;
23-
} editor_action_definitions[] = {
19+
static Editor::ActionDef editor_action_definitions[] = {
2420
{ "confirm", &Editor::Confirm },
2521
{ "toggle_selection", &Editor::ToggleSelection },
2622
{ "commit_comment", &Editor::CommitComment },
@@ -33,7 +29,7 @@ static struct EditorActionDef {
3329
{ "delete_candidate", &Editor::DeleteCandidate },
3430
{ "delete", &Editor::DeleteChar },
3531
{ "cancel", &Editor::CancelComposition },
36-
{ "noop", nullptr }
32+
Editor::kActionNoop
3733
};
3834

3935
static struct EditorCharHandlerDef {
@@ -45,7 +41,8 @@ static struct EditorCharHandlerDef {
4541
{ "noop", nullptr }
4642
};
4743

48-
Editor::Editor(const Ticket& ticket, bool auto_commit) : Processor(ticket) {
44+
Editor::Editor(const Ticket& ticket, bool auto_commit)
45+
: Processor(ticket), KeyBindingProcessor(editor_action_definitions) {
4946
engine_->context()->set_option("_auto_commit", auto_commit);
5047
}
5148

@@ -55,27 +52,9 @@ ProcessResult Editor::ProcessKeyEvent(const KeyEvent& key_event) {
5552
int ch = key_event.keycode();
5653
Context* ctx = engine_->context();
5754
if (ctx->IsComposing()) {
58-
if (Accept(key_event)) {
59-
return kAccepted;
60-
}
61-
if (key_event.ctrl() || key_event.alt()) {
62-
return kNoop;
63-
}
64-
if (key_event.shift()) {
65-
KeyEvent shift_as_ctrl{
66-
key_event.keycode(),
67-
(key_event.modifier() & ~kShiftMask) | kControlMask
68-
};
69-
if (Accept(shift_as_ctrl)) {
70-
return kAccepted;
71-
}
72-
KeyEvent remove_shift{
73-
key_event.keycode(),
74-
key_event.modifier() & ~kShiftMask
75-
};
76-
if (Accept(remove_shift)) {
77-
return kAccepted;
78-
}
55+
auto result = KeyBindingProcessor::ProcessKeyEvent(key_event, ctx);
56+
if (result != kNoop) {
57+
return result;
7958
}
8059
}
8160
if (char_handler_ &&
@@ -89,53 +68,12 @@ ProcessResult Editor::ProcessKeyEvent(const KeyEvent& key_event) {
8968
return kNoop;
9069
}
9170

92-
bool Editor::Accept(const KeyEvent& key_event) {
93-
auto binding = key_bindings_.find(key_event);
94-
if (binding != key_bindings_.end()) {
95-
auto action = binding->second;
96-
RIME_THIS_CALL(action)(engine_->context());
97-
DLOG(INFO) << "editor action key accepted: " << key_event.repr();
98-
return true;
99-
}
100-
return false;
101-
}
102-
103-
void Editor::Bind(KeyEvent key_event, HandlerPtr action) {
104-
if (action) {
105-
key_bindings_[key_event] = action;
106-
}
107-
else {
108-
key_bindings_.erase(key_event);
109-
}
110-
}
111-
11271
void Editor::LoadConfig() {
11372
if (!engine_) {
11473
return;
11574
}
11675
Config* config = engine_->schema()->config();
117-
if (auto bindings = config->GetMap("editor/bindings")) {
118-
for (auto it = bindings->begin(); it != bindings->end(); ++it) {
119-
auto value = As<ConfigValue>(it->second);
120-
if (!value) {
121-
continue;
122-
}
123-
auto* p = editor_action_definitions;
124-
while (p->action && p->name != value->str()) {
125-
++p;
126-
}
127-
if (!p->action && p->name != value->str()) {
128-
LOG(WARNING) << "invalid editor action: " << value->str();
129-
continue;
130-
}
131-
KeyEvent ke;
132-
if (!ke.Parse(it->first)) {
133-
LOG(WARNING) << "invalid edit key: " << it->first;
134-
continue;
135-
}
136-
Bind(ke, p->action);
137-
}
138-
}
76+
KeyBindingProcessor::LoadConfig(config, "editor");
13977
if (auto value = config->GetValue("editor/char_handler")) {
14078
auto* p = editor_char_handler_definitions;
14179
while (p->action && p->name != value->str()) {

src/rime/gear/editor.h

+2-7
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,16 @@
1111
#include <rime/component.h>
1212
#include <rime/key_event.h>
1313
#include <rime/processor.h>
14+
#include <rime/gear/key_binding_processor.h>
1415

1516
namespace rime {
1617

1718
class Context;
1819

19-
class Editor : public Processor {
20+
class Editor : public Processor, public KeyBindingProcessor<Editor> {
2021
public:
21-
typedef void Handler(Context* ctx);
2222
typedef ProcessResult CharHandler(Context* ctx, int ch);
23-
using HandlerPtr = void (Editor::*)(Context* ctx);
2423
using CharHandlerPtr = ProcessResult (Editor::*)(Context* ctx, int ch);
25-
using KeyBindings = map<KeyEvent, HandlerPtr>;
2624

2725
Editor(const Ticket& ticket, bool auto_commit);
2826
ProcessResult ProcessKeyEvent(const KeyEvent& key_event);
@@ -44,11 +42,8 @@ class Editor : public Processor {
4442
CharHandler AddToInput;
4543

4644
protected:
47-
bool Accept(const KeyEvent& key_event);
48-
void Bind(KeyEvent key_event, HandlerPtr action);
4945
void LoadConfig();
5046

51-
KeyBindings key_bindings_;
5247
CharHandlerPtr char_handler_ = nullptr;
5348
};
5449

src/rime/gear/key_binding_processor.h

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//
2+
// Copyright RIME Developers
3+
// Distributed under the BSD License
4+
//
5+
#ifndef RIME_KEY_BINDING_PROCESSOR_H_
6+
#define RIME_KEY_BINDING_PROCESSOR_H_
7+
8+
#include <rime/common.h>
9+
#include <rime/key_event.h>
10+
#include <rime/processor.h>
11+
12+
namespace rime {
13+
14+
class Config;
15+
class Context;
16+
17+
template <class T>
18+
class KeyBindingProcessor {
19+
public:
20+
typedef void Handler(Context* ctx);
21+
using HandlerPtr = void (T::*)(Context* ctx);
22+
struct ActionDef {
23+
const char* name;
24+
HandlerPtr action;
25+
};
26+
27+
static const ActionDef kActionNoop;
28+
29+
KeyBindingProcessor(ActionDef* action_definitions)
30+
: action_definitions_(action_definitions) {}
31+
ProcessResult ProcessKeyEvent(const KeyEvent& key_event, Context* ctx);
32+
bool Accept(const KeyEvent& key_event, Context* ctx);
33+
void Bind(KeyEvent key_event, HandlerPtr action);
34+
void LoadConfig(Config* config, const string& section);
35+
36+
private:
37+
ActionDef* action_definitions_;
38+
39+
using KeyBindingMap = map<KeyEvent, HandlerPtr>;
40+
KeyBindingMap key_bindings_;
41+
};
42+
43+
} // namespace rime
44+
45+
#include <rime/gear/key_binding_processor_impl.h>
46+
47+
#endif // RIME_KEY_BINDING_PROCESSOR_H_
+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
//
2+
// Copyright RIME Developers
3+
// Distributed under the BSD License
4+
//
5+
6+
namespace rime {
7+
8+
template <class T>
9+
const typename KeyBindingProcessor<T>::ActionDef
10+
KeyBindingProcessor<T>::kActionNoop = { "noop", nullptr };
11+
12+
template <class T>
13+
ProcessResult KeyBindingProcessor<T>::ProcessKeyEvent(
14+
const KeyEvent& key_event, Context* ctx) {
15+
// exact match
16+
if (Accept(key_event, ctx)) {
17+
return kAccepted;
18+
}
19+
// fallback: compatible modifiers
20+
if (key_event.ctrl() || key_event.alt()) {
21+
return kNoop;
22+
}
23+
if (key_event.shift()) {
24+
KeyEvent shift_as_ctrl{
25+
key_event.keycode(),
26+
(key_event.modifier() & ~kShiftMask) | kControlMask
27+
};
28+
if (Accept(shift_as_ctrl, ctx)) {
29+
return kAccepted;
30+
}
31+
KeyEvent ignore_shift{
32+
key_event.keycode(),
33+
key_event.modifier() & ~kShiftMask
34+
};
35+
if (Accept(ignore_shift, ctx)) {
36+
return kAccepted;
37+
}
38+
}
39+
// not handled
40+
return kNoop;
41+
}
42+
43+
template <class T>
44+
bool KeyBindingProcessor<T>::Accept(const KeyEvent& key_event, Context* ctx) {
45+
auto binding = key_bindings_.find(key_event);
46+
if (binding != key_bindings_.end()) {
47+
auto action = binding->second;
48+
RIME_THIS_CALL_AS(T, action)(ctx);
49+
DLOG(INFO) << "action key accepted: " << key_event.repr();
50+
return true;
51+
}
52+
return false;
53+
}
54+
55+
template <class T>
56+
void KeyBindingProcessor<T>::Bind(KeyEvent key_event, HandlerPtr action) {
57+
if (action) {
58+
key_bindings_[key_event] = action;
59+
}
60+
else {
61+
key_bindings_.erase(key_event);
62+
}
63+
}
64+
65+
template <class T>
66+
void KeyBindingProcessor<T>::LoadConfig(Config* config, const string& section) {
67+
if (auto bindings = config->GetMap(section + "/bindings")) {
68+
for (auto it = bindings->begin(); it != bindings->end(); ++it) {
69+
auto value = As<ConfigValue>(it->second);
70+
if (!value) {
71+
continue;
72+
}
73+
auto* p = action_definitions_;
74+
while (p->action && p->name != value->str()) {
75+
++p;
76+
}
77+
if (!p->action && p->name != value->str()) {
78+
LOG(WARNING) << "[" << section << "] invalid action: " << value->str();
79+
continue;
80+
}
81+
KeyEvent ke;
82+
if (!ke.Parse(it->first)) {
83+
LOG(WARNING) << "[" << section << "] invalid key: " << it->first;
84+
continue;
85+
}
86+
Bind(ke, p->action);
87+
}
88+
}
89+
}
90+
91+
} // namespace rime

0 commit comments

Comments
 (0)