mirror of
https://github.com/openharmony/ace_ace_engine.git
synced 2026-07-19 22:54:50 -04:00
!2314 Make the input components in the previewer support keyboard input.
Merge pull request !2314 from ZhangYu/master
This commit is contained in:
@@ -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})" ]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 == "") {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user