Skip to content

Commit f0a8b64

Browse files
authored
Use TextInputModel's composing (#171)
* Use composing methods of TextInputModel in preedit events callback. * Make Implementations about editing text simpler. * Remove unnecessary public methods of TizenInputMethodContext. * Fix a bug that didn't reset IMF-context when the selection base changed Signed-off-by: Boram Bae <[email protected]>
1 parent 4f03173 commit f0a8b64

File tree

4 files changed

+194
-170
lines changed

4 files changed

+194
-170
lines changed

shell/platform/tizen/channels/text_input_channel.cc

Lines changed: 91 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -63,59 +63,63 @@ TextInputChannel::TextInputChannel(
6363
HandleMethodCall(call, std::move(result));
6464
});
6565

66-
// Set input method callbacks
67-
input_method_context_->SetOnCommitCallback([this](std::string str) -> void {
68-
FT_LOG(Debug) << "OnCommit: " << str;
69-
text_editing_context_.edit_status_ = EditStatus::kCommit;
70-
ConsumeLastPreedit();
71-
active_model_->AddText(str);
72-
SendStateUpdate(*active_model_);
66+
// Set input method callbacks.
67+
input_method_context_->SetOnPreeditStart([this]() {
68+
FT_LOG(Debug) << "onPreeditStart";
69+
text_editing_context_.edit_status_ = EditStatus::kPreeditStart;
70+
active_model_->BeginComposing();
7371
});
7472

75-
input_method_context_->SetOnPreeditCallback(
73+
input_method_context_->SetOnPreeditChanged(
7674
[this](std::string str, int cursor_pos) -> void {
77-
text_editing_context_.edit_status_ = EditStatus::kPreeditStart;
78-
if (str.compare("") == 0) {
79-
text_editing_context_.edit_status_ = EditStatus::kPreeditEnd;
75+
FT_LOG(Debug) << "onPreedit: str[" << str << "] cursor_pos["
76+
<< cursor_pos << "]";
77+
if (str == "") {
78+
// Enter pre-edit end stage.
79+
return;
8080
}
81+
active_model_->UpdateComposingText(str);
82+
SendStateUpdate(*active_model_);
83+
});
8184

82-
if (text_editing_context_.edit_status_ == EditStatus::kPreeditStart ||
83-
(text_editing_context_.edit_status_ == EditStatus::kPreeditEnd &&
84-
// For tv, fix me
85-
text_editing_context_.last_handled_ecore_event_keyname_.compare(
86-
"Return") != 0)) {
87-
text_editing_context_.last_handled_ecore_event_keyname_ = "";
88-
ConsumeLastPreedit();
89-
}
85+
input_method_context_->SetOnPreeditEnd([this]() {
86+
text_editing_context_.edit_status_ = EditStatus::kPreeditEnd;
87+
FT_LOG(Debug) << "onPreeditEnd";
9088

91-
text_editing_context_.has_preedit_ = false;
92-
if (text_editing_context_.edit_status_ == EditStatus::kPreeditStart) {
93-
text_editing_context_.preedit_start_pos_ =
94-
active_model_->selection().base();
95-
active_model_->AddText(str);
96-
text_editing_context_.preedit_end_pos_ =
97-
active_model_->selection().base();
98-
text_editing_context_.has_preedit_ = true;
99-
SendStateUpdate(*active_model_);
100-
FT_LOG(Debug) << "Preedit start position: "
101-
<< text_editing_context_.preedit_start_pos_
102-
<< ", end position: "
103-
<< text_editing_context_.preedit_end_pos_;
104-
}
105-
});
89+
// Delete preedit-string, it will be committed.
90+
int count = active_model_->composing_range().extent() -
91+
active_model_->composing_range().base();
10692

107-
input_method_context_->SetOnInputPannelStateChangedCallback(
108-
[this](int state) {
109-
if (state == ECORE_IMF_INPUT_PANEL_STATE_HIDE) {
110-
// Fallback for HW back-key
111-
input_method_context_->HideInputPannel();
112-
input_method_context_->ResetInputMethodContext();
113-
ResetTextEditingContext();
114-
is_software_keyboard_showing_ = false;
115-
} else {
116-
is_software_keyboard_showing_ = true;
117-
}
118-
});
93+
active_model_->CommitComposing();
94+
active_model_->EndComposing();
95+
96+
active_model_->DeleteSurrounding(-count, count);
97+
98+
SendStateUpdate(*active_model_);
99+
});
100+
101+
input_method_context_->SetOnCommit([this](std::string str) -> void {
102+
FT_LOG(Debug) << "OnCommit: str[" << str << "]";
103+
text_editing_context_.edit_status_ = EditStatus::kCommit;
104+
active_model_->AddText(str);
105+
if (active_model_->composing()) {
106+
active_model_->CommitComposing();
107+
active_model_->EndComposing();
108+
}
109+
SendStateUpdate(*active_model_);
110+
});
111+
112+
input_method_context_->SetOnInputPannelStateChanged([this](int state) {
113+
if (state == ECORE_IMF_INPUT_PANEL_STATE_HIDE) {
114+
// Fallback for HW back-key.
115+
input_method_context_->HideInputPannel();
116+
input_method_context_->ResetInputMethodContext();
117+
ResetTextEditingContext();
118+
is_software_keyboard_showing_ = false;
119+
} else {
120+
is_software_keyboard_showing_ = true;
121+
}
122+
});
119123
}
120124

121125
TextInputChannel::~TextInputChannel() {}
@@ -125,7 +129,7 @@ bool TextInputChannel::SendKeyEvent(Ecore_Event_Key* key, bool is_down) {
125129
return false;
126130
}
127131

128-
if (!FilterEvent(key) && !text_editing_context_.has_preedit_) {
132+
if (!FilterEvent(key)) {
129133
HandleUnfilteredEvent(key);
130134
}
131135

@@ -136,7 +140,7 @@ void TextInputChannel::HandleMethodCall(
136140
const MethodCall<rapidjson::Document>& method_call,
137141
std::unique_ptr<MethodResult<rapidjson::Document>> result) {
138142
const std::string& method = method_call.method_name();
139-
FT_LOG(Debug) << "Handle a method: " << method;
143+
FT_LOG(Debug) << "method: " << method;
140144

141145
if (method.compare(kShowMethod) == 0) {
142146
input_method_context_->ShowInputPannel();
@@ -194,6 +198,9 @@ void TextInputChannel::HandleMethodCall(
194198

195199
active_model_ = std::make_unique<TextInputModel>();
196200
} else if (method.compare(kSetEditingStateMethod) == 0) {
201+
input_method_context_->ResetInputMethodContext();
202+
ResetTextEditingContext();
203+
197204
if (!method_call.arguments() || method_call.arguments()->IsNull()) {
198205
result->Error(kBadArgumentError, "Method invoked without args");
199206
return;
@@ -224,10 +231,34 @@ void TextInputChannel::HandleMethodCall(
224231
"Selection base/extent values invalid.");
225232
return;
226233
}
234+
auto selection_base_value = selection_base->value.GetInt();
235+
auto selection_extent_value = selection_extent->value.GetInt();
227236

228237
active_model_->SetText(text->value.GetString());
229-
active_model_->SetSelection(TextRange(selection_base->value.GetInt(),
230-
selection_extent->value.GetInt()));
238+
active_model_->SetSelection(
239+
TextRange(selection_base_value, selection_extent_value));
240+
241+
auto composing_base = args.FindMember(kComposingBaseKey);
242+
auto composing_extent = args.FindMember(kComposingBaseKey);
243+
auto composing_base_value = composing_base != args.MemberEnd()
244+
? composing_base->value.GetInt()
245+
: -1;
246+
auto composing_extent_value = composing_extent != args.MemberEnd()
247+
? composing_extent->value.GetInt()
248+
: -1;
249+
250+
if (composing_base_value == -1 && composing_extent_value == -1) {
251+
active_model_->EndComposing();
252+
} else {
253+
size_t composing_start =
254+
std::min(composing_base_value, composing_extent_value);
255+
size_t cursor_offset = selection_base_value - composing_start;
256+
257+
active_model_->SetComposingRange(
258+
flutter::TextRange(composing_base_value, composing_extent_value),
259+
cursor_offset);
260+
}
261+
SendStateUpdate(*active_model_);
231262
} else {
232263
result->NotImplemented();
233264
return;
@@ -244,8 +275,14 @@ void TextInputChannel::SendStateUpdate(const TextInputModel& model) {
244275

245276
TextRange selection = model.selection();
246277
rapidjson::Value editing_state(rapidjson::kObjectType);
247-
editing_state.AddMember(kComposingBaseKey, -1, allocator);
248-
editing_state.AddMember(kComposingExtentKey, -1, allocator);
278+
int composing_base =
279+
active_model_->composing() ? active_model_->composing_range().base() : -1;
280+
int composing_extent = active_model_->composing()
281+
? active_model_->composing_range().extent()
282+
: -1;
283+
284+
editing_state.AddMember(kComposingBaseKey, composing_base, allocator);
285+
editing_state.AddMember(kComposingExtentKey, composing_extent, allocator);
249286
editing_state.AddMember(kSelectionAffinityKey, kAffinityDownstream,
250287
allocator);
251288
editing_state.AddMember(kSelectionBaseKey, selection.base(), allocator);
@@ -255,7 +292,7 @@ void TextInputChannel::SendStateUpdate(const TextInputModel& model) {
255292
kTextKey, rapidjson::Value(model.GetText(), allocator).Move(), allocator);
256293
args->PushBack(editing_state, allocator);
257294

258-
FT_LOG(Info) << "Send text: " << model.GetText();
295+
FT_LOG(Debug) << "Send text:[" << model.GetText() << "]";
259296
channel_->InvokeMethod(kUpdateEditingStateMethod, std::move(args));
260297
}
261298

@@ -285,10 +322,6 @@ bool TextInputChannel::FilterEvent(Ecore_Event_Key* event) {
285322

286323
handled = input_method_context_->FilterEvent(event, is_ime ? "ime" : "");
287324

288-
if (handled) {
289-
text_editing_context_.last_handled_ecore_event_keyname_ = event->keyname;
290-
}
291-
292325
#ifdef WEARABLE_PROFILE
293326
if (!handled && !strcmp(event->key, "Return") &&
294327
text_editing_context_.is_in_select_mode_) {
@@ -306,7 +339,7 @@ void TextInputChannel::HandleUnfilteredEvent(Ecore_Event_Key* event) {
306339
#ifdef MOBILE_PROFILE
307340
// FIXME: Only for mobile.
308341
if (text_editing_context_.edit_status_ == EditStatus::kPreeditEnd) {
309-
FT_LOG(Warn) << "Ignore a key event: " << event->keyname;
342+
FT_LOG(Debug) << "Ignore a key event: " << event->keyname;
310343
ResetTextEditingContext();
311344
return;
312345
}
@@ -378,22 +411,6 @@ void TextInputChannel::EnterPressed(TextInputModel* model, bool select) {
378411
channel_->InvokeMethod(kPerformActionMethod, std::move(args));
379412
}
380413

381-
void TextInputChannel::ConsumeLastPreedit() {
382-
if (text_editing_context_.has_preedit_) {
383-
std::string before = active_model_->GetText();
384-
int count = text_editing_context_.preedit_end_pos_ -
385-
text_editing_context_.preedit_start_pos_;
386-
active_model_->DeleteSurrounding(-count, count);
387-
std::string after = active_model_->GetText();
388-
FT_LOG(Debug) << "Last preedit count: " << count << ", text: " << before
389-
<< " -> " << after;
390-
SendStateUpdate(*active_model_);
391-
}
392-
text_editing_context_.has_preedit_ = false;
393-
text_editing_context_.preedit_end_pos_ = 0;
394-
text_editing_context_.preedit_start_pos_ = 0;
395-
}
396-
397414
bool TextInputChannel::ShouldNotFilterEvent(std::string key, bool is_ime) {
398415
// Force redirect to HandleUnfilteredEvent(especially on TV)
399416
// If you don't do this, it will affects the input panel.

shell/platform/tizen/channels/text_input_channel.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,7 @@ enum class EditStatus { kNone, kPreeditStart, kPreeditEnd, kCommit };
2525

2626
struct TextEditingContext {
2727
EditStatus edit_status_ = EditStatus::kNone;
28-
bool has_preedit_ = false;
2928
bool is_in_select_mode_ = false;
30-
std::string last_handled_ecore_event_keyname_ = "";
31-
int preedit_end_pos_ = 0;
32-
int preedit_start_pos_ = 0;
3329
};
3430

3531
class TextInputChannel {
@@ -51,7 +47,6 @@ class TextInputChannel {
5147
bool FilterEvent(Ecore_Event_Key* event);
5248
void HandleUnfilteredEvent(Ecore_Event_Key* event);
5349
void EnterPressed(TextInputModel* model, bool select);
54-
void ConsumeLastPreedit();
5550
void ResetTextEditingContext() {
5651
text_editing_context_ = TextEditingContext();
5752
}

0 commit comments

Comments
 (0)