diff --git a/shell/platform/tizen/channels/text_input_channel.cc b/shell/platform/tizen/channels/text_input_channel.cc index dd4eec438e35b..a158c74e8a902 100644 --- a/shell/platform/tizen/channels/text_input_channel.cc +++ b/shell/platform/tizen/channels/text_input_channel.cc @@ -4,12 +4,14 @@ #include "text_input_channel.h" +#include #include #include "flutter/shell/platform/tizen/logger.h" +#include "flutter/shell/platform/tizen/tizen_embedder_engine.h" +#include "flutter/shell/platform/tizen/tizen_surface.h" #include "stdlib.h" #include "string.h" - static constexpr char kSetEditingStateMethod[] = "TextInput.setEditingState"; static constexpr char kClearClientMethod[] = "TextInput.clearClient"; static constexpr char kSetClientMethod[] = "TextInput.setClient"; @@ -54,15 +56,15 @@ static bool IsASCIIPrintableKey(char c) { return false; } -static void CommitCallback(void* data, Ecore_IMF_Context* ctx, - void* event_info) { +void TextInputChannel::CommitCallback(void* data, Ecore_IMF_Context* ctx, + void* event_info) { TextInputChannel* self = (TextInputChannel*)data; char* str = (char*)event_info; self->OnCommit(str); } -static void PreeditCallback(void* data, Ecore_IMF_Context* ctx, - void* event_info) { +void TextInputChannel::PreeditCallback(void* data, Ecore_IMF_Context* ctx, + void* event_info) { TextInputChannel* self = (TextInputChannel*)data; char* preedit_string = nullptr; int cursor_pos; @@ -73,34 +75,54 @@ static void PreeditCallback(void* data, Ecore_IMF_Context* ctx, } } -static void PrivateCommandCallback(void* data, Ecore_IMF_Context* ctx, - void* event_info) { +void TextInputChannel::PrivateCommandCallback(void* data, + Ecore_IMF_Context* ctx, + void* event_info) { // TODO LoggerD("Unimplemented"); } -static void DeleteSurroundingCallback(void* data, Ecore_IMF_Context* ctx, - void* event_info) { +void TextInputChannel::DeleteSurroundingCallback(void* data, + Ecore_IMF_Context* ctx, + void* event_info) { // TODO LoggerD("Unimplemented"); } -static void InputPanelStatChangedCallback(void* data, - Ecore_IMF_Context* context, - int value) { +void TextInputChannel::InputPanelStateChangedCallback( + void* data, Ecore_IMF_Context* context, int value) { if (!data) { LoggerD("[No Data]\n"); return; } TextInputChannel* self = (TextInputChannel*)data; switch (value) { - case ECORE_IMF_INPUT_PANEL_STATE_SHOW: + case ECORE_IMF_INPUT_PANEL_STATE_SHOW: { LoggerD("[PANEL_STATE_SHOW]\n"); - self->ShowSoftwareKeyboard(); - break; + if (self->engine_->device_profile == + "mobile") { // FIXME : Needs improvement on other devices. + ecore_timer_add( + 0.25, + [](void* data) -> Eina_Bool { + TextInputChannel* self = (TextInputChannel*)data; + int32_t surface_w = self->engine_->tizen_surface->GetWidth(); + int32_t surface_h = self->engine_->tizen_surface->GetHeight() - + self->current_keyboard_geometry_.h; + self->engine_->tizen_surface->SetSize(surface_w, surface_h); + if (self->rotation == 90 || self->rotation == 270) { + self->engine_->SendWindowMetrics(surface_h, surface_w, 0); + } else { + self->engine_->SendWindowMetrics(surface_w, surface_h, 0); + } + + return ECORE_CALLBACK_CANCEL; + }, + self); + } + } break; case ECORE_IMF_INPUT_PANEL_STATE_HIDE: + self->HideSoftwareKeyboard(); // FIXME: Fallback for HW back-key LoggerD("[PANEL_STATE_HIDE]\n"); - self->HideSoftwareKeyboard(); break; case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW: LoggerD("[PANEL_STATE_WILL_SHOW]\n"); @@ -111,8 +133,28 @@ static void InputPanelStatChangedCallback(void* data, } } -static Eina_Bool RetrieveSurroundingCallback(void* data, Ecore_IMF_Context* ctx, - char** text, int* cursor_pos) { +void TextInputChannel::InputPanelGeometryChangedCallback( + void* data, Ecore_IMF_Context* context, int value) { + if (!data) { + LoggerD("[No Data]\n"); + return; + } + TextInputChannel* self = (TextInputChannel*)data; + ecore_imf_context_input_panel_geometry_get( + self->imfContext_, &self->current_keyboard_geometry_.x, + &self->current_keyboard_geometry_.y, &self->current_keyboard_geometry_.w, + &self->current_keyboard_geometry_.h); + + LoggerD( + "[Current keyboard geometry] x:%d y:%d w:%d h:%d\n", + self->current_keyboard_geometry_.x, self->current_keyboard_geometry_.y, + self->current_keyboard_geometry_.w, self->current_keyboard_geometry_.h); +} + +Eina_Bool TextInputChannel::RetrieveSurroundingCallback(void* data, + Ecore_IMF_Context* ctx, + char** text, + int* cursor_pos) { // TODO if (text) { *text = strdup(""); @@ -226,21 +268,15 @@ Ecore_IMF_Device_Subclass EoreDeviceSubClassToEcoreIMFDeviceSubClass( } TextInputChannel::TextInputChannel(flutter::BinaryMessenger* messenger, - Ecore_Wl2_Window* ecoreWindow) + TizenEmbedderEngine* engine) : channel_(std::make_unique>( messenger, kChannelName, &flutter::JsonMethodCodec::GetInstance())), active_model_(nullptr), isSoftwareKeyboardShowing_(false), lastPreeditStringLength_(0), imfContext_(nullptr), - isWearable_(false), - inSelectMode_(false) { - const char* elmProfile = getenv("ELM_PROFILE"); - if (!elmProfile || strcmp(elmProfile, "wearable") == 0) { - LoggerD("ELM_PROFILE is wearable"); - isWearable_ = true; - } - + inSelectMode_(false), + engine_(engine) { channel_->SetMethodCallHandler( [this]( const flutter::MethodCall& call, @@ -256,6 +292,8 @@ TextInputChannel::TextInputChannel(flutter::BinaryMessenger* messenger, imfContext_ = ecore_imf_context_add(getImfMethod()); } if (imfContext_) { + Ecore_Wl2_Window* ecoreWindow = + ((TizenSurfaceGL*)engine_->tizen_surface.get())->wl2_window(); ecore_imf_context_client_window_set( imfContext_, (void*)ecore_wl2_window_id_get(ecoreWindow)); RegisterIMFCallback(ecoreWindow); @@ -391,8 +429,8 @@ void TextInputChannel::SendStateUpdate(const flutter::TextInputModel& model) { } bool TextInputChannel::FilterEvent(Ecore_Event_Key* keyDownEvent) { + LoggerD("NonIMFFallback key name [%s]", keyDownEvent->keyname); bool handled = false; - const char* device = ecore_device_name_get(keyDownEvent->dev); Ecore_IMF_Event_Key_Down ecoreKeyDownEvent; @@ -414,7 +452,7 @@ bool TextInputChannel::FilterEvent(Ecore_Event_Key* keyDownEvent) { bool isIME = strcmp(device, "ime") == 0; if (isIME && strcmp(keyDownEvent->key, "Select") == 0) { - if (isWearable_) { + if (engine_->device_profile == "wearable") { inSelectMode_ = true; } else { SelectPressed(active_model_.get()); @@ -563,9 +601,33 @@ void TextInputChannel::HideSoftwareKeyboard() { isSoftwareKeyboardShowing_); if (imfContext_ && isSoftwareKeyboardShowing_) { isSoftwareKeyboardShowing_ = false; - ecore_imf_context_reset(imfContext_); - ecore_imf_context_focus_out(imfContext_); - ecore_imf_context_input_panel_hide(imfContext_); + + if (engine_->device_profile == + "mobile") { // FIXME : Needs improvement on other devices. + auto w = engine_->tizen_surface->GetWidth(); + auto h = engine_->tizen_surface->GetHeight(); + + if (rotation == 90 || rotation == 270) { + engine_->SendWindowMetrics(h, w, 0); + } else { + engine_->SendWindowMetrics(w, h, 0); + } + engine_->tizen_surface->SetSize(w, h); + ecore_timer_add( + 0.05, + [](void* data) -> Eina_Bool { + Ecore_IMF_Context* imfContext = (Ecore_IMF_Context*)data; + ecore_imf_context_reset(imfContext); + ecore_imf_context_focus_out(imfContext); + ecore_imf_context_input_panel_hide(imfContext); + return ECORE_CALLBACK_CANCEL; + }, + imfContext_); + } else { + ecore_imf_context_reset(imfContext_); + ecore_imf_context_focus_out(imfContext_); + ecore_imf_context_input_panel_hide(imfContext_); + } } } @@ -583,7 +645,10 @@ void TextInputChannel::RegisterIMFCallback(Ecore_Wl2_Window* ecoreWindow) { PrivateCommandCallback, this); ecore_imf_context_input_panel_event_callback_add( imfContext_, ECORE_IMF_INPUT_PANEL_STATE_EVENT, - InputPanelStatChangedCallback, this); + InputPanelStateChangedCallback, this); + ecore_imf_context_input_panel_event_callback_add( + imfContext_, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, + InputPanelGeometryChangedCallback, this); ecore_imf_context_retrieve_surrounding_callback_set( imfContext_, RetrieveSurroundingCallback, this); @@ -613,5 +678,8 @@ void TextInputChannel::UnregisterIMFCallback() { PrivateCommandCallback); ecore_imf_context_input_panel_event_callback_del( imfContext_, ECORE_IMF_INPUT_PANEL_STATE_EVENT, - InputPanelStatChangedCallback); + InputPanelStateChangedCallback); + ecore_imf_context_input_panel_event_callback_del( + imfContext_, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, + InputPanelGeometryChangedCallback); } diff --git a/shell/platform/tizen/channels/text_input_channel.h b/shell/platform/tizen/channels/text_input_channel.h index b8d8985bcadf2..76346114a440b 100644 --- a/shell/platform/tizen/channels/text_input_channel.h +++ b/shell/platform/tizen/channels/text_input_channel.h @@ -17,10 +17,14 @@ #include "flutter/shell/platform/common/cpp/json_method_codec.h" #include "flutter/shell/platform/common/cpp/text_input_model.h" +class TizenEmbedderEngine; class TextInputChannel { public: + struct SoftwareKeyboardGeometry { + int32_t x = 0, y = 0, w = 0, h = 0; + }; explicit TextInputChannel(flutter::BinaryMessenger* messenger, - Ecore_Wl2_Window* ecoreWindow); + TizenEmbedderEngine* engine); virtual ~TextInputChannel(); void OnKeyDown(Ecore_Event_Key* key); void OnCommit(const char* str); @@ -28,6 +32,11 @@ class TextInputChannel { void ShowSoftwareKeyboard(); void HideSoftwareKeyboard(); bool isSoftwareKeyboardShowing() { return isSoftwareKeyboardShowing_; } + SoftwareKeyboardGeometry GetCurrentKeyboardGeometry() { + return current_keyboard_geometry_; + } + + int32_t rotation = 0; private: void HandleMethodCall( @@ -44,14 +53,32 @@ class TextInputChannel { std::unique_ptr> channel_; std::unique_ptr active_model_; - private: + static void CommitCallback(void* data, Ecore_IMF_Context* ctx, + void* event_info); + static void PreeditCallback(void* data, Ecore_IMF_Context* ctx, + void* event_info); + static void PrivateCommandCallback(void* data, Ecore_IMF_Context* ctx, + void* event_info); + static void DeleteSurroundingCallback(void* data, Ecore_IMF_Context* ctx, + void* event_info); + static void InputPanelStateChangedCallback(void* data, + Ecore_IMF_Context* context, + int value); + static void InputPanelGeometryChangedCallback(void* data, + Ecore_IMF_Context* context, + int value); + static Eina_Bool RetrieveSurroundingCallback(void* data, + Ecore_IMF_Context* ctx, + char** text, int* cursor_pos); + int client_id_; std::string input_type_; std::string input_action_; bool isSoftwareKeyboardShowing_; int lastPreeditStringLength_; Ecore_IMF_Context* imfContext_; - bool isWearable_; bool inSelectMode_; + TizenEmbedderEngine* engine_; + SoftwareKeyboardGeometry current_keyboard_geometry_; }; #endif diff --git a/shell/platform/tizen/tizen_embedder_engine.cc b/shell/platform/tizen/tizen_embedder_engine.cc index cebf3f6ae6b97..05fbe02ce4e7b 100644 --- a/shell/platform/tizen/tizen_embedder_engine.cc +++ b/shell/platform/tizen/tizen_embedder_engine.cc @@ -16,8 +16,25 @@ // Unique number associated with platform tasks. static constexpr size_t kPlatformTaskRunnerIdentifier = 1; +static std::string GetDeviceProfile() { + char* feature_profile; + system_info_get_platform_string("http://tizen.org/feature/profile", + &feature_profile); + std::string profile(feature_profile); + free(feature_profile); + return profile; +} + +static double GetDeviceDpi() { + int feature_dpi; + system_info_get_platform_int("http://tizen.org/feature/screen.dpi", + &feature_dpi); + return (double)feature_dpi; +} + TizenEmbedderEngine::TizenEmbedderEngine( - const FlutterWindowProperties& window_properties) { + const FlutterWindowProperties& window_properties) + : device_profile(GetDeviceProfile()), device_dpi(GetDeviceDpi()) { tizen_surface = std::make_unique( window_properties.x, window_properties.y, window_properties.width, window_properties.height); @@ -163,8 +180,7 @@ bool TizenEmbedderEngine::RunEngine( settings_channel = std::make_unique( internal_plugin_registrar_->messenger()); text_input_channel = std::make_unique( - internal_plugin_registrar_->messenger(), - ((TizenSurfaceGL*)tizen_surface.get())->wl2_window()); + internal_plugin_registrar_->messenger(), this); localization_channel = std::make_unique(flutter_engine); localization_channel->SendLocales(); lifecycle_channel = std::make_unique(flutter_engine); @@ -210,22 +226,6 @@ bool TizenEmbedderEngine::OnAcquireExternalTexture( ->PopulateTextureWithIdentifier(width, height, texture); } -std::string GetDeviceProfile() { - char* feature_profile; - system_info_get_platform_string("http://tizen.org/feature/profile", - &feature_profile); - std::string profile(feature_profile); - free(feature_profile); - return profile; -} - -double GetDeviceDpi() { - int feature_dpi; - system_info_get_platform_int("http://tizen.org/feature/screen.dpi", - &feature_dpi); - return (double)feature_dpi; -} - void TizenEmbedderEngine::SendWindowMetrics(int32_t width, int32_t height, double pixel_ratio) { FlutterWindowMetricsEvent event; @@ -236,16 +236,15 @@ void TizenEmbedderEngine::SendWindowMetrics(int32_t width, int32_t height, // The scale factor is computed based on the display DPI and the current // profile. A fixed DPI value (72) is used on TVs. See: // https://docs.tizen.org/application/native/guides/ui/efl/multiple-screens - std::string profile = GetDeviceProfile(); double profile_factor = 1.0; - if (profile == "wearable") { + if (device_profile == "wearable") { profile_factor = 0.4; - } else if (profile == "mobile") { + } else if (device_profile == "mobile") { profile_factor = 0.7; - } else if (profile == "tv") { + } else if (device_profile == "tv") { profile_factor = 2.0; } - double dpi = profile == "tv" ? 72.0 : GetDeviceDpi(); + double dpi = device_profile == "tv" ? 72.0 : device_dpi; double scale_factor = dpi / 90.0 * profile_factor; event.pixel_ratio = std::max(scale_factor, 1.0); } else { @@ -265,6 +264,11 @@ void TizenEmbedderEngine::SetWindowOrientation(int32_t degree) { double rad = (360 - degree) * M_PI / 180; double width = tizen_surface->GetWidth(); double height = tizen_surface->GetHeight(); + + if (text_input_channel->isSoftwareKeyboardShowing()) { + height -= text_input_channel->GetCurrentKeyboardGeometry().h; + } + double trans_x = 0.0, trans_y = 0.0; if (degree == 90) { trans_y = height; @@ -280,7 +284,7 @@ void TizenEmbedderEngine::SetWindowOrientation(int32_t degree) { 0.0, 0.0, 1.0 // perspective }; touch_event_handler_->rotation = degree; - + text_input_channel->rotation = degree; if (degree == 90 || degree == 270) { SendWindowMetrics(height, width, 0.0); } else { diff --git a/shell/platform/tizen/tizen_embedder_engine.h b/shell/platform/tizen/tizen_embedder_engine.h index d7156d6074c34..882d3072dbf7a 100644 --- a/shell/platform/tizen/tizen_embedder_engine.h +++ b/shell/platform/tizen/tizen_embedder_engine.h @@ -76,6 +76,7 @@ class TizenEmbedderEngine { void SetPluginRegistrarDestructionCallback( FlutterDesktopOnPluginRegistrarDestroyed callback); + void SendWindowMetrics(int32_t width, int32_t height, double pixel_ratio); void SetWindowOrientation(int32_t degree); void SendLocales(); void AppIsInactive(); @@ -105,6 +106,9 @@ class TizenEmbedderEngine { std::unique_ptr text_input_channel; std::unique_ptr platform_view_channel; + const std::string device_profile; + const double device_dpi; + private: static bool MakeContextCurrent(void* user_data); static bool ClearContext(void* user_data); @@ -117,7 +121,6 @@ class TizenEmbedderEngine { const FlutterPlatformMessage* engine_message, void* user_data); static void OnVsyncCallback(void* user_data, intptr_t baton); - void SendWindowMetrics(int32_t width, int32_t height, double pixel_ratio); FlutterDesktopMessage ConvertToDesktopMessage( const FlutterPlatformMessage& engine_message); static bool OnAcquireExternalTexture(void* user_data, int64_t texture_id, diff --git a/shell/platform/tizen/tizen_surface.cc b/shell/platform/tizen/tizen_surface.cc index d841054efdb07..55926b3097c5d 100644 --- a/shell/platform/tizen/tizen_surface.cc +++ b/shell/platform/tizen/tizen_surface.cc @@ -9,6 +9,6 @@ TizenSurface::TizenSurface(int32_t x, int32_t y, int32_t width, int32_t height) TizenSurface::~TizenSurface() {} -uint32_t TizenSurface::GetWidth() { return window_width_; } +int32_t TizenSurface::GetWidth() { return window_width_; } -uint32_t TizenSurface::GetHeight() { return window_height_; } +int32_t TizenSurface::GetHeight() { return window_height_; } diff --git a/shell/platform/tizen/tizen_surface.h b/shell/platform/tizen/tizen_surface.h index 736eb5b593de4..29bf6a34d5320 100644 --- a/shell/platform/tizen/tizen_surface.h +++ b/shell/platform/tizen/tizen_surface.h @@ -18,8 +18,9 @@ class TizenSurface { virtual uint32_t OnGetFBO() = 0; virtual void* OnProcResolver(const char* name) = 0; virtual bool IsValid() = 0; - uint32_t GetWidth(); - uint32_t GetHeight(); + virtual void SetSize(int32_t width, int32_t height) = 0; + int32_t GetWidth(); + int32_t GetHeight(); protected: const int32_t window_width_; diff --git a/shell/platform/tizen/tizen_surface_gl.cc b/shell/platform/tizen/tizen_surface_gl.cc index 466bf83a33ca6..7e1769a3583a9 100644 --- a/shell/platform/tizen/tizen_surface_gl.cc +++ b/shell/platform/tizen/tizen_surface_gl.cc @@ -3,8 +3,10 @@ // found in the LICENSE file. #include "tizen_surface_gl.h" + #include #include + #include "flutter/shell/platform/tizen/logger.h" TizenSurfaceGL::TizenSurfaceGL(int32_t x, int32_t y, int32_t width, @@ -78,7 +80,7 @@ uint32_t TizenSurfaceGL::OnGetFBO() { return 0; // FBO0 } -#define GL_FUNC(FunctionName) \ +#define GL_FUNC(FunctionName) \ else if (strcmp(name, #FunctionName) == 0) { \ return reinterpret_cast(FunctionName); \ } @@ -241,6 +243,8 @@ bool TizenSurfaceGL::InitalizeDisplay() { // ecore_wl2 SHOW ecore_wl2_window_show(wl2_window_); + ecore_wl2_window_aux_hint_add(wl2_window_, 0, "wm.policy.win.user.geometry", + "1"); ecore_wl2_window_position_set(wl2_window_, x_, y_); ecore_wl2_window_geometry_set(wl2_window_, x_, y_, window_width_, window_height_); @@ -366,3 +370,9 @@ void TizenSurfaceGL::Destroy() { } ecore_wl2_shutdown(); } + +void TizenSurfaceGL::SetSize(int32_t width, int32_t height) { + LoggerD("Resize egl window %d %d", width, height); + ecore_wl2_egl_window_resize_with_rotation(egl_window_, 0, 0, width, height, + 0); +} diff --git a/shell/platform/tizen/tizen_surface_gl.h b/shell/platform/tizen/tizen_surface_gl.h index 3024c9d4e4be9..257512753901c 100644 --- a/shell/platform/tizen/tizen_surface_gl.h +++ b/shell/platform/tizen/tizen_surface_gl.h @@ -33,6 +33,7 @@ class TizenSurfaceGL : public TizenSurface { bool IsValid(); bool InitalizeDisplay(); void Destroy(); + void SetSize(int32_t width, int32_t height); Ecore_Wl2_Window* wl2_window() { return wl2_window_; } private: