From f0a243496631e620d2d92f9712e26d7ce50d6347 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 3 Feb 2026 10:10:37 +0900 Subject: [PATCH 1/2] Add input panel state event channel Add InputPanelChannel to broadcast input panel state changes to Dart via "tizen/internal/inputpanel" event channel. States include "show", "hide", and "will_show". --- flutter/shell/platform/tizen/BUILD.gn | 1 + .../tizen/channels/input_panel_channel.cc | 60 +++++++++++++++++++ .../tizen/channels/input_panel_channel.h | 35 +++++++++++ .../platform/tizen/flutter_tizen_view.cc | 2 + .../shell/platform/tizen/flutter_tizen_view.h | 4 ++ .../tizen/tizen_input_method_context.cc | 47 +++++++++++++++ .../tizen/tizen_input_method_context.h | 15 +++++ 7 files changed, 164 insertions(+) create mode 100644 flutter/shell/platform/tizen/channels/input_panel_channel.cc create mode 100644 flutter/shell/platform/tizen/channels/input_panel_channel.h diff --git a/flutter/shell/platform/tizen/BUILD.gn b/flutter/shell/platform/tizen/BUILD.gn index f5a6df0c..a6aa508d 100644 --- a/flutter/shell/platform/tizen/BUILD.gn +++ b/flutter/shell/platform/tizen/BUILD.gn @@ -69,6 +69,7 @@ template("embedder") { "channels/app_control_channel.cc", "channels/feedback_manager.cc", "channels/input_device_channel.cc", + "channels/input_panel_channel.cc", "channels/key_mapping.cc", "channels/keyboard_channel.cc", "channels/lifecycle_channel.cc", diff --git a/flutter/shell/platform/tizen/channels/input_panel_channel.cc b/flutter/shell/platform/tizen/channels/input_panel_channel.cc new file mode 100644 index 00000000..d8e3eae6 --- /dev/null +++ b/flutter/shell/platform/tizen/channels/input_panel_channel.cc @@ -0,0 +1,60 @@ +// Copyright 2026 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "input_panel_channel.h" + +#include "flutter/shell/platform/common/client_wrapper/include/flutter/event_stream_handler_functions.h" +#include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_method_codec.h" +#include "flutter/shell/platform/tizen/logger.h" +#include "flutter/shell/platform/tizen/tizen_input_method_context.h" + +namespace { + +constexpr char kChannelName[] = "tizen/internal/inputpanel"; + +} // namespace + +namespace flutter { + +InputPanelChannel::InputPanelChannel(BinaryMessenger* messenger, + TizenInputMethodContext* imf_context) + : imf_context_(imf_context) { + event_channel_ = std::make_unique>( + messenger, kChannelName, &StandardMethodCodec::GetInstance()); + auto event_channel_handler = std::make_unique>( + [this](const EncodableValue* arguments, + std::unique_ptr>&& events) + -> std::unique_ptr> { + event_sink_ = std::move(events); + imf_context_->SetOnInputPanelStateChanged( + [this](const std::string& state) { + SendInputPanelStateEvent(state); + }); + return nullptr; + }, + [this](const EncodableValue* arguments) + -> std::unique_ptr> { + imf_context_->SetOnInputPanelStateChanged(nullptr); + event_sink_.reset(); + return nullptr; + }); + + event_channel_->SetStreamHandler(std::move(event_channel_handler)); +} + +InputPanelChannel::~InputPanelChannel() { + imf_context_->SetOnInputPanelStateChanged(nullptr); +} + +void InputPanelChannel::SendInputPanelStateEvent(const std::string& state) { + if (!event_sink_) { + return; + } + + EncodableMap event; + event[EncodableValue("state")] = EncodableValue(state); + event_sink_->Success(EncodableValue(event)); +} + +} // namespace flutter diff --git a/flutter/shell/platform/tizen/channels/input_panel_channel.h b/flutter/shell/platform/tizen/channels/input_panel_channel.h new file mode 100644 index 00000000..755c2097 --- /dev/null +++ b/flutter/shell/platform/tizen/channels/input_panel_channel.h @@ -0,0 +1,35 @@ +// Copyright 2026 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EMBEDDER_INPUT_PANEL_CHANNEL_H_ +#define EMBEDDER_INPUT_PANEL_CHANNEL_H_ + +#include +#include + +#include "flutter/shell/platform/common/client_wrapper/include/flutter/binary_messenger.h" +#include "flutter/shell/platform/common/client_wrapper/include/flutter/encodable_value.h" +#include "flutter/shell/platform/common/client_wrapper/include/flutter/event_channel.h" + +namespace flutter { + +class TizenInputMethodContext; + +class InputPanelChannel { + public: + explicit InputPanelChannel(BinaryMessenger* messenger, + TizenInputMethodContext* imf_context); + virtual ~InputPanelChannel(); + + private: + void SendInputPanelStateEvent(const std::string& state); + + std::unique_ptr> event_channel_; + std::unique_ptr> event_sink_; + TizenInputMethodContext* imf_context_; +}; + +} // namespace flutter + +#endif // EMBEDDER_INPUT_PANEL_CHANNEL_H_ diff --git a/flutter/shell/platform/tizen/flutter_tizen_view.cc b/flutter/shell/platform/tizen/flutter_tizen_view.cc index 2dddeb6d..8e665707 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_view.cc +++ b/flutter/shell/platform/tizen/flutter_tizen_view.cc @@ -96,6 +96,8 @@ void FlutterTizenView::SetupChannels() { tizen_view_->input_method_context()); input_device_channel_ = std::make_unique(messenger); + input_panel_channel_ = std::make_unique( + messenger, tizen_view_->input_method_context()); } void FlutterTizenView::Resize(int32_t width, int32_t height) { diff --git a/flutter/shell/platform/tizen/flutter_tizen_view.h b/flutter/shell/platform/tizen/flutter_tizen_view.h index 1d3d0acc..085ec06d 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_view.h +++ b/flutter/shell/platform/tizen/flutter_tizen_view.h @@ -13,6 +13,7 @@ #include "flutter/shell/platform/common/client_wrapper/include/flutter/plugin_registrar.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/tizen/channels/input_device_channel.h" +#include "flutter/shell/platform/tizen/channels/input_panel_channel.h" #include "flutter/shell/platform/tizen/channels/mouse_cursor_channel.h" #include "flutter/shell/platform/tizen/channels/platform_channel.h" #include "flutter/shell/platform/tizen/channels/text_input_channel.h" @@ -188,6 +189,9 @@ class FlutterTizenView : public TizenViewEventHandlerDelegate { // A plugin to report input device information. std::unique_ptr input_device_channel_; + // A plugin to report input panel information. + std::unique_ptr input_panel_channel_; + // The current view rotation degree. int32_t rotation_degree_ = 0; diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.cc b/flutter/shell/platform/tizen/tizen_input_method_context.cc index 1ecf2e60..869d2c03 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.cc +++ b/flutter/shell/platform/tizen/tizen_input_method_context.cc @@ -143,9 +143,11 @@ TizenInputMethodContext::TizenInputMethodContext(uintptr_t window_id) { SetContextOptions(); SetInputPanelOptions(); RegisterEventCallbacks(); + RegisterInputPanelEventCallback(); } TizenInputMethodContext::~TizenInputMethodContext() { + UnregisterInputPanelEventCallback(); UnregisterEventCallbacks(); #ifdef NUI_SUPPORT @@ -386,4 +388,49 @@ void TizenInputMethodContext::SetInputPanelOptions() { imf_context_, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC); } +void TizenInputMethodContext::InputPanelStateChangedCallback( + void* data, + Ecore_IMF_Context* ctx, + int value) { + auto* self = static_cast(data); + Ecore_IMF_Input_Panel_State state = + static_cast(value); + + std::string state_str; + switch (state) { + case ECORE_IMF_INPUT_PANEL_STATE_SHOW: + state_str = "show"; + break; + case ECORE_IMF_INPUT_PANEL_STATE_HIDE: + state_str = "hide"; + break; + case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW: + state_str = "will_show"; + break; + default: + state_str = "unknown"; + break; + } + + if (self->on_input_panel_state_changed_) { + self->on_input_panel_state_changed_(state_str); + } +} + +void TizenInputMethodContext::RegisterInputPanelEventCallback() { + FT_ASSERT(imf_context_); + + ecore_imf_context_input_panel_event_callback_add( + imf_context_, ECORE_IMF_INPUT_PANEL_STATE_EVENT, + InputPanelStateChangedCallback, this); +} + +void TizenInputMethodContext::UnregisterInputPanelEventCallback() { + FT_ASSERT(imf_context_); + + ecore_imf_context_input_panel_event_callback_del( + imf_context_, ECORE_IMF_INPUT_PANEL_STATE_EVENT, + InputPanelStateChangedCallback); +} + } // namespace flutter diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.h b/flutter/shell/platform/tizen/tizen_input_method_context.h index ca5285f3..89e39825 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.h +++ b/flutter/shell/platform/tizen/tizen_input_method_context.h @@ -18,6 +18,7 @@ using OnCommit = std::function; using OnPreeditChanged = std::function; using OnPreeditStart = std::function; using OnPreeditEnd = std::function; +using OnInputPanelStateChanged = std::function; struct InputPanelGeometry { int32_t x = 0, y = 0, w = 0, h = 0; @@ -70,7 +71,20 @@ class TizenInputMethodContext { void SetOnPreeditEnd(OnPreeditEnd callback) { on_preedit_end_ = callback; } + void SetOnInputPanelStateChanged(OnInputPanelStateChanged callback) { + on_input_panel_state_changed_ = callback; + } + + void RegisterInputPanelEventCallback(); + void UnregisterInputPanelEventCallback(); + + Ecore_IMF_Context* GetImfContext() { return imf_context_; } + private: + static void InputPanelStateChangedCallback(void* data, + Ecore_IMF_Context* ctx, + int value); + void RegisterEventCallbacks(); void UnregisterEventCallbacks(); @@ -85,6 +99,7 @@ class TizenInputMethodContext { OnPreeditChanged on_preedit_changed_; OnPreeditStart on_preedit_start_; OnPreeditEnd on_preedit_end_; + OnInputPanelStateChanged on_input_panel_state_changed_; std::unordered_map event_callbacks_; }; From 63ddde9a0e61bd979b4ffc67f63743105cfb8e68 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Wed, 4 Feb 2026 13:55:18 +0900 Subject: [PATCH 2/2] Apply review comments --- flutter/shell/platform/tizen/channels/input_panel_channel.cc | 2 ++ flutter/shell/platform/tizen/tizen_input_method_context.h | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/flutter/shell/platform/tizen/channels/input_panel_channel.cc b/flutter/shell/platform/tizen/channels/input_panel_channel.cc index d8e3eae6..c2af019c 100644 --- a/flutter/shell/platform/tizen/channels/input_panel_channel.cc +++ b/flutter/shell/platform/tizen/channels/input_panel_channel.cc @@ -44,6 +44,8 @@ InputPanelChannel::InputPanelChannel(BinaryMessenger* messenger, } InputPanelChannel::~InputPanelChannel() { + event_channel_->SetStreamHandler(nullptr); + imf_context_->SetOnInputPanelStateChanged(nullptr); } diff --git a/flutter/shell/platform/tizen/tizen_input_method_context.h b/flutter/shell/platform/tizen/tizen_input_method_context.h index 89e39825..6915dd51 100644 --- a/flutter/shell/platform/tizen/tizen_input_method_context.h +++ b/flutter/shell/platform/tizen/tizen_input_method_context.h @@ -78,8 +78,6 @@ class TizenInputMethodContext { void RegisterInputPanelEventCallback(); void UnregisterInputPanelEventCallback(); - Ecore_IMF_Context* GetImfContext() { return imf_context_; } - private: static void InputPanelStateChangedCallback(void* data, Ecore_IMF_Context* ctx,