diff --git a/flutter/shell/platform/tizen/channels/text_input_channel.cc b/flutter/shell/platform/tizen/channels/text_input_channel.cc index 7e2b343..605a544 100644 --- a/flutter/shell/platform/tizen/channels/text_input_channel.cc +++ b/flutter/shell/platform/tizen/channels/text_input_channel.cc @@ -136,13 +136,18 @@ void TextInputChannel::HandleMethodCall( if (input_type_ != kNoneInputType) { input_method_context_->ShowInputPanel(); } + if (active_model_) { + input_method_context_->SetEditingActive(true); + } } else if (method.compare(kHideMethod) == 0) { + input_method_context_->SetEditingActive(false); input_method_context_->HideInputPanel(); input_method_context_->ResetInputMethodContext(); } else if (method.compare(kSetPlatformViewClient) == 0) { result->NotImplemented(); return; } else if (method.compare(kClearClientMethod) == 0) { + input_method_context_->SetEditingActive(false); active_model_ = nullptr; } else if (method.compare(kSetClientMethod) == 0) { if (!method_call.arguments() || method_call.arguments()->IsNull()) { @@ -212,14 +217,18 @@ void TextInputChannel::HandleMethodCall( // change. See https://github.com/flutter-tizen/engine/pull/194. input_method_context_->HideInputPanel(); if (input_type_ != kNoneInputType) { + input_method_context_->SetInputPanelEnabled(true); input_method_context_->ShowInputPanel(); + } else { + input_method_context_->SetInputPanelEnabled(false); } } } + input_method_context_->ResetInputMethodContext(); active_model_ = std::make_unique(); + input_method_context_->SetEditingActive(true); } else if (method.compare(kSetEditingStateMethod) == 0) { - input_method_context_->ResetInputMethodContext(); if (!method_call.arguments() || method_call.arguments()->IsNull()) { result->Error(kBadArgumentError, "Method invoked without args."); return; @@ -250,8 +259,14 @@ void TextInputChannel::HandleMethodCall( "Selection base/extent values invalid."); return; } + int selection_base_value = selection_base->value.GetInt(); int selection_extent_value = selection_extent->value.GetInt(); + if (active_model_->GetText() != text->value.GetString() || + !(active_model_->selection() == + TextRange(selection_base_value, selection_extent_value))) { + input_method_context_->ResetInputMethodContext(); + } active_model_->SetText(text->value.GetString()); active_model_->SetSelection( @@ -327,10 +342,16 @@ bool TextInputChannel::HandleKey(const char* key, active_model_->AddCodePoint(string[0]); needs_update = true; } else if (key_str == "Return") { + if (active_model_->composing()) { + input_method_context_->ResetInputMethodContext(); + } EnterPressed(); return true; #ifdef TV_PROFILE } else if (key_str == "Select") { + if (active_model_->composing()) { + input_method_context_->ResetInputMethodContext(); + } SelectPressed(); return true; #endif diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.cc b/flutter/shell/platform/tizen/tizen_input_method_context.cc index 869d2c0..76e46d6 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.cc +++ b/flutter/shell/platform/tizen/tizen_input_method_context.cc @@ -4,6 +4,8 @@ #include "tizen_input_method_context.h" +#include + #include "flutter/shell/platform/tizen/logger.h" namespace { @@ -115,6 +117,27 @@ T EcoreEventKeyToEcoreImfEvent(Ecore_Event_Key* event) { return imf_event; } +bool IsNavigationOrSystemKey(const char* key) { + if (!key) { + return false; + } + // Multimedia / system / TV remote keys. + if (strncmp(key, "XF86", 4) == 0) { + return true; + } + // Directional and action keys used for app/remote navigation. + static const char* kNavigationKeys[] = { + "Up", "Down", "Left", "Right", "KP_Up", "KP_Down", + "KP_Left", "KP_Right", "Return", "KP_Enter", "Select", + }; + for (const char* nav_key : kNavigationKeys) { + if (strcmp(key, nav_key) == 0) { + return true; + } + } + return false; +} + } // namespace namespace flutter { @@ -165,8 +188,10 @@ TizenInputMethodContext::~TizenInputMethodContext() { bool TizenInputMethodContext::HandleEcoreEventKey(Ecore_Event_Key* event, bool is_down) { - FT_ASSERT(imf_context_); FT_ASSERT(event); + if (!imf_context_) { + return false; + } Ecore_IMF_Event imf_event; if (is_down) { @@ -192,7 +217,7 @@ bool TizenInputMethodContext::HandleNuiKeyEvent(const char* device_name, uint32_t scan_code, size_t timestamp, bool is_down) { - Ecore_Event_Key event; + Ecore_Event_Key event = {}; event.keyname = event.key = key ? key : ""; event.string = string ? string : ""; event.modifiers = modifiers; @@ -227,39 +252,80 @@ bool TizenInputMethodContext::HandleNuiKeyEvent(const char* device_name, #endif InputPanelGeometry TizenInputMethodContext::GetInputPanelGeometry() { - FT_ASSERT(imf_context_); InputPanelGeometry geometry; + if (!imf_context_) { + return geometry; + } ecore_imf_context_input_panel_geometry_get( imf_context_, &geometry.x, &geometry.y, &geometry.w, &geometry.h); return geometry; } void TizenInputMethodContext::ResetInputMethodContext() { - FT_ASSERT(imf_context_); + if (!imf_context_) { + return; + } ecore_imf_context_reset(imf_context_); } void TizenInputMethodContext::ShowInputPanel() { - FT_ASSERT(imf_context_); + if (!imf_context_) { + return; + } ecore_imf_context_input_panel_show(imf_context_); - ecore_imf_context_focus_in(imf_context_); } void TizenInputMethodContext::HideInputPanel() { - FT_ASSERT(imf_context_); - ecore_imf_context_focus_out(imf_context_); + if (!imf_context_) { + return; + } ecore_imf_context_input_panel_hide(imf_context_); } +void TizenInputMethodContext::SetEditingActive(bool active) { + if (!imf_context_) { + return; + } + editing_active_ = active; + if (active) { + ecore_imf_context_focus_in(imf_context_); + } else { + ecore_imf_context_focus_out(imf_context_); + } +} + +void TizenInputMethodContext::SetInputPanelEnabled(bool enabled) { + if (!imf_context_) { + return; + } + ecore_imf_context_input_panel_enabled_set(imf_context_, enabled); +} + +bool TizenInputMethodContext::ShouldFilterKey(const char* key) { + if (!imf_context_) { + return false; + } + if (IsInputPanelShown()) { + return true; + } + return editing_active_ && !IsNavigationOrSystemKey(key); +} + bool TizenInputMethodContext::IsInputPanelShown() { + if (!imf_context_) { + return false; + } Ecore_IMF_Input_Panel_State state = ecore_imf_context_input_panel_state_get(imf_context_); - return state == ECORE_IMF_INPUT_PANEL_STATE_SHOW; + return state == ECORE_IMF_INPUT_PANEL_STATE_SHOW || + state == ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW; } void TizenInputMethodContext::SetInputPanelLayout( const std::string& input_type) { - FT_ASSERT(imf_context_); + if (!imf_context_) { + return; + } Ecore_IMF_Input_Panel_Layout panel_layout = TextInputTypeToEcoreImfInputPanelLayout(input_type); ecore_imf_context_input_panel_layout_set(imf_context_, panel_layout); @@ -267,6 +333,9 @@ void TizenInputMethodContext::SetInputPanelLayout( void TizenInputMethodContext::SetInputPanelLayoutVariation(bool is_signed, bool is_decimal) { + if (!imf_context_) { + return; + } Ecore_IMF_Input_Panel_Layout_Numberonly_Variation variation; if (is_signed && is_decimal) { variation = @@ -282,6 +351,9 @@ void TizenInputMethodContext::SetInputPanelLayoutVariation(bool is_signed, } void TizenInputMethodContext::SetAutocapitalType(const std::string& type) { + if (!imf_context_) { + return; + } Ecore_IMF_Autocapital_Type autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_NONE; if (type == "TextCapitalization.characters") { @@ -356,7 +428,9 @@ void TizenInputMethodContext::RegisterEventCallbacks() { } void TizenInputMethodContext::UnregisterEventCallbacks() { - FT_ASSERT(imf_context_); + if (!imf_context_) { + return; + } ecore_imf_context_event_callback_del( imf_context_, ECORE_IMF_CALLBACK_COMMIT, event_callbacks_[ECORE_IMF_CALLBACK_COMMIT]); @@ -418,7 +492,9 @@ void TizenInputMethodContext::InputPanelStateChangedCallback( } void TizenInputMethodContext::RegisterInputPanelEventCallback() { - FT_ASSERT(imf_context_); + if (!imf_context_) { + return; + } ecore_imf_context_input_panel_event_callback_add( imf_context_, ECORE_IMF_INPUT_PANEL_STATE_EVENT, @@ -426,7 +502,9 @@ void TizenInputMethodContext::RegisterInputPanelEventCallback() { } void TizenInputMethodContext::UnregisterInputPanelEventCallback() { - FT_ASSERT(imf_context_); + if (!imf_context_) { + return; + } ecore_imf_context_input_panel_event_callback_del( imf_context_, ECORE_IMF_INPUT_PANEL_STATE_EVENT, diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.h b/flutter/shell/platform/tizen/tizen_input_method_context.h index 6915dd5..1e1a63c 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.h +++ b/flutter/shell/platform/tizen/tizen_input_method_context.h @@ -53,6 +53,12 @@ class TizenInputMethodContext { bool IsInputPanelShown(); + void SetEditingActive(bool active); + + void SetInputPanelEnabled(bool enabled); + + bool ShouldFilterKey(const char* key); + void SetInputPanelLayout(const std::string& layout); void SetInputPanelLayoutVariation(bool is_signed, bool is_decimal); @@ -93,6 +99,7 @@ class TizenInputMethodContext { Ecore_Device* ecore_device_ = nullptr; #endif Ecore_IMF_Context* imf_context_ = nullptr; + bool editing_active_ = false; OnCommit on_commit_; OnPreeditChanged on_preedit_changed_; OnPreeditStart on_preedit_start_; diff --git a/flutter/shell/platform/tizen/tizen_view_nui.cc b/flutter/shell/platform/tizen/tizen_view_nui.cc index f3b9347..a848a39 100644 --- a/flutter/shell/platform/tizen/tizen_view_nui.cc +++ b/flutter/shell/platform/tizen/tizen_view_nui.cc @@ -90,7 +90,7 @@ void TizenViewNui::OnKey(const char* device_name, bool is_down) { bool handled = false; - if (input_method_context_->IsInputPanelShown()) { + if (input_method_context_->ShouldFilterKey(key)) { handled = input_method_context_->HandleNuiKeyEvent( device_name, device_class, device_subclass, key, string, modifiers, scan_code, timestamp, is_down); diff --git a/flutter/shell/platform/tizen/tizen_window_ecore_wl2.cc b/flutter/shell/platform/tizen/tizen_window_ecore_wl2.cc index 41d16b9..98bfb7c 100644 --- a/flutter/shell/platform/tizen/tizen_window_ecore_wl2.cc +++ b/flutter/shell/platform/tizen/tizen_window_ecore_wl2.cc @@ -567,7 +567,7 @@ void TizenWindowEcoreWl2::RegisterEventHandlers() { auto* key_event = reinterpret_cast(event); if (key_event->window == self->GetWindowId()) { bool handled = false; - if (self->input_method_context_->IsInputPanelShown()) { + if (self->input_method_context_->ShouldFilterKey(key_event->key)) { handled = self->input_method_context_->HandleEcoreEventKey( key_event, true); } @@ -592,7 +592,7 @@ void TizenWindowEcoreWl2::RegisterEventHandlers() { auto* key_event = reinterpret_cast(event); if (key_event->window == self->GetWindowId()) { bool handled = false; - if (self->input_method_context_->IsInputPanelShown()) { + if (self->input_method_context_->ShouldFilterKey(key_event->key)) { handled = self->input_method_context_->HandleEcoreEventKey( key_event, false); }