Skip to content

Commit

Permalink
refactor(navigator): key bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
lotem committed Jun 12, 2018
1 parent 7f9b056 commit 122893d
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 55 deletions.
5 changes: 2 additions & 3 deletions src/rime/gear/key_binding_processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@
#define RIME_KEY_BINDING_PROCESSOR_H_

#include <rime/common.h>
#include <rime/config.h>
#include <rime/context.h>
#include <rime/key_event.h>
#include <rime/processor.h>

namespace rime {

class Config;
class Context;

template <class T>
class KeyBindingProcessor {
public:
Expand Down
123 changes: 78 additions & 45 deletions src/rime/gear/navigator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,63 +11,96 @@
#include <rime/engine.h>
#include <rime/key_event.h>
#include <rime/key_table.h>
#include <rime/schema.h>
#include <rime/gear/navigator.h>
#include <rime/gear/translator_commons.h>

namespace rime {

static Navigator::ActionDef navigation_actions[] = {
{ "rewind", &Navigator::Rewind },
{ "left_by_char", &Navigator::LeftByChar },
{ "right_by_char", &Navigator::RightByChar },
{ "left_by_syllable", &Navigator::LeftBySyllable },
{ "right_by_syllable", &Navigator::RightBySyllable },
{ "home", &Navigator::Home },
{ "end", &Navigator::End },
Navigator::kActionNoop
};

Navigator::Navigator(const Ticket& ticket)
: Processor(ticket), KeyBindingProcessor<Navigator>(navigation_actions) {
// Default key binding.
Bind({XK_Left, 0}, &Navigator::Rewind);
Bind({XK_Left, kControlMask}, &Navigator::LeftBySyllable);
Bind({XK_KP_Left, 0}, &Navigator::LeftByChar);
Bind({XK_Right, 0}, &Navigator::RightByChar);
Bind({XK_Right, kControlMask}, &Navigator::RightBySyllable);
Bind({XK_KP_Right, 0}, &Navigator::RightByChar);
Bind({XK_Home, 0}, &Navigator::Home);
Bind({XK_KP_Home, 0}, &Navigator::Home);
Bind({XK_End, 0}, &Navigator::End);
Bind({XK_KP_End, 0}, &Navigator::End);

Config* config = engine_->schema()->config();
KeyBindingProcessor::LoadConfig(config, "navigator");
}

ProcessResult Navigator::ProcessKeyEvent(const KeyEvent& key_event) {
if (key_event.release())
return kNoop;
Context* ctx = engine_->context();
if (!ctx->IsComposing())
return kNoop;
int ch = key_event.keycode();
if (ch == XK_Left || ch == XK_KP_Left) {
BeginMove(ctx);
if (key_event.ctrl() || key_event.shift()) {
size_t confirmed_pos = ctx->composition().GetConfirmedPosition();
JumpLeft(ctx, confirmed_pos) || End(ctx);
}
else {
// take a jump leftwards when there are multiple spans,
// but not from the middle of a span.
(spans_.Count() > 1 &&
spans_.HasVertex(ctx->caret_pos())
? JumpLeft(ctx) : Left(ctx)) || End(ctx);
}
return kAccepted;
}
if (ch == XK_Right || ch == XK_KP_Right) {
BeginMove(ctx);
if (key_event.ctrl() || key_event.shift()) {
size_t confirmed_pos = ctx->composition().GetConfirmedPosition();
JumpRight(ctx, confirmed_pos) || End(ctx);
}
else {
Right(ctx) || Home(ctx);
}
return kAccepted;
}
if (ch == XK_Home || ch == XK_KP_Home) {
BeginMove(ctx);
Home(ctx);
return kAccepted;
}
if (ch == XK_End || ch == XK_KP_End) {
BeginMove(ctx);
End(ctx);
return kAccepted;
}
// not handled
return kNoop;
return KeyBindingProcessor::ProcessKeyEvent(key_event, ctx);
}

void Navigator::LeftBySyllable(Context* ctx) {
BeginMove(ctx);
size_t confirmed_pos = ctx->composition().GetConfirmedPosition();
JumpLeft(ctx, confirmed_pos) || GoToEnd(ctx);
}

void Navigator::LeftByChar(Context* ctx) {
BeginMove(ctx);
MoveLeft(ctx) || GoToEnd(ctx);
}

void Navigator::Rewind(Context* ctx) {
BeginMove(ctx);
// take a jump leftwards when there are multiple spans,
// but not from the middle of a span.
(
spans_.Count() > 1 && spans_.HasVertex(ctx->caret_pos())
? JumpLeft(ctx) : MoveLeft(ctx)
) || GoToEnd(ctx);
}

void Navigator::RightBySyllable(Context* ctx) {
BeginMove(ctx);
size_t confirmed_pos = ctx->composition().GetConfirmedPosition();
JumpRight(ctx, confirmed_pos) || GoToEnd(ctx);
}

void Navigator::RightByChar(Context* ctx) {
BeginMove(ctx);
MoveRight(ctx) || GoHome(ctx);
}

void Navigator::Home(Context* ctx) {
BeginMove(ctx);
GoHome(ctx);
}

void Navigator::End(Context* ctx) {
BeginMove(ctx);
GoToEnd(ctx);
}

void Navigator::BeginMove(Context* ctx) {
ctx->ConfirmPreviousSelection();
// update spans
size_t caret_pos = ctx->caret_pos();
if (input_ != ctx->input() || caret_pos > spans_.end()) {
if (input_ != ctx->input() || ctx->caret_pos() > spans_.end()) {
input_ = ctx->input();
spans_.Clear();
for (const auto &seg : ctx->composition()) {
Expand Down Expand Up @@ -109,7 +142,7 @@ bool Navigator::JumpRight(Context* ctx, size_t start_pos) {
return false;
}

bool Navigator::Left(Context* ctx) {
bool Navigator::MoveLeft(Context* ctx) {
DLOG(INFO) << "navigate left.";
size_t caret_pos = ctx->caret_pos();
if (caret_pos == 0)
Expand All @@ -118,7 +151,7 @@ bool Navigator::Left(Context* ctx) {
return true;
}

bool Navigator::Right(Context* ctx) {
bool Navigator::MoveRight(Context* ctx) {
DLOG(INFO) << "navigate right.";
size_t caret_pos = ctx->caret_pos();
if (caret_pos >= ctx->input().length())
Expand All @@ -127,7 +160,7 @@ bool Navigator::Right(Context* ctx) {
return true;
}

bool Navigator::Home(Context* ctx) {
bool Navigator::GoHome(Context* ctx) {
DLOG(INFO) << "navigate home.";
size_t caret_pos = ctx->caret_pos();
const Composition& comp = ctx->composition();
Expand All @@ -151,7 +184,7 @@ bool Navigator::Home(Context* ctx) {
return false;
}

bool Navigator::End(Context* ctx) {
bool Navigator::GoToEnd(Context* ctx) {
DLOG(INFO) << "navigate end.";
size_t end_pos = ctx->input().length();
if (ctx->caret_pos() != end_pos) {
Expand Down
23 changes: 16 additions & 7 deletions src/rime/gear/navigator.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,33 @@
#include <rime/common.h>
#include <rime/component.h>
#include <rime/processor.h>
#include <rime/gear/key_binding_processor.h>
#include <rime/gear/translator_commons.h>

namespace rime {

class Navigator : public Processor {
class Navigator : public Processor, public KeyBindingProcessor<Navigator> {
public:
Navigator(const Ticket& ticket) : Processor(ticket) {}
explicit Navigator(const Ticket& ticket);

virtual ProcessResult ProcessKeyEvent(const KeyEvent& key_event);
ProcessResult ProcessKeyEvent(const KeyEvent& key_event) override;

Handler Rewind;
Handler LeftByChar;
Handler RightByChar;
Handler LeftBySyllable;
Handler RightBySyllable;
Handler Home;
Handler End;

private:
void BeginMove(Context* ctx);
bool JumpLeft(Context* ctx, size_t start_pos = 0);
bool JumpRight(Context* ctx, size_t start_pos = 0);
bool Left(Context* ctx);
bool Right(Context* ctx);
bool Home(Context* ctx);
bool End(Context* ctx);
bool MoveLeft(Context* ctx);
bool MoveRight(Context* ctx);
bool GoHome(Context* ctx);
bool GoToEnd(Context* ctx);

string input_;
Spans spans_;
Expand Down

0 comments on commit 122893d

Please sign in to comment.