Skip to content

Commit 48a5982

Browse files
authored
Resize egl window when software keyboard is shown (flutter-tizen#7)
Signed-off-by: Boram Bae <[email protected]>
1 parent abd12b9 commit 48a5982

8 files changed

+182
-68
lines changed

shell/platform/tizen/channels/text_input_channel.cc

+102-34
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44

55
#include "text_input_channel.h"
66

7+
#include <Ecore.h>
78
#include <Ecore_IMF_Evas.h>
89

910
#include "flutter/shell/platform/tizen/logger.h"
11+
#include "flutter/shell/platform/tizen/tizen_embedder_engine.h"
12+
#include "flutter/shell/platform/tizen/tizen_surface.h"
1013
#include "stdlib.h"
1114
#include "string.h"
12-
1315
static constexpr char kSetEditingStateMethod[] = "TextInput.setEditingState";
1416
static constexpr char kClearClientMethod[] = "TextInput.clearClient";
1517
static constexpr char kSetClientMethod[] = "TextInput.setClient";
@@ -54,15 +56,15 @@ static bool IsASCIIPrintableKey(char c) {
5456
return false;
5557
}
5658

57-
static void CommitCallback(void* data, Ecore_IMF_Context* ctx,
58-
void* event_info) {
59+
void TextInputChannel::CommitCallback(void* data, Ecore_IMF_Context* ctx,
60+
void* event_info) {
5961
TextInputChannel* self = (TextInputChannel*)data;
6062
char* str = (char*)event_info;
6163
self->OnCommit(str);
6264
}
6365

64-
static void PreeditCallback(void* data, Ecore_IMF_Context* ctx,
65-
void* event_info) {
66+
void TextInputChannel::PreeditCallback(void* data, Ecore_IMF_Context* ctx,
67+
void* event_info) {
6668
TextInputChannel* self = (TextInputChannel*)data;
6769
char* preedit_string = nullptr;
6870
int cursor_pos;
@@ -73,34 +75,54 @@ static void PreeditCallback(void* data, Ecore_IMF_Context* ctx,
7375
}
7476
}
7577

76-
static void PrivateCommandCallback(void* data, Ecore_IMF_Context* ctx,
77-
void* event_info) {
78+
void TextInputChannel::PrivateCommandCallback(void* data,
79+
Ecore_IMF_Context* ctx,
80+
void* event_info) {
7881
// TODO
7982
LoggerD("Unimplemented");
8083
}
8184

82-
static void DeleteSurroundingCallback(void* data, Ecore_IMF_Context* ctx,
83-
void* event_info) {
85+
void TextInputChannel::DeleteSurroundingCallback(void* data,
86+
Ecore_IMF_Context* ctx,
87+
void* event_info) {
8488
// TODO
8589
LoggerD("Unimplemented");
8690
}
8791

88-
static void InputPanelStatChangedCallback(void* data,
89-
Ecore_IMF_Context* context,
90-
int value) {
92+
void TextInputChannel::InputPanelStateChangedCallback(
93+
void* data, Ecore_IMF_Context* context, int value) {
9194
if (!data) {
9295
LoggerD("[No Data]\n");
9396
return;
9497
}
9598
TextInputChannel* self = (TextInputChannel*)data;
9699
switch (value) {
97-
case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
100+
case ECORE_IMF_INPUT_PANEL_STATE_SHOW: {
98101
LoggerD("[PANEL_STATE_SHOW]\n");
99-
self->ShowSoftwareKeyboard();
100-
break;
102+
if (self->engine_->device_profile ==
103+
"mobile") { // FIXME : Needs improvement on other devices.
104+
ecore_timer_add(
105+
0.25,
106+
[](void* data) -> Eina_Bool {
107+
TextInputChannel* self = (TextInputChannel*)data;
108+
int32_t surface_w = self->engine_->tizen_surface->GetWidth();
109+
int32_t surface_h = self->engine_->tizen_surface->GetHeight() -
110+
self->current_keyboard_geometry_.h;
111+
self->engine_->tizen_surface->SetSize(surface_w, surface_h);
112+
if (self->rotation == 90 || self->rotation == 270) {
113+
self->engine_->SendWindowMetrics(surface_h, surface_w, 0);
114+
} else {
115+
self->engine_->SendWindowMetrics(surface_w, surface_h, 0);
116+
}
117+
118+
return ECORE_CALLBACK_CANCEL;
119+
},
120+
self);
121+
}
122+
} break;
101123
case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
124+
self->HideSoftwareKeyboard(); // FIXME: Fallback for HW back-key
102125
LoggerD("[PANEL_STATE_HIDE]\n");
103-
self->HideSoftwareKeyboard();
104126
break;
105127
case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
106128
LoggerD("[PANEL_STATE_WILL_SHOW]\n");
@@ -111,8 +133,28 @@ static void InputPanelStatChangedCallback(void* data,
111133
}
112134
}
113135

114-
static Eina_Bool RetrieveSurroundingCallback(void* data, Ecore_IMF_Context* ctx,
115-
char** text, int* cursor_pos) {
136+
void TextInputChannel::InputPanelGeometryChangedCallback(
137+
void* data, Ecore_IMF_Context* context, int value) {
138+
if (!data) {
139+
LoggerD("[No Data]\n");
140+
return;
141+
}
142+
TextInputChannel* self = (TextInputChannel*)data;
143+
ecore_imf_context_input_panel_geometry_get(
144+
self->imfContext_, &self->current_keyboard_geometry_.x,
145+
&self->current_keyboard_geometry_.y, &self->current_keyboard_geometry_.w,
146+
&self->current_keyboard_geometry_.h);
147+
148+
LoggerD(
149+
"[Current keyboard geometry] x:%d y:%d w:%d h:%d\n",
150+
self->current_keyboard_geometry_.x, self->current_keyboard_geometry_.y,
151+
self->current_keyboard_geometry_.w, self->current_keyboard_geometry_.h);
152+
}
153+
154+
Eina_Bool TextInputChannel::RetrieveSurroundingCallback(void* data,
155+
Ecore_IMF_Context* ctx,
156+
char** text,
157+
int* cursor_pos) {
116158
// TODO
117159
if (text) {
118160
*text = strdup("");
@@ -226,21 +268,15 @@ Ecore_IMF_Device_Subclass EoreDeviceSubClassToEcoreIMFDeviceSubClass(
226268
}
227269

228270
TextInputChannel::TextInputChannel(flutter::BinaryMessenger* messenger,
229-
Ecore_Wl2_Window* ecoreWindow)
271+
TizenEmbedderEngine* engine)
230272
: channel_(std::make_unique<flutter::MethodChannel<rapidjson::Document>>(
231273
messenger, kChannelName, &flutter::JsonMethodCodec::GetInstance())),
232274
active_model_(nullptr),
233275
isSoftwareKeyboardShowing_(false),
234276
lastPreeditStringLength_(0),
235277
imfContext_(nullptr),
236-
isWearable_(false),
237-
inSelectMode_(false) {
238-
const char* elmProfile = getenv("ELM_PROFILE");
239-
if (!elmProfile || strcmp(elmProfile, "wearable") == 0) {
240-
LoggerD("ELM_PROFILE is wearable");
241-
isWearable_ = true;
242-
}
243-
278+
inSelectMode_(false),
279+
engine_(engine) {
244280
channel_->SetMethodCallHandler(
245281
[this](
246282
const flutter::MethodCall<rapidjson::Document>& call,
@@ -256,6 +292,8 @@ TextInputChannel::TextInputChannel(flutter::BinaryMessenger* messenger,
256292
imfContext_ = ecore_imf_context_add(getImfMethod());
257293
}
258294
if (imfContext_) {
295+
Ecore_Wl2_Window* ecoreWindow =
296+
((TizenSurfaceGL*)engine_->tizen_surface.get())->wl2_window();
259297
ecore_imf_context_client_window_set(
260298
imfContext_, (void*)ecore_wl2_window_id_get(ecoreWindow));
261299
RegisterIMFCallback(ecoreWindow);
@@ -391,8 +429,8 @@ void TextInputChannel::SendStateUpdate(const flutter::TextInputModel& model) {
391429
}
392430

393431
bool TextInputChannel::FilterEvent(Ecore_Event_Key* keyDownEvent) {
432+
LoggerD("NonIMFFallback key name [%s]", keyDownEvent->keyname);
394433
bool handled = false;
395-
396434
const char* device = ecore_device_name_get(keyDownEvent->dev);
397435

398436
Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
@@ -414,7 +452,7 @@ bool TextInputChannel::FilterEvent(Ecore_Event_Key* keyDownEvent) {
414452

415453
bool isIME = strcmp(device, "ime") == 0;
416454
if (isIME && strcmp(keyDownEvent->key, "Select") == 0) {
417-
if (isWearable_) {
455+
if (engine_->device_profile == "wearable") {
418456
inSelectMode_ = true;
419457
} else {
420458
SelectPressed(active_model_.get());
@@ -563,9 +601,33 @@ void TextInputChannel::HideSoftwareKeyboard() {
563601
isSoftwareKeyboardShowing_);
564602
if (imfContext_ && isSoftwareKeyboardShowing_) {
565603
isSoftwareKeyboardShowing_ = false;
566-
ecore_imf_context_reset(imfContext_);
567-
ecore_imf_context_focus_out(imfContext_);
568-
ecore_imf_context_input_panel_hide(imfContext_);
604+
605+
if (engine_->device_profile ==
606+
"mobile") { // FIXME : Needs improvement on other devices.
607+
auto w = engine_->tizen_surface->GetWidth();
608+
auto h = engine_->tizen_surface->GetHeight();
609+
610+
if (rotation == 90 || rotation == 270) {
611+
engine_->SendWindowMetrics(h, w, 0);
612+
} else {
613+
engine_->SendWindowMetrics(w, h, 0);
614+
}
615+
engine_->tizen_surface->SetSize(w, h);
616+
ecore_timer_add(
617+
0.05,
618+
[](void* data) -> Eina_Bool {
619+
Ecore_IMF_Context* imfContext = (Ecore_IMF_Context*)data;
620+
ecore_imf_context_reset(imfContext);
621+
ecore_imf_context_focus_out(imfContext);
622+
ecore_imf_context_input_panel_hide(imfContext);
623+
return ECORE_CALLBACK_CANCEL;
624+
},
625+
imfContext_);
626+
} else {
627+
ecore_imf_context_reset(imfContext_);
628+
ecore_imf_context_focus_out(imfContext_);
629+
ecore_imf_context_input_panel_hide(imfContext_);
630+
}
569631
}
570632
}
571633

@@ -583,7 +645,10 @@ void TextInputChannel::RegisterIMFCallback(Ecore_Wl2_Window* ecoreWindow) {
583645
PrivateCommandCallback, this);
584646
ecore_imf_context_input_panel_event_callback_add(
585647
imfContext_, ECORE_IMF_INPUT_PANEL_STATE_EVENT,
586-
InputPanelStatChangedCallback, this);
648+
InputPanelStateChangedCallback, this);
649+
ecore_imf_context_input_panel_event_callback_add(
650+
imfContext_, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT,
651+
InputPanelGeometryChangedCallback, this);
587652
ecore_imf_context_retrieve_surrounding_callback_set(
588653
imfContext_, RetrieveSurroundingCallback, this);
589654

@@ -613,5 +678,8 @@ void TextInputChannel::UnregisterIMFCallback() {
613678
PrivateCommandCallback);
614679
ecore_imf_context_input_panel_event_callback_del(
615680
imfContext_, ECORE_IMF_INPUT_PANEL_STATE_EVENT,
616-
InputPanelStatChangedCallback);
681+
InputPanelStateChangedCallback);
682+
ecore_imf_context_input_panel_event_callback_del(
683+
imfContext_, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT,
684+
InputPanelGeometryChangedCallback);
617685
}

shell/platform/tizen/channels/text_input_channel.h

+30-3
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,26 @@
1717
#include "flutter/shell/platform/common/cpp/json_method_codec.h"
1818
#include "flutter/shell/platform/common/cpp/text_input_model.h"
1919

20+
class TizenEmbedderEngine;
2021
class TextInputChannel {
2122
public:
23+
struct SoftwareKeyboardGeometry {
24+
int32_t x = 0, y = 0, w = 0, h = 0;
25+
};
2226
explicit TextInputChannel(flutter::BinaryMessenger* messenger,
23-
Ecore_Wl2_Window* ecoreWindow);
27+
TizenEmbedderEngine* engine);
2428
virtual ~TextInputChannel();
2529
void OnKeyDown(Ecore_Event_Key* key);
2630
void OnCommit(const char* str);
2731
void OnPredit(const char* str, int cursorPos);
2832
void ShowSoftwareKeyboard();
2933
void HideSoftwareKeyboard();
3034
bool isSoftwareKeyboardShowing() { return isSoftwareKeyboardShowing_; }
35+
SoftwareKeyboardGeometry GetCurrentKeyboardGeometry() {
36+
return current_keyboard_geometry_;
37+
}
38+
39+
int32_t rotation = 0;
3140

3241
private:
3342
void HandleMethodCall(
@@ -44,14 +53,32 @@ class TextInputChannel {
4453
std::unique_ptr<flutter::MethodChannel<rapidjson::Document>> channel_;
4554
std::unique_ptr<flutter::TextInputModel> active_model_;
4655

47-
private:
56+
static void CommitCallback(void* data, Ecore_IMF_Context* ctx,
57+
void* event_info);
58+
static void PreeditCallback(void* data, Ecore_IMF_Context* ctx,
59+
void* event_info);
60+
static void PrivateCommandCallback(void* data, Ecore_IMF_Context* ctx,
61+
void* event_info);
62+
static void DeleteSurroundingCallback(void* data, Ecore_IMF_Context* ctx,
63+
void* event_info);
64+
static void InputPanelStateChangedCallback(void* data,
65+
Ecore_IMF_Context* context,
66+
int value);
67+
static void InputPanelGeometryChangedCallback(void* data,
68+
Ecore_IMF_Context* context,
69+
int value);
70+
static Eina_Bool RetrieveSurroundingCallback(void* data,
71+
Ecore_IMF_Context* ctx,
72+
char** text, int* cursor_pos);
73+
4874
int client_id_;
4975
std::string input_type_;
5076
std::string input_action_;
5177
bool isSoftwareKeyboardShowing_;
5278
int lastPreeditStringLength_;
5379
Ecore_IMF_Context* imfContext_;
54-
bool isWearable_;
5580
bool inSelectMode_;
81+
TizenEmbedderEngine* engine_;
82+
SoftwareKeyboardGeometry current_keyboard_geometry_;
5683
};
5784
#endif

0 commit comments

Comments
 (0)