!2314 Make the input components in the previewer support keyboard input.

Merge pull request !2314 from ZhangYu/master
This commit is contained in:
openharmony_ci
2022-04-25 10:55:45 +00:00
committed by Gitee
24 changed files with 1061 additions and 28 deletions
+14 -2
View File
@@ -34,6 +34,12 @@ template("preview_entrance_source") {
"ace_application_info.cpp",
"ace_container.cpp",
"ace_resource_register.cpp",
"clipboard/clipboard_impl.cpp",
"clipboard/clipboard_proxy_impl.cpp",
"editing/text_input_client_mgr.cpp",
"editing/text_input_connection_impl.cpp",
"editing/text_input_impl.cpp",
"editing/text_input_plugin.cpp",
"flutter_ace_view.cpp",
"subwindow_preview.cpp",
]
@@ -48,13 +54,19 @@ template("preview_entrance_source") {
if (!is_cross_platform_build) {
if (platform == "windows") {
defines -= [ "UNICODE" ]
include_dirs = [ "//utils/native/base/include" ]
include_dirs = [
"//utils/native/base/include",
"//third_party/glfw/include",
]
deps += [ "//base/global/resmgr_standard/frameworks/resmgr:global_resmgr_win(${current_toolchain})" ]
cflags_cc += [ "-DNONLS" ]
}
if (platform == "mac") {
include_dirs = [ "//utils/native/base/include" ]
include_dirs = [
"//utils/native/base/include",
"//third_party/glfw/include",
]
deps += [ "//base/global/resmgr_standard/frameworks/resmgr:global_resmgr_mac(${current_toolchain})" ]
}
}
+59
View File
@@ -28,6 +28,14 @@
#include "frameworks/core/components/common/painter/flutter_svg_painter.h"
#include "third_party/skia/include/core/SkFontMgr.h"
#include "third_party/skia/src/ports/SkFontMgr_config_parser.h"
#include "adapter/preview/entrance/editing/text_input_client_mgr.h"
#include "adapter/preview/entrance/clipboard/clipboard_impl.h"
#include "adapter/preview/entrance/clipboard/clipboard_proxy_impl.h"
#include "core/common/clipboard/clipboard_proxy.h"
#ifdef USE_GLFW_WINDOW
#include "adapter/preview/entrance/editing/text_input_plugin.h"
#endif
namespace OHOS::Ace::Platform {
@@ -171,6 +179,24 @@ std::unique_ptr<AceAbility> AceAbility::CreateInstance(AceRunArgs& runArgs)
auto controller = FlutterDesktopCreateWindow(
runArgs.deviceWidth, runArgs.deviceHeight, runArgs.windowTitle.c_str(), runArgs.onRender);
#ifdef USE_GLFW_WINDOW
std::unique_ptr<TextInputPlugin> textInputPlugin = std::make_unique<TextInputPlugin>();
textInputPlugin->RegisterKeyboardHookCallback((KeyboardHookCallback) AceAbility::DispatchKeyEvent);
textInputPlugin->RegisterCharHookCallback((CharHookCallback) AceAbility::DispatchInputMethodEvent);
FlutterDesktopAddKeyboardHookHandler(controller, std::move(textInputPlugin));
auto callbackSetClipboardData = [controller](const std::string& data) {
FlutterDesktopSetClipboardData(controller, data.c_str());
};
auto callbackGetClipboardData = [controller]() {
return FlutterDesktopGetClipboardData(controller);
};
ClipboardProxy::GetInstance()->SetDelegate(
std::make_unique<ClipboardProxyImpl>(callbackSetClipboardData, callbackGetClipboardData));
#endif
// Initial the proxy of Input method
TextInputClientMgr::GetInstance().InitTextInputProxy();
auto aceAbility = std::make_unique<AceAbility>(runArgs);
aceAbility->SetGlfwWindowController(controller);
return aceAbility;
@@ -344,6 +370,39 @@ bool AceAbility::DispatchBackPressedEvent()
return backFuture.get();
}
bool AceAbility::DispatchInputMethodEvent(unsigned int code_point)
{
return TextInputClientMgr::GetInstance().AddCharacter(static_cast<wchar_t>(code_point));
}
bool AceAbility::DispatchKeyEvent(const KeyEvent& event)
{
if (TextInputClientMgr::GetInstance().HandleKeyEvent(event)) {
LOGI("The event is related to the input component and has been handled successfully.");
return true;
}
auto container = AceContainer::GetContainerInstance(ACE_INSTANCE_ID);
if (!container) {
LOGE("container is null");
return false;
}
auto aceView = container->GetAceView();
if (!aceView) {
LOGE("aceView is null");
return false;
}
bool isHandled;
container->GetTaskExecutor()->PostTask(
[aceView, event, &isHandled]() {
isHandled = aceView->HandleKeyEvent(event);
},
TaskExecutor::TaskType::UI);
return isHandled;
}
void AceAbility::SetConfigChanges(const std::string& configChanges)
{
if (configChanges == "") {
+5 -9
View File
@@ -22,14 +22,8 @@
#include "adapter/preview/entrance/ace_run_args.h"
#include "core/event/touch_event.h"
#ifndef ACE_PREVIEW_EXPORT
#ifdef _WIN32
#define ACE_PREVIEW_EXPORT __declspec(dllexport)
#elif defined(__APPLE__)
#define ACE_PREVIEW_EXPORT __attribute__((visibility("default")))
#endif
#endif // ACE_PREVIEW_EXPORT
#include "core/event/key_event.h"
#include "base/utils/macros.h"
namespace OHOS::Ace::Platform {
@@ -54,7 +48,7 @@ struct SystemParams {
OHOS::Ace::DeviceOrientation orientation { DeviceOrientation::PORTRAIT };
};
class ACE_PREVIEW_EXPORT AceAbility {
class ACE_FORCE_EXPORT_WITH_PREVIEW AceAbility {
public:
explicit AceAbility(const AceRunArgs& runArgs);
~AceAbility();
@@ -67,6 +61,8 @@ public:
static bool DispatchTouchEvent(const TouchEvent& event);
static bool DispatchBackPressedEvent();
static bool DispatchInputMethodEvent(unsigned int code_point);
static bool DispatchKeyEvent(const KeyEvent& keyEvent);
void OnConfigurationChanged(const DeviceConfig& newConfig);
void SurfaceChanged(
+2 -9
View File
@@ -19,17 +19,10 @@
#include <functional>
#include <string>
#include "base/utils/macros.h"
#include "base/utils/device_type.h"
#include "base/utils/device_config.h"
#ifndef ACE_PREVIEW_EXPORT
#ifdef _WIN32
#define ACE_PREVIEW_EXPORT __declspec(dllexport)
#elif defined(__APPLE__)
#define ACE_PREVIEW_EXPORT __attribute__((visibility("default")))
#endif
#endif // ACE_PREVIEW_EXPORT
namespace OHOS::Ace::Platform {
using SendRenderDataCallback = bool (*)(const void*, const size_t, const int32_t, const int32_t);
@@ -49,7 +42,7 @@ enum class ProjectModel {
STAGE,
};
struct ACE_PREVIEW_EXPORT AceRunArgs {
struct ACE_FORCE_EXPORT_WITH_PREVIEW AceRunArgs {
// the adopted project model
ProjectModel projectModel = ProjectModel::FA;
// stores routing information
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "adapter/preview/entrance/clipboard/clipboard_impl.h"
namespace OHOS::Ace::Platform {
void ClipboardImpl::SetData(const std::string& data)
{
if (!taskExecutor_ || !callbackSetClipboardData_) {
LOGE("Failed to set the data to clipboard.");
return;
}
taskExecutor_->PostTask(
[callbackSetClipboardData = callbackSetClipboardData_, data] {
callbackSetClipboardData(data);
},
TaskExecutor::TaskType::PLATFORM);
}
void ClipboardImpl::GetData(const std::function<void(const std::string&)>& callback, bool syncMode)
{
if (!taskExecutor_ || !callbackGetClipboardData_ || !callback) {
LOGE("Failed to get the data from clipboard.");
return;
}
taskExecutor_->PostTask(
[callbackGetClipboardData = callbackGetClipboardData_, callback] {
callback(callbackGetClipboardData());
},
TaskExecutor::TaskType::PLATFORM);
}
void ClipboardImpl::Clear() {}
void ClipboardImpl::RegisterCallbackSetClipboardData(CallbackSetClipboardData callback)
{
callbackSetClipboardData_ = callback;
}
void ClipboardImpl::RegisterCallbackGetClipboardData(CallbackGetClipboardData callback)
{
callbackGetClipboardData_ = callback;
}
} // namespace OHOS::Ace::Platform
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOUNDATION_ACE_ACE_ENGINE_ADAPTER_PREVIEW_ENTRANCE_CLIPBOARD_CLIPBOARD_IMPL_H
#define FOUNDATION_ACE_ACE_ENGINE_ADAPTER_PREVIEW_ENTRANCE_CLIPBOARD_CLIPBOARD_IMPL_H
#include <string>
#include <functional>
#include "base/utils/macros.h"
#include "base/memory/referenced.h"
#include "base/thread/task_executor.h"
#include "core/common/clipboard/clipboard.h"
#include "core/common/clipboard/clipboard_interface.h"
namespace OHOS::Ace::Platform {
using CallbackSetClipboardData = std::function< void(const std::string&) >;
using CallbackGetClipboardData = std::function< const std::string(void) >;
class ACE_FORCE_EXPORT_WITH_PREVIEW ClipboardImpl : public Clipboard {
public:
explicit ClipboardImpl(const RefPtr<TaskExecutor>& taskExecutor) : Clipboard(taskExecutor) {}
~ClipboardImpl() override = default;
void SetData(const std::string& data) override;
void GetData(const std::function<void(const std::string&)>& callback, bool syncMode = false) override;
void Clear() override;
void RegisterCallbackSetClipboardData(CallbackSetClipboardData callback);
void RegisterCallbackGetClipboardData(CallbackGetClipboardData callback);
private:
CallbackSetClipboardData callbackSetClipboardData_;
CallbackGetClipboardData callbackGetClipboardData_;
};
} // namespace OHOS::Ace::Platform
#endif // FOUNDATION_ACE_ACE_ENGINE_ADAPTER_PREVIEW_ENTRANCE_CLIPBOARD_CLIPBOARD_IMPL_H
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "adapter/preview/entrance/clipboard/clipboard_proxy_impl.h"
namespace OHOS::Ace::Platform {
ClipboardProxyImpl::ClipboardProxyImpl(CallbackSetClipboardData callbackSetData,
CallbackGetClipboardData callbackGetData) : callbackSetClipboardData_(callbackSetData),
callbackGetClipboardData_(callbackGetData) {}
RefPtr<Clipboard> ClipboardProxyImpl::GetClipboard(const RefPtr<TaskExecutor>& taskExecutor) const
{
auto clipboard = AceType::MakeRefPtr<ClipboardImpl>(taskExecutor);
clipboard->RegisterCallbackSetClipboardData(callbackSetClipboardData_);
clipboard->RegisterCallbackGetClipboardData(callbackGetClipboardData_);
return clipboard;
}
} // namespace OHOS::Ace::Platform
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOUNDATION_ACE_ACE_ENGINE_ADAPTER_PREVIEW_ENTRANCE_CLIPBOARD_CLIPBOARD_PROXY_IMPL_H
#define FOUNDATION_ACE_ACE_ENGINE_ADAPTER_PREVIEW_ENTRANCE_CLIPBOARD_CLIPBOARD_PROXY_IMPL_H
#include "base/utils/macros.h"
#include "core/common/clipboard/clipboard.h"
#include "adapter/preview/entrance/clipboard/clipboard_impl.h"
namespace OHOS::Ace::Platform {
class ACE_FORCE_EXPORT_WITH_PREVIEW ClipboardProxyImpl : public ClipboardInterface {
public:
ClipboardProxyImpl(CallbackSetClipboardData callbackSetData, CallbackGetClipboardData callbackGetData);
~ClipboardProxyImpl() = default;
RefPtr<Clipboard> GetClipboard(const RefPtr<TaskExecutor>& taskExecutor) const override;
private:
CallbackSetClipboardData callbackSetClipboardData_;
CallbackGetClipboardData callbackGetClipboardData_;
};
} // namespace OHOS::Ace::Platform
#endif // FOUNDATION_ACE_ACE_ENGINE_ADAPTER_PREVIEW_ENTRANCE_CLIPBOARD_CLIPBOARD_PROXY_IMPL_H
@@ -0,0 +1,238 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "adapter/preview/entrance/editing/text_input_client_mgr.h"
#include <map>
#include "base/utils/string_utils.h"
#include "base/memory/ace_type.h"
#include "core/common/ime/constant.h"
#include "core/common/ime/text_selection.h"
#include "core/common/ime/text_editing_value.h"
#include "core/common/ime/text_input_proxy.h"
#include "adapter/preview/entrance/editing/text_input_impl.h"
namespace OHOS::Ace::Platform {
namespace {
const wchar_t UPPER_CASE_A = L'A';
const wchar_t LOWER_CASE_A = L'a';
const wchar_t CASE_0 = L'0';
const std::wstring NUM_SYMBOLS = L")!@#$%^&*(";
const std::map<KeyCode, wchar_t> PRINTABEL_SYMBOLS = {
{KeyCode::KEY_GRAVE, L'`'},
{KeyCode::KEY_MINUS, L'-'},
{KeyCode::KEY_EQUALS, L'='},
{KeyCode::KEY_LEFT_BRACKET, L'['},
{KeyCode::KEY_RIGHT_BRACKET, L']'},
{KeyCode::KEY_BACKSLASH, L'\\'},
{KeyCode::KEY_SEMICOLON, L';'},
{KeyCode::KEY_APOSTROPHE, L'\''},
{KeyCode::KEY_COMMA, L','},
{KeyCode::KEY_PERIOD, L'.'},
{KeyCode::KEY_SLASH, L'/'},
{KeyCode::KEY_SPACE, L' '},
{KeyCode::KEY_NUMPAD_DIVIDE, L'/'},
{KeyCode::KEY_NUMPAD_MULTIPLY, L'*'},
{KeyCode::KEY_NUMPAD_SUBTRACT, L'-'},
{KeyCode::KEY_NUMPAD_ADD, L'+'},
{KeyCode::KEY_NUMPAD_DOT, L'.'},
{KeyCode::KEY_NUMPAD_COMMA, L','},
{KeyCode::KEY_NUMPAD_EQUALS, L'='},
};
const std::map<KeyCode, wchar_t> SHIFT_PRINTABEL_SYMBOLS = {
{KeyCode::KEY_GRAVE, L'~'},
{KeyCode::KEY_MINUS, L'_'},
{KeyCode::KEY_EQUALS, L'+'},
{KeyCode::KEY_LEFT_BRACKET, L'{'},
{KeyCode::KEY_RIGHT_BRACKET, L'}'},
{KeyCode::KEY_BACKSLASH, L'|'},
{KeyCode::KEY_SEMICOLON, L':'},
{KeyCode::KEY_APOSTROPHE, L'\"'},
{KeyCode::KEY_COMMA, L'<'},
{KeyCode::KEY_PERIOD, L'>'},
{KeyCode::KEY_SLASH, L'?'},
};
}
TextInputClientMgr::TextInputClientMgr() : clientId_(IME_CLIENT_ID_NONE), enableCapsLock_(false),
enableNumLock_(true), currentConnection_(nullptr)
{}
TextInputClientMgr::~TextInputClientMgr() = default;
void TextInputClientMgr::InitTextInputProxy()
{
// Initial the proxy of Input method
TextInputProxy::GetInstance().SetDelegate(std::make_unique<TextInputImpl>());
}
void TextInputClientMgr::SetClientId(const int32_t clientId)
{
clientId_ = clientId;
}
void TextInputClientMgr::ResetClientId()
{
SetClientId(IME_CLIENT_ID_NONE);
}
bool TextInputClientMgr::IsValidClientId() const
{
return clientId_ != IME_CLIENT_ID_NONE;
}
bool TextInputClientMgr::AddCharacter(const wchar_t wideChar)
{
LOGI("The unicode of inputed character is: %{public}d.", static_cast<int32_t>(wideChar));
if (!IsValidClientId()) {
return false;
}
std::wstring appendElement(1, wideChar);
auto textEditingValue = std::make_shared<TextEditingValue>();
textEditingValue->text = textEditingValue_.GetBeforeSelection() + StringUtils::ToString(appendElement) +
textEditingValue_.GetAfterSelection();
textEditingValue->UpdateSelection(std::max(textEditingValue_.selection.GetStart(), 0) + appendElement.length());
SetTextEditingValue(*textEditingValue);
return UpdateEditingValue(textEditingValue);
}
bool TextInputClientMgr::HandleTextKeyEvent(const KeyEvent& event)
{
// Only the keys involved in the input component are processed here, and the other keys will be forwarded.
if (!IsValidClientId()) {
return false;
}
const static size_t maxKeySizes = 2;
wchar_t keyChar;
if (event.pressedCodes.size() == 1) {
auto iterCode = PRINTABEL_SYMBOLS.find(event.code);
if (iterCode != PRINTABEL_SYMBOLS.end()) {
keyChar = iterCode->second;
} else if (KeyCode::KEY_0 <= event.code && event.code <= KeyCode::KEY_9) {
keyChar = static_cast<wchar_t>(event.code) - static_cast<wchar_t>(KeyCode::KEY_0) + CASE_0;
} else if (KeyCode::KEY_NUMPAD_0 <= event.code && event.code <= KeyCode::KEY_NUMPAD_9) {
if (!enableNumLock_) {
return true;
}
keyChar = static_cast<wchar_t>(event.code) - static_cast<wchar_t>(KeyCode::KEY_NUMPAD_0) + CASE_0;
} else if (KeyCode::KEY_A <= event.code && event.code <= KeyCode::KEY_Z) {
keyChar = static_cast<wchar_t>(event.code) - static_cast<wchar_t>(KeyCode::KEY_A);
keyChar += (enableCapsLock_ ? UPPER_CASE_A : LOWER_CASE_A);
} else {
return false;
}
} else if (event.pressedCodes.size() == maxKeySizes && event.pressedCodes[0] == KeyCode::KEY_SHIFT_LEFT) {
auto iterCode = SHIFT_PRINTABEL_SYMBOLS.find(event.code);
if (iterCode != SHIFT_PRINTABEL_SYMBOLS.end()) {
keyChar = iterCode->second;
} else if (KeyCode::KEY_A <= event.code && event.code <= KeyCode::KEY_Z) {
keyChar = static_cast<wchar_t>(event.code) - static_cast<wchar_t>(KeyCode::KEY_A);
keyChar += (enableCapsLock_ ? LOWER_CASE_A : UPPER_CASE_A);
} else if (KeyCode::KEY_0 <= event.code && event.code <= KeyCode::KEY_9) {
keyChar = NUM_SYMBOLS[static_cast<int32_t>(event.code) - static_cast<int32_t>(KeyCode::KEY_0)];
} else {
return false;
}
} else {
return false;
}
if (event.action != KeyAction::DOWN) {
return true;
}
return AddCharacter(keyChar);
}
bool TextInputClientMgr::HandleKeyEvent(const KeyEvent& event)
{
if (event.action == KeyAction::DOWN) {
if (event.IsKey({ KeyCode::KEY_CAPS_LOCK })) {
enableCapsLock_ = !enableCapsLock_;
return true;
} else if (event.IsKey({ KeyCode::KEY_NUM_LOCK })) {
enableNumLock_ = !enableNumLock_;
return true;
}
}
// Process all printable characters.
return HandleTextKeyEvent(event);
}
void TextInputClientMgr::SetTextEditingValue(const TextEditingValue& textEditingValue)
{
textEditingValue_ = textEditingValue;
}
void TextInputClientMgr::SetCurrentConnection(const RefPtr<TextInputConnection>& currentConnection)
{
currentConnection_ = currentConnection;
}
bool TextInputClientMgr::IsCurrentConnection(const TextInputConnection* connection) const
{
return currentConnection_ == connection;
}
bool TextInputClientMgr::UpdateEditingValue(const std::shared_ptr<TextEditingValue>& value, bool needFireChangeEvent)
{
if (!currentConnection_ || currentConnection_->GetClientId() != clientId_) {
return false;
}
auto weak = AceType::WeakClaim(AceType::RawPtr(currentConnection_));
currentConnection_->GetTaskExecutor()->PostTask(
[weak, value, needFireChangeEvent]() {
auto currentConnection = weak.Upgrade();
if (currentConnection == nullptr) {
LOGE("currentConnection is nullptr");
return;
}
auto client = currentConnection->GetClient();
if (client) {
client->UpdateEditingValue(value, needFireChangeEvent);
}
},
TaskExecutor::TaskType::UI);
return true;
}
bool TextInputClientMgr::PerformAction(const TextInputAction action)
{
if (!currentConnection_ || currentConnection_->GetClientId() != clientId_) {
return false;
}
auto weak = AceType::WeakClaim(AceType::RawPtr(currentConnection_));
currentConnection_->GetTaskExecutor()->PostTask(
[weak, action]() {
auto currentConnection = weak.Upgrade();
if (currentConnection == nullptr) {
LOGE("currentConnection is nullptr");
return;
}
auto client = currentConnection->GetClient();
if (client) {
client->PerformAction(action);
}
},
TaskExecutor::TaskType::UI);
return true;
}
} // namespace OHOS::Ace::Platform
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOUNDATION_ACE_ADAPTER_PREVIEW_ENTRANCE_EDITING_TEXT_INPUT_CLIENT_MGR_H
#define FOUNDATION_ACE_ADAPTER_PREVIEW_ENTRANCE_EDITING_TEXT_INPUT_CLIENT_MGR_H
#include "base/memory/referenced.h"
#include "base/utils/singleton.h"
#include "core/event/key_event.h"
#include "core/common/clipboard/clipboard_proxy.h"
#include "core/common/ime/text_input_connection.h"
namespace OHOS::Ace::Platform {
class TextInputClientMgr : public Singleton<TextInputClientMgr> {
DECLARE_SINGLETON(TextInputClientMgr);
public:
void InitTextInputProxy();
void SetClientId(const int32_t clientId);
// Set the current client id to invalid value.
void ResetClientId();
bool IsValidClientId() const;
void SetTextEditingValue(const TextEditingValue& textEditingValue);
void SetCurrentConnection(const RefPtr<TextInputConnection>& currentConnection);
bool IsCurrentConnection(const TextInputConnection* connection) const;
bool AddCharacter(const wchar_t wideChar);
bool HandleKeyEvent(const KeyEvent& event);
private:
// Process all printable characters. If the input method is used, this function is invalid.
bool HandleTextKeyEvent(const KeyEvent& event);
bool PerformAction(const TextInputAction action);
bool UpdateEditingValue(const std::shared_ptr<TextEditingValue>& value, bool needFireChangeEvent = true);
int32_t clientId_;
bool enableCapsLock_;
bool enableNumLock_;
TextEditingValue textEditingValue_;
RefPtr<TextInputConnection> currentConnection_;
};
} // namespace OHOS::Ace::Platform
#endif // FOUNDATION_ACE_ADAPTER_PREVIEW_ENTRANCE_EDITING_TEXT_INPUT_CLIENT_MGR_H
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "adapter/preview/entrance/editing/text_input_connection_impl.h"
#include "adapter/preview/entrance/editing/text_input_client_mgr.h"
namespace OHOS::Ace::Platform {
void TextInputConnectionImpl::Show(bool isFocusViewChanged, int32_t instanceId)
{}
void TextInputConnectionImpl::SetEditingState(
const TextEditingValue& value, int32_t instanceId, bool needFireChangeEvent)
{
if (taskExecutor_ && Attached()) {
taskExecutor_->PostTask(
[value, instanceId, needFireChangeEvent] {
TextInputClientMgr::GetInstance().SetTextEditingValue(value);
},
TaskExecutor::TaskType::PLATFORM);
}
}
void TextInputConnectionImpl::Close(int32_t instanceId)
{
// Set the current client id to invalid value.
TextInputClientMgr::GetInstance().ResetClientId();
TextInputClientMgr::GetInstance().SetCurrentConnection(nullptr);
if (Attached()) {
LOGE("Text input connection close failed.");
}
}
bool TextInputConnectionImpl::Attached()
{
return TextInputClientMgr::GetInstance().IsCurrentConnection(this);
}
} // namespace OHOS::Ace::Platform
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOUNDATION_ACE_ADAPTER_PREVIEW_ENTRANCE_EDITING_TEXT_INPUT_CONNECTION_IMPL_H
#define FOUNDATION_ACE_ADAPTER_PREVIEW_ENTRANCE_EDITING_TEXT_INPUT_CONNECTION_IMPL_H
#include "base/memory/ace_type.h"
#include "base/thread/task_executor.h"
#include "core/common/ime/constant.h"
#include "core/common/ime/text_editing_value.h"
#include "core/common/ime/text_input_client.h"
#include "core/common/ime/text_input_connection.h"
namespace OHOS::Ace::Platform {
class TextInputConnectionImpl : public TextInputConnection {
DECLARE_ACE_TYPE(TextInputConnectionImpl, TextInputConnection);
public:
TextInputConnectionImpl() = delete;
TextInputConnectionImpl(const WeakPtr<TextInputClient>&client, const RefPtr<TaskExecutor>& taskExecutor)
: TextInputConnection(client, taskExecutor)
{}
~TextInputConnectionImpl() override = default;
void Show(bool isFocusViewChanged, int32_t instanceId) override;
void SetEditingState(
const TextEditingValue& value, int32_t instanceId, bool needFireChangeEvent = true) override;
void Close(int32_t instanceId) override;
private:
bool Attached();
};
} // namespace OHOS::Ace::Platform
#endif // FOUNDATION_ACE_ADAPTER_PREVIEW_ENTRANCE_EDITING_TEXT_INPUT_CONNECTION_IMPL_H
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "adapter/preview/entrance/editing/text_input_impl.h"
#include "base/log/log.h"
#include "adapter/preview/entrance/editing/text_input_client_mgr.h"
#include "adapter/preview/entrance/editing/text_input_connection_impl.h"
namespace OHOS::Ace::Platform {
RefPtr<TextInputConnection> TextInputImpl::Attach(const WeakPtr<TextInputClient>& client,
const TextInputConfiguration& config, const RefPtr<TaskExecutor>& taskExecutor, int32_t instanceId)
{
auto connection = AceType::MakeRefPtr<TextInputConnectionImpl>(client, taskExecutor);
TextInputClientMgr::GetInstance().SetCurrentConnection(connection);
taskExecutor->PostTask(
[clientId = connection->GetClientId(), config, instanceId] {
TextInputClientMgr::GetInstance().SetClientId(clientId);
},
TaskExecutor::TaskType::PLATFORM);
return connection;
}
} // namespace OHOS::Ace::Platform
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOUNDATION_ACE_ADAPTER_PREVIEW_ENTRANCE_EDITING_TEXT_INPUT_IMPL_H
#define FOUNDATION_ACE_ADAPTER_PREVIEW_ENTRANCE_EDITING_TEXT_INPUT_IMPL_H
#include "base/memory/referenced.h"
#include "base/thread/task_executor.h"
#include "core/common/ime/text_input.h"
#include "core/common/ime/text_input_client.h"
#include "core/common/ime/text_input_configuration.h"
#include "core/common/ime/text_input_connection.h"
namespace OHOS::Ace::Platform {
class TextInputImpl : public TextInput {
public:
TextInputImpl() = default;
~TextInputImpl() override = default;
RefPtr<TextInputConnection> Attach(const WeakPtr<TextInputClient>& client, const TextInputConfiguration& config,
const RefPtr<TaskExecutor>& taskExecutor, int32_t instanceId) override;
};
} // namespace OHOS::Ace::Platform
#endif // FOUNDATION_ACE_ADAPTER_PREVIEW_ENTRANCE_EDITING_TEXT_INPUT_IMPL_H
@@ -0,0 +1,135 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "adapter/preview/entrance/editing/text_input_plugin.h"
#include <map>
#include "base/log/log.h"
namespace OHOS::Ace::Platform {
namespace {
const std::map<int, KeyAction> ACTION_MAP = {
{GLFW_RELEASE, KeyAction::UP},
{GLFW_PRESS, KeyAction::DOWN},
{GLFW_REPEAT, KeyAction::LONG_PRESS},
};
const std::map<int, KeyCode> CODE_MAP = {
{GLFW_KEY_BACKSPACE, KeyCode::KEY_FORWARD_DEL},
{GLFW_KEY_DELETE, KeyCode::KEY_DEL},
{GLFW_KEY_ESCAPE, KeyCode::KEY_ESCAPE},
{GLFW_KEY_ENTER, KeyCode::KEY_ENTER},
{GLFW_KEY_CAPS_LOCK, KeyCode::KEY_CAPS_LOCK},
{GLFW_KEY_UP, KeyCode::KEY_DPAD_UP},
{GLFW_KEY_DOWN, KeyCode::KEY_DPAD_DOWN},
{GLFW_KEY_LEFT, KeyCode::KEY_DPAD_LEFT},
{GLFW_KEY_RIGHT, KeyCode::KEY_DPAD_RIGHT},
{GLFW_KEY_GRAVE_ACCENT, KeyCode::KEY_GRAVE},
{GLFW_KEY_MINUS, KeyCode::KEY_MINUS},
{GLFW_KEY_EQUAL, KeyCode::KEY_EQUALS},
{GLFW_KEY_TAB, KeyCode::KEY_TAB},
{GLFW_KEY_LEFT_BRACKET, KeyCode::KEY_LEFT_BRACKET},
{GLFW_KEY_RIGHT_BRACKET, KeyCode::KEY_RIGHT_BRACKET},
{GLFW_KEY_BACKSLASH, KeyCode::KEY_BACKSLASH},
{GLFW_KEY_SEMICOLON, KeyCode::KEY_SEMICOLON},
{GLFW_KEY_APOSTROPHE, KeyCode::KEY_APOSTROPHE},
{GLFW_KEY_COMMA, KeyCode::KEY_COMMA},
{GLFW_KEY_PERIOD, KeyCode::KEY_PERIOD},
{GLFW_KEY_SLASH, KeyCode::KEY_SLASH},
{GLFW_KEY_SPACE, KeyCode::KEY_SPACE},
{GLFW_KEY_KP_DIVIDE, KeyCode::KEY_NUMPAD_DIVIDE},
{GLFW_KEY_KP_MULTIPLY, KeyCode::KEY_NUMPAD_MULTIPLY},
{GLFW_KEY_KP_SUBTRACT, KeyCode::KEY_NUMPAD_SUBTRACT},
{GLFW_KEY_KP_ADD, KeyCode::KEY_NUMPAD_ADD},
{GLFW_KEY_KP_ENTER, KeyCode::KEY_NUMPAD_ENTER},
{GLFW_KEY_KP_EQUAL, KeyCode::KEY_NUMPAD_EQUALS},
{GLFW_KEY_NUM_LOCK, KeyCode::KEY_NUM_LOCK},
};
}
void TextInputPlugin::KeyboardHook(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (RecognizeKeyEvent(key, action, mods)) {
keyboardHookCallback_(keyEvent_);
} else {
LOGW("Unrecognized key type.");
}
}
void TextInputPlugin::CharHook(GLFWwindow* window, unsigned int code_point)
{
LOGW("Input method is not currently supported");
}
void TextInputPlugin::RegisterKeyboardHookCallback(KeyboardHookCallback&& keyboardHookCallback)
{
if (keyboardHookCallback) {
keyboardHookCallback_ = std::move(keyboardHookCallback);
}
}
void TextInputPlugin::RegisterCharHookCallback(CharHookCallback&& charHookCallback)
{
if (charHookCallback) {
charHookCallback_ = std::move(charHookCallback);
}
}
bool TextInputPlugin::RecognizeKeyEvent(int key, int action, int mods)
{
auto iterAction = ACTION_MAP.find(action);
if (iterAction == ACTION_MAP.end()) {
return false;
}
keyEvent_.action = iterAction->second;
keyEvent_.pressedCodes.clear();
if (mods & GLFW_MOD_CONTROL) {
keyEvent_.pressedCodes.push_back(KeyCode::KEY_CTRL_LEFT);
}
if (mods & GLFW_MOD_SHIFT) {
keyEvent_.pressedCodes.push_back(KeyCode::KEY_SHIFT_LEFT);
}
if (mods & GLFW_MOD_ALT) {
keyEvent_.pressedCodes.push_back(KeyCode::KEY_ALT_LEFT);
}
auto iterCode = CODE_MAP.find(key);
if (iterCode == CODE_MAP.end() && !(key >= GLFW_KEY_A && key <= GLFW_KEY_Z) &&
!(key >= GLFW_KEY_0 && key <= GLFW_KEY_9) && !(key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_9)) {
return false;
}
if (iterCode != CODE_MAP.end()) {
keyEvent_.code = iterCode->second;
}
if (key >= GLFW_KEY_A && key <= GLFW_KEY_Z) {
keyEvent_.code = static_cast<KeyCode>(static_cast<int32_t>(KeyCode::KEY_A) + key - GLFW_KEY_A);
}
if (key >= GLFW_KEY_0 && key <= GLFW_KEY_9) {
keyEvent_.code = static_cast<KeyCode>(static_cast<int32_t>(KeyCode::KEY_0) + key - GLFW_KEY_0);
}
if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_9) {
keyEvent_.code = static_cast<KeyCode>(static_cast<int32_t>(KeyCode::KEY_0) + key - GLFW_KEY_KP_0);
}
keyEvent_.key = KeyToString(static_cast<int32_t>(keyEvent_.code));
keyEvent_.pressedCodes.push_back(keyEvent_.code);
return true;
}
} // namespace OHOS::Ace::Platform
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOUNDATION_ACE_ADAPTER_PREVIEW_ENTRANCE_EDITING_TEXT_INPUT_PLUGIN_H
#define FOUNDATION_ACE_ADAPTER_PREVIEW_ENTRANCE_EDITING_TEXT_INPUT_PLUGIN_H
#include "flutter/shell/platform/glfw/keyboard_hook_handler.h"
#include "core/event/key_event.h"
namespace OHOS::Ace::Platform {
using KeyboardHookCallback = std::function<bool(const KeyEvent& keyEvent)>;
using CharHookCallback = std::function<bool(unsigned int code_point)>;
class TextInputPlugin : public flutter::KeyboardHookHandler {
public:
TextInputPlugin() = default;
~TextInputPlugin() override = default;
// A function for hooking into keyboard input.
void KeyboardHook(GLFWwindow* window, int key, int scancode, int action, int mods) override;
// A function for hooking into unicode code point input.
void CharHook(GLFWwindow* window, unsigned int code_point) override;
// Register the dispatch function of the keyboard event
void RegisterKeyboardHookCallback(KeyboardHookCallback&& keyboardHookCallback);
// Register the dispatch function of the input method event
void RegisterCharHookCallback(CharHookCallback&& charHookCallback);
private:
bool RecognizeKeyEvent(int key, int action, int mods);
KeyEvent keyEvent_;
CharHookCallback charHookCallback_;
KeyboardHookCallback keyboardHookCallback_;
};
} // namespace OHOS::Ace::Platform
#endif // FOUNDATION_ACE_ADAPTER_PREVIEW_ENTRANCE_EDITING_TEXT_INPUT_PLUGIN_H
@@ -172,6 +172,15 @@ bool FlutterAceView::HandleTouchEvent(const TouchEvent& touchEvent)
return true;
}
bool FlutterAceView::HandleKeyEvent(const KeyEvent& keyEvent)
{
if (!keyEventCallback_) {
return false;
}
return keyEventCallback_(keyEvent);
}
std::unique_ptr<DrawDelegate> FlutterAceView::GetDrawDelegate()
{
auto drawDelegate = std::make_unique<DrawDelegate>();
@@ -142,6 +142,9 @@ public:
// Use to receive event from pc previewer
bool HandleTouchEvent(const TouchEvent& touchEvent) override;
// Use to receive event from pc previewer
bool HandleKeyEvent(const KeyEvent& keyEvent) override;
ViewType GetViewType() const override
{
return AceView::ViewType::SURFACE_VIEW;
+5
View File
@@ -90,6 +90,11 @@ public:
{
return false;
}
// Use to receive key event from pc previewer
virtual bool HandleKeyEvent(const KeyEvent& keyEvent)
{
return false;
}
// Use to get native window handle by texture id
virtual const void* GetNativeWindowById(uint64_t textureId) = 0;
@@ -21,7 +21,7 @@
namespace OHOS::Ace {
class ACE_EXPORT ClipboardProxy : public ClipboardInterface {
class ACE_EXPORT_WITH_PREVIEW ClipboardProxy : public ClipboardInterface {
public:
static ClipboardProxy* GetInstance();
ClipboardProxy() = default;
@@ -947,10 +947,14 @@ const TextEditingValue& RenderTextField::GetPreEditingValue() const
return controller_->GetPreValue();
}
void RenderTextField::SetEditingValue(TextEditingValue&& newValue, bool needFireChangeEvent)
void RenderTextField::SetEditingValue(TextEditingValue&& newValue, bool needFireChangeEvent, bool isClearRecords)
{
if (newValue.text != GetEditingValue().text && needFireChangeEvent) {
needNotifyChangeEvent_ = true;
operationRecords_.push_back(newValue);
if (isClearRecords) {
inverseOperationRecords_.clear();
}
}
ChangeCounterStyle(newValue);
auto context = context_.Upgrade();
@@ -1218,6 +1222,12 @@ bool RenderTextField::OnKeyEvent(const KeyEvent& event)
if (event.action == KeyAction::DOWN) {
cursorPositionType_ = CursorPositionType::NONE;
if (KeyCode::TV_CONTROL_UP <= event.code && event.code <= KeyCode::TV_CONTROL_RIGHT && (
event.IsKey({ KeyCode::KEY_SHIFT_LEFT, event.code }) ||
event.IsKey({ KeyCode::KEY_SHIFT_RIGHT, event.code }))) {
HandleOnSelect(event.code);
return true;
}
if (event.code == KeyCode::TV_CONTROL_LEFT) {
CursorMoveLeft();
obscureTickPendings_ = 0;
@@ -1238,6 +1248,18 @@ bool RenderTextField::OnKeyEvent(const KeyEvent& event)
obscureTickPendings_ = 0;
return true;
}
if (event.code == KeyCode::KEY_FORWARD_DEL) {
int32_t startPos = GetEditingValue().selection.GetStart();
int32_t endPos = GetEditingValue().selection.GetEnd();
Delete(startPos, startPos==endPos ? startPos-1 : endPos);
return true;
}
if (event.code == KeyCode::KEY_DEL) {
int32_t startPos = GetEditingValue().selection.GetStart();
int32_t endPos = GetEditingValue().selection.GetEnd();
Delete(startPos, startPos==endPos ? startPos+1 : endPos);
return true;
}
}
return HandleKeyEvent(event);
}
@@ -1665,6 +1687,77 @@ void RenderTextField::SetIsOverlayShowed(bool isOverlayShowed, bool needStartTwi
}
}
void RenderTextField::HandleOnSelect(KeyCode keyCode, CursorMoveSkip skip)
{
if (skip != CursorMoveSkip::CHARACTER) {
// Not support yet.
LOGE("move skip not support character yet");
return;
}
isValueFromRemote_ = false;
auto value = GetEditingValue();
int32_t startPos = value.selection.GetStart();
int32_t endPos = value.selection.GetEnd();
static bool isForwardSelect;
switch (keyCode) {
case KeyCode::KEY_DPAD_LEFT:
if (startPos == endPos) {
isForwardSelect = true;
}
if (isForwardSelect) {
value.UpdateSelection(startPos-1, endPos);
} else {
value.UpdateSelection(startPos, endPos-1);
}
break;
case KeyCode::KEY_DPAD_RIGHT:
if (startPos == endPos) {
isForwardSelect = false;
}
if (isForwardSelect) {
value.UpdateSelection(startPos+1, endPos);
} else {
value.UpdateSelection(startPos, endPos+1);
}
break;
default:
LOGI("Currently only left and right selections are supported.");
return;
}
SetEditingValue(std::move(value));
MarkNeedLayout();
}
void RenderTextField::HandleOnRevoke()
{
if (operationRecords_.empty()) {
return;
}
inverseOperationRecords_.push_back(GetEditingValue());
operationRecords_.pop_back();
auto value = operationRecords_.back();
operationRecords_.pop_back();
isValueFromRemote_ = false;
SetEditingValue(std::move(value), true, false);
cursorPositionType_ = CursorPositionType::NONE;
MarkNeedLayout();
}
void RenderTextField::HandleOnInverseRevoke()
{
if (inverseOperationRecords_.empty()) {
return;
}
auto value = inverseOperationRecords_.back();
inverseOperationRecords_.pop_back();
isValueFromRemote_ = false;
SetEditingValue(std::move(value), true, false);
cursorPositionType_ = CursorPositionType::NONE;
MarkNeedLayout();
}
void RenderTextField::HandleOnCut()
{
if (!clipboard_) {
@@ -1778,11 +1871,25 @@ bool RenderTextField::HandleKeyEvent(const KeyEvent& event)
{
std::string appendElement;
if (event.action == KeyAction::DOWN) {
if (event.IsNumberKey()) {
if (event.code == KeyCode::KEY_ENTER || event.code == KeyCode::KEY_NUMPAD_ENTER) {
if (keyboard_ == TextInputType::MULTILINE) {
appendElement = "\n";
}
} else if (event.IsNumberKey()) {
appendElement = event.ConvertCodeToString();
} else if (event.IsLetterKey()) {
if (event.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_A }) ||
event.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_A })) {
if (event.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_SHIFT_LEFT, KeyCode::KEY_Z }) ||
event.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_SHIFT_RIGHT, KeyCode::KEY_Z }) ||
event.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_SHIFT_LEFT, KeyCode::KEY_Z }) ||
event.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_SHIFT_RIGHT, KeyCode::KEY_Z }) ||
event.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_Y }) ||
event.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_Y })) {
HandleOnInverseRevoke();
} else if (event.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_Z }) ||
event.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_Z })) {
HandleOnRevoke();
} else if (event.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_A }) ||
event.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_A })) {
HandleOnCopyAll(nullptr);
} else if (event.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_C }) ||
event.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_C })) {
@@ -1802,11 +1909,19 @@ bool RenderTextField::HandleKeyEvent(const KeyEvent& event)
if (appendElement.empty()) {
return false;
}
#if defined(WINDOWS_PLATFORM) || defined(MAC_PLATFORM)
auto editingValue = GetEditingValue();
editingValue.text = editingValue.GetBeforeSelection() + appendElement + editingValue.GetAfterSelection();
editingValue.UpdateSelection(
std::max(editingValue.selection.GetEnd(), 0) + StringUtils::Str8ToStr16(appendElement).length());
SetEditingValue(std::move(editingValue));
#else
auto editingValue = std::make_shared<TextEditingValue>();
editingValue->text = GetEditingValue().GetBeforeSelection() + appendElement + GetEditingValue().GetAfterSelection();
editingValue->UpdateSelection(
std::max(GetEditingValue().selection.GetEnd(), 0) + StringUtils::Str8ToStr16(appendElement).length());
UpdateEditingValue(editingValue);
#endif
MarkNeedLayout();
return true;
}
@@ -353,7 +353,7 @@ protected:
void OnLongPress(const LongPressInfo& longPressInfo);
bool HandleMouseEvent(const MouseEvent& event) override;
void SetEditingValue(TextEditingValue&& newValue, bool needFireChangeEvent = true);
void SetEditingValue(TextEditingValue&& newValue, bool needFireChangeEvent = true, bool isClearRecords = true);
std::u16string GetTextForDisplay(const std::string& text) const;
void UpdateStartSelection(int32_t end, const Offset& pos, bool isSingleHandle, bool isLongPress);
@@ -525,6 +525,9 @@ private:
void UpdatePasswordIcon(const RefPtr<TextFieldComponent>& textField);
void UpdateOverlay();
void RegisterFontCallbacks();
void HandleOnSelect(KeyCode keyCode, CursorMoveSkip skip = CursorMoveSkip::CHARACTER);
void HandleOnRevoke();
void HandleOnInverseRevoke();
void HandleOnCut();
void HandleOnCopy();
void HandleOnPaste();
@@ -618,6 +621,8 @@ private:
RefPtr<RawRecognizer> rawRecognizer_;
RefPtr<Animator> pressController_;
RefPtr<Animator> animator_;
std::vector<TextEditingValue> operationRecords_;
std::vector<TextEditingValue> inverseOperationRecords_;
#if defined(OHOS_STANDARD_SYSTEM) && !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
bool imeAttached_ = false;
#endif
+1 -1
View File
@@ -442,7 +442,7 @@ enum class KeyAction : int32_t {
constexpr int32_t ASCII_START_UPPER_CASE_LETTER = 65;
constexpr int32_t ASCII_START_LOWER_CASE_LETTER = 97;
const char* KeyToString(int32_t code);
ACE_FORCE_EXPORT_WITH_PREVIEW const char* KeyToString(int32_t code);
struct KeyEvent final {
KeyEvent()
@@ -1594,7 +1594,6 @@ bool PipelineContext::OnKeyEvent(const KeyEvent& event)
if (event.action == KeyAction::UP) {
SetIsKeyEvent(true);
}
return true;
} else if (event.code == KeyCode::KEY_ENTER) {
if (event.action == KeyAction::CLICK) {
SetIsKeyEvent(true);