Description: implement raw input event injecting tool

IssueNo:IAUTBL
Feature or Bugfix: Feature
Binary Source:No

Signed-off-by: jiadexiang <jiadexiang@huawei.com>
This commit is contained in:
piggyguy 2024-10-03 22:23:50 +08:00
parent 20bfe8fe12
commit 37219f3851
13 changed files with 1719 additions and 0 deletions

View File

@ -162,6 +162,7 @@ adapter/ohos/osal/want_wrap_ohos.cpp @arkui_superman
adapter/ohos/osal/want_wrap_ohos.h @arkui_superman
adapter/ohos/sa_profile/ @arkuiframework
adapter/ohos/services/ @arkuiframework
adapter/ohos/tools/raw_input_injector/ @arkuievent
[Preview adapter]
adapter/preview/ @arkuistatemgmt

View File

@ -18,6 +18,7 @@ import("//foundation/arkui/ace_engine/ace_config.gni")
group("ace_packages") {
# core library for Ability Cross-platform Environment(ACE) JS
deps = [
"$ace_root/adapter/ohos/tools:tools_target",
"$ace_root/advanced_ui_component:advanced_ui_component",
"$ace_root/build:libace",
"$ace_root/build:libace_compatible",

View File

@ -0,0 +1,24 @@
# Copyright (c) 2024 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.
import("//build/ohos.gni")
import("//foundation/arkui/ace_engine/ace_config.gni")
group("tools_target") {
if (build_variant == "root") {
# only compiling for eng version, and don`t compile for previewer and arkui-x
if (is_ohos_standard_system && !use_mingw_win && !use_mac && !use_linux) {
deps = [ "raw_input_injector:rawinput" ]
}
}
}

View File

@ -0,0 +1,55 @@
# Copyright (c) 2024 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.
import("//build/ohos.gni")
import("//foundation/arkui/ace_engine/ace_config.gni")
ohos_source_set("rawinput-injector") {
sources = [
"injecting_executor.cpp",
"injector_utils.cpp",
"raw_input_command.cpp",
"raw_input_injector.cpp",
]
branch_protector_ret = "pac_ret"
sanitize = {
cfi = true
cfi_cross_dso = true
debug = false
}
external_deps = [
"c_utils:utils",
"input:libmmi-client",
]
part_name = ace_engine_part
subsystem_name = ace_engine_subsystem
}
ohos_executable("rawinput") {
sources = [ "main.cpp" ]
configs = [ "$ace_root:ace_coverage_config" ]
branch_protector_ret = "pac_ret"
sanitize = {
cfi = true
cfi_cross_dso = true
debug = false
}
deps = [ ":rawinput-injector" ]
part_name = ace_engine_part
subsystem_name = ace_engine_subsystem
}

View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 2024 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 "injecting_executor.h"
#include <chrono>
#include <iostream>
#include <thread>
#include "input_manager.h"
#include "pointer_event.h"
namespace OHOS {
namespace Ace {
int32_t InjectingExecutor::GetPointerActionFromCommandType(CommandType type)
{
switch (type) {
case CommandType::TOUCH_DOWN:
return MMI::PointerEvent::POINTER_ACTION_DOWN;
case CommandType::TOUCH_MOVE:
return MMI::PointerEvent::POINTER_ACTION_MOVE;
case CommandType::TOUCH_UP:
return MMI::PointerEvent::POINTER_ACTION_UP;
case CommandType::TOUCH_CANCEL:
return MMI::PointerEvent::POINTER_ACTION_CANCEL;
default:
return MMI::PointerEvent::POINTER_ACTION_MOVE;
}
}
CommandType InjectingExecutor::GetCommandTypeFromPointerAction(int32_t pointerActionType)
{
switch (pointerActionType) {
case MMI::PointerEvent::POINTER_ACTION_DOWN:
return CommandType::TOUCH_DOWN;
case MMI::PointerEvent::POINTER_ACTION_MOVE:
return CommandType::TOUCH_MOVE;
case MMI::PointerEvent::POINTER_ACTION_UP:
return CommandType::TOUCH_UP;
case MMI::PointerEvent::POINTER_ACTION_CANCEL:
return CommandType::TOUCH_CANCEL;
default:
return CommandType::UNKNOWN;
}
return CommandType::UNKNOWN;
}
std::string InjectingExecutor::GetPointerActionName(int32_t pointerActionType)
{
switch (pointerActionType) {
case MMI::PointerEvent::POINTER_ACTION_DOWN:
return "down";
case MMI::PointerEvent::POINTER_ACTION_MOVE:
return "move";
case MMI::PointerEvent::POINTER_ACTION_UP:
return "up";
case MMI::PointerEvent::POINTER_ACTION_CANCEL:
return "cancel";
default:
return "unkown";
}
return "unkown";
}
bool InjectingExecutor::IsEventNeedTriggerImmediatly(int32_t pointerActionType)
{
if (pointerActionType == MMI::PointerEvent::POINTER_ACTION_DOWN ||
pointerActionType == MMI::PointerEvent::POINTER_ACTION_UP ||
pointerActionType == MMI::PointerEvent::POINTER_ACTION_CANCEL) {
return true;
}
return false;
}
bool InjectingExecutor::InjectOnePonterEvent(
std::vector<InjectingInfo>& activingInjecting, std::vector<InjectingInfo>& allOtherInjectings)
{
// must have one activing action at least
if (activingInjecting.empty()) {
return false;
}
bool ret = false;
for (auto& activingPointer : activingInjecting) {
if (ret) {
// give a little break 1ms between two actions
std::cout << "give a little break between two continus injecting" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
// 1. prepare the pointer event
auto pointerEvent = MMI::PointerEvent::Create();
pointerEvent->SetSourceType(MMI::PointerEvent::SOURCE_TYPE_TOUCHSCREEN);
pointerEvent->SetPointerAction(activingPointer.actionType);
pointerEvent->SetPointerId(activingPointer.finger);
// 2. add the activing pointer self as the first item
MMI::PointerEvent::PointerItem activingItem;
activingItem.SetDisplayX(activingPointer.x);
activingItem.SetDisplayY(activingPointer.y);
activingItem.SetPointerId(activingPointer.finger);
pointerEvent->AddPointerItem(activingItem);
// 3. pack all other pointers into items
for (auto& otherPointer : allOtherInjectings) {
MMI::PointerEvent::PointerItem item;
item.SetDisplayX(otherPointer.x);
item.SetDisplayY(otherPointer.y);
item.SetPointerId(otherPointer.finger);
pointerEvent->AddPointerItem(item);
}
// 4. inject
MMI::InputManager::GetInstance()->SimulateInputEvent(pointerEvent);
ret = true;
}
return ret;
}
} // namespace Ace
} // namespace OHOS

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2024 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 ARKUI_INPUT_RAW_INPUT_INJECTOR_RAW_INPUT_INJECTING_EXECUTOR_H
#define ARKUI_INPUT_RAW_INPUT_INJECTOR_RAW_INPUT_INJECTING_EXECUTOR_H
#include <string>
#include <vector>
#include "raw_input_command.h"
namespace OHOS {
namespace Ace {
struct InjectingInfo {
int32_t actionType;
int32_t finger;
int32_t x;
int32_t y;
int64_t actionTime;
int32_t sourceType; // not used for now
};
class InjectingExecutor {
public:
static int32_t GetPointerActionFromCommandType(CommandType type);
static CommandType GetCommandTypeFromPointerAction(int32_t pointerActionType);
static std::string GetPointerActionName(int32_t pointerActionType);
static bool IsEventNeedTriggerImmediatly(int32_t pointerActionType);
// 1. the activing injecting will be used as the pointer event object;
// 2. all other injectings will be packed into the activing injecting object;
// 3. if there is no any activing injecting, the injecting will be given up, and return false as result;
// 4. if there are more than 1 activing injecting, they will be injected one by one, and all other injecting info
// will be packed into them seperatly;
static bool InjectOnePonterEvent(
std::vector<InjectingInfo>& activingInjecting, std::vector<InjectingInfo>& allOtherInjectings);
private:
InjectingExecutor() = default;
~InjectingExecutor() = default;
};
} // namespace Ace
} // namespace OHOS
#endif // ARKUI_INPUT_RAW_INPUT_INJECTOR_RAW_INPUT_INJECTING_EXECUTOR_H

View File

@ -0,0 +1,144 @@
/*
* Copyright (c) 2024 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 "injector_utils.h"
#include <cmath>
#include <ctime>
#include <iostream>
#include <map>
namespace OHOS {
namespace Ace {
namespace {
constexpr int32_t TIME_TRANSITION = 1000;
} // namespace
bool InjectorUtils::debugEnabled_ = false;
int64_t InjectorUtils::GetSysClockTime()
{
struct timespec ts = { 0, 0 };
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
return 0;
}
return (ts.tv_sec * TIME_TRANSITION * TIME_TRANSITION) + (ts.tv_nsec / TIME_TRANSITION);
}
int32_t InjectorUtils::CalculateNextPosValueWithLinear(
int32_t startPoint, int32_t targetPoint, int32_t currentIndex, int32_t totalCount)
{
if (totalCount < 1) {
std::cout << "too few total count" << std::endl;
return -1;
}
if (targetPoint == startPoint) {
// no moving
return targetPoint;
}
auto distance = targetPoint - startPoint;
auto possitive = (distance > 0) ? 1 : -1; // possitive means increasing
// distance step
float absStep = static_cast<float>(std::abs(distance)) / totalCount;
// one px at least
absStep = (absStep == 0) ? 1 : absStep;
int32_t result = startPoint + static_cast<float>((absStep * (currentIndex + 1)) * possitive);
if (possitive) {
result = (result > targetPoint) ? targetPoint : result;
} else {
result = (result < targetPoint) ? targetPoint : result;
}
return result;
}
int InjectorUtils::Combination(int n, int k)
{
double result = 1.0;
for (int i = 1; i <= k; ++i) {
result *= static_cast<double>(n - i + 1) / i;
}
return result;
}
Point InjectorUtils::BezierCurve(const std::vector<Point>& controlPoints, double t)
{
Point result = { 0.0, 0.0 };
int n = controlPoints.size() - 1;
for (int i = 0; i <= n; ++i) {
double coeff = static_cast<double>(Combination(n, i)) * pow(t, i) * pow(1 - t, n - i);
result.x += coeff * controlPoints[i].x;
result.y += coeff * controlPoints[i].y;
}
return result;
}
// cubic: x < 0.5 ? 4 * x * x * x : 1 - pow(-2 * x + 2, 3) / 2
static double EaseInOutCubic(double t)
{
const double c1 = 0.5;
const int c2 = 4;
const int c3 = -2;
const int c4 = 2;
const int c5 = 3;
const int c6 = 2;
return (t < c1) ? (c2 * t * t * t) : (1 - pow(c3 * t + c4, c5) / c6);
}
// quart: x < 0.5 ? 8 * x * x * x * x : 1 - pow(-2 * x + 2, 4) / 2
static double EaseInOutQuart(double t)
{
const double c1 = 0.5;
const int c2 = 8;
const int c3 = -2;
const int c4 = 2;
const int c5 = 4;
const int c6 = 2;
return (t < c1) ? (c2 * t * t * t * t) : (1 - pow(c3 * t + c4, c5) / c6);
}
double InjectorUtils::EaseInOut(double t, EaseAlgorithm algorithm)
{
static const std::map<EaseAlgorithm, double (*)(double)> easeAlgorithmMap = {
{ EaseAlgorithm::CUBIC, EaseInOutCubic }, { EaseAlgorithm::QUART, EaseInOutQuart }
};
return easeAlgorithmMap.at(algorithm)(t);
}
Point InjectorUtils::CalculateNextPosValueWithBezier(
std::vector<Point>& controlPoints, int32_t currentIndex, int32_t totalCount, CoordinateCurve curve)
{
Point result;
if (currentIndex < 0 || currentIndex > totalCount || totalCount < 1) {
std::cout << "wrong count given: currentIndex " << currentIndex << ", totalCount " << totalCount << std::endl;
return result;
}
if (controlPoints.empty()) {
std::cout << "start and target point need be given at least" << std::endl;
return result;
}
double t = static_cast<double>(currentIndex) / totalCount;
if (curve == CoordinateCurve::EASE_IN_OUT) {
t = EaseInOut(t, EaseAlgorithm::QUART);
}
return BezierCurve(controlPoints, t);
}
} // namespace Ace
} // namespace OHOS

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2024 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 ARKUI_INPUT_RAW_INPUT_INJECTOR_RAW_INPUT_INJECTOR_UTILS_H
#define ARKUI_INPUT_RAW_INPUT_INJECTOR_RAW_INPUT_INJECTOR_UTILS_H
#include <cstdint>
#include <vector>
namespace OHOS {
namespace Ace {
// coordinate calculation function curve, used for point calculation of touch move
// [Note]: only LINEAR is supported for now
enum class CoordinateCurve : size_t { LINEAR = 0, EASE_IN_OUT, EASE_IN, EASE_OUT };
enum class EaseAlgorithm : size_t { CUBIC = 0, QUART };
struct Point {
double x = 0; // use double for high precision
double y = 0;
};
class InjectorUtils final {
public:
static bool IsDebugOn()
{
return debugEnabled_;
}
static void SetDebugEnabled(bool debug)
{
debugEnabled_ = debug;
}
static int64_t GetSysClockTime();
// calculate one point value in linear way
static int32_t CalculateNextPosValueWithLinear(
int32_t startPoint, int32_t targetPoint, int32_t currentIndex, int32_t totalCount);
static Point CalculateNextPosValueWithBezier(
std::vector<Point>& controlPoints, int32_t currentIndex, int32_t totalCount, CoordinateCurve curve);
private:
InjectorUtils() = default;
~InjectorUtils() = default;
// bezier curve calculation
static Point BezierCurve(const std::vector<Point>& controlPoints, double t);
static int Combination(int n, int k);
static double EaseInOut(double t, EaseAlgorithm algorithm);
static bool debugEnabled_;
};
} // namespace Ace
} // namespace OHOS
#endif // ARKUI_INPUT_RAW_INPUT_INJECTOR_RAW_INPUT_INJECTOR_H

View File

@ -0,0 +1,22 @@
/*
* Copyright (c) 2024 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 "raw_input_injector.h"
int32_t main(int32_t argc, char** argv)
{
OHOS::Ace::RawInputInjector injector;
return injector.ExecuteInject(argc, argv);
}

View File

@ -0,0 +1,246 @@
/*
* Copyright (c) 2024 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 "raw_input_command.h"
#include <iostream>
#include "string_ex.h"
namespace OHOS {
namespace Ace {
namespace {
constexpr int32_t MIN_DATA_COUNT_FOR_RAW_EVENT = 2;
constexpr int32_t MAX_DATA_COUNT_FOR_RAW_EVENT = 4;
constexpr int32_t RAW_EVENT_X_INDEX = 0;
constexpr int32_t RAW_EVENT_Y_INDEX = 1;
constexpr int32_t RAW_EVENT_DURATION_INDEX = 2;
} // namespace
std::string BaseCommand::GetCommandTypeName(CommandType type)
{
switch (type) {
case CommandType::TOUCH_DOWN:
return "d";
case CommandType::TOUCH_MOVE:
return "m";
case CommandType::TOUCH_UP:
return "u";
case CommandType::TOUCH_CANCEL:
return "c";
case CommandType::COMMAND_WAIT:
return "w";
default:
return "";
}
}
std::string BaseCommand::GetReadableCommandTypeName(CommandType type)
{
switch (type) {
case CommandType::TOUCH_DOWN:
return "down";
case CommandType::TOUCH_MOVE:
return "move";
case CommandType::TOUCH_UP:
return "up";
case CommandType::TOUCH_CANCEL:
return "cancel";
case CommandType::COMMAND_WAIT:
return "wait";
default:
return "";
}
}
bool BaseCommand::Feed(const std::vector<std::string>& data)
{
if (data.empty()) {
return true;
}
for (const auto& str : data) {
int32_t duration;
if (!StrToInt(str, duration)) {
return false;
}
SetDuration(duration);
break;
}
return true;
}
// -d/m/u/c x y duration finger
bool BaseRawEventCommand::Feed(const std::vector<std::string>& data)
{
if (data.size() < MIN_DATA_COUNT_FOR_RAW_EVENT || data.size() > MAX_DATA_COUNT_FOR_RAW_EVENT) {
std::cout << "error data count for -" << GetCommandTypeName(GetCommandType()) << std::endl;
return false;
}
bool durationSet = false;
int32_t paramInd = 0;
for (const auto& str : data) {
int32_t value;
if (!StrToInt(str, value)) {
std::cout << "parse error for " << str << std::endl;
return false;
}
switch (paramInd) {
case RAW_EVENT_X_INDEX:
SetTargetDisplayX(value);
break;
case RAW_EVENT_Y_INDEX:
SetTargetDisplayY(value);
break;
case RAW_EVENT_DURATION_INDEX:
durationSet = true;
SetDuration(value);
break;
default:
break;
}
paramInd++;
}
OnFeeded(durationSet, data);
return true;
}
std::string BaseRawEventCommand::ToString() const
{
std::string typeName = GetReadableCommandTypeName(GetCommandType());
std::string result = "";
if (GetDuration() != 0) {
result = typeName + "(" + std::to_string(GetTargetDisplayX()) + ", " + std::to_string(GetTargetDisplayY()) +
")-[" + std::to_string(GetDuration()) + "ms]";
} else {
result =
typeName + "(" + std::to_string(GetTargetDisplayX()) + ", " + std::to_string(GetTargetDisplayY()) + ")";
}
return result;
}
std::string WaitCommand::ToString() const
{
return "wait-[" + std::to_string(GetDuration()) + "]ms";
}
void TouchMoveCommand::OnFeeded(bool durationSet, const std::vector<std::string>& data)
{
(void)(data); // not used for now
if (!durationSet) {
// for touch move, the default duration is 1000
SetDuration(DEFAULT_MOVE_DURATION);
}
}
void CommandList::AddCommand(std::shared_ptr<BaseCommand> command)
{
commands_.push_back(command);
}
void CommandList::Clear()
{
commands_.clear();
}
const std::vector<std::shared_ptr<BaseCommand>>& CommandList::GetCommands() const
{
return commands_;
}
std::string CommandList::ToString() const
{
std::string dumpStr = "";
for (auto& command : commands_) {
dumpStr += (" " + command->ToString());
}
return dumpStr;
}
bool BaseCommand::ConsumeOnce(int64_t currentTime, ConsumeActionInfo& actionInfo)
{
// mark the base time line first if not set before this consuming try
MarkConsumeBaseTimeLine(currentTime);
// check if already consumed out
if (IsConsumedOut()) {
return false; // running out, can not be consumed any more
}
if (currentTime >= (consumeBaseTimeLine_ + duration_)) {
// give the current command at least one chance to be executed
isConsumedOut_ = true;
}
// call the func implemented by child class
bool ret = DoConsumeOnce(currentTime, actionInfo);
// increase consumed count
MarkConsumedOnce();
return ret;
}
bool WaitCommand::DoConsumeOnce(int64_t currentTime, ConsumeActionInfo& actionInfo)
{
actionInfo.type = GetCommandType();
actionInfo.curve = GetCoordinateCurve();
actionInfo.finger = GetFingerId();
actionInfo.targetDisplayX = 0;
actionInfo.targetDisplayY = 0;
actionInfo.consumeIndex = GetConsumedCount();
actionInfo.totalCount = GetTotalCount();
return true;
}
bool BaseRawEventCommand::DoConsumeOnce(int64_t currentTime, ConsumeActionInfo& actionInfo)
{
actionInfo.type = GetCommandType();
actionInfo.curve = GetCoordinateCurve();
actionInfo.finger = GetFingerId();
actionInfo.targetDisplayX = GetTargetDisplayX();
actionInfo.targetDisplayY = GetTargetDisplayY();
actionInfo.consumeIndex = GetConsumedCount();
actionInfo.totalCount = GetTotalCount();
return true;
}
bool CommandList::IsAllConsumed() const
{
for (const auto& command : commands_) {
if (!(command->IsConsumedOut())) {
return false;
}
}
return true;
}
bool CommandList::ConsumeOnce(int64_t currentTime, ConsumeActionInfo& actionInfo)
{
if (currentConsumingIndex_ >= commands_.size()) {
return false;
}
auto& command = commands_[currentConsumingIndex_];
command->ConsumeOnce(currentTime, actionInfo);
if (command->IsConsumedOut()) {
currentConsumingIndex_++;
}
return true;
}
} // namespace Ace
} // namespace OHOS

View File

@ -0,0 +1,235 @@
/*
* Copyright (c) 2024 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 ARKUI_INPUT_RAW_INPUT_INJECTOR_RAW_INPUT_COMMAND_H
#define ARKUI_INPUT_RAW_INPUT_INJECTOR_RAW_INPUT_COMMAND_H
#include <string>
#include <vector>
#include "injector_utils.h"
namespace OHOS {
namespace Ace {
// command types
enum class CommandType : size_t { TOUCH_DOWN = 0, TOUCH_UP, TOUCH_MOVE, TOUCH_CANCEL, COMMAND_WAIT, UNKNOWN };
struct ConsumeActionInfo {
CommandType type = CommandType::UNKNOWN;
CoordinateCurve curve = CoordinateCurve::EASE_IN_OUT;
int32_t finger = 0;
int32_t targetDisplayX = 0;
int32_t targetDisplayY = 0;
int32_t consumeIndex = 0;
int32_t totalCount = 1;
};
class BaseCommand {
public:
BaseCommand() = default;
virtual ~BaseCommand() = default;
virtual bool Feed(const std::vector<std::string>& data);
virtual std::string ToString() const = 0;
bool ConsumeOnce(int64_t currentTime, ConsumeActionInfo& actionInfo);
// implemented by child for raw event injecting
virtual bool DoConsumeOnce(int64_t currentTime, ConsumeActionInfo& actionInfo) = 0;
static std::string GetCommandTypeName(CommandType type);
static std::string GetReadableCommandTypeName(CommandType type);
bool IsConsumedOut() const
{
return isConsumedOut_;
}
void SetDuration(int32_t duration)
{
duration_ = duration;
auto total = (duration / eventInjectingInterval_);
totalCount_ = (duration % eventInjectingInterval_ != 0) ? (total + 1) : total;
}
int32_t GetDuration() const
{
return duration_;
}
void SetCommandType(CommandType type)
{
commandType_ = type;
}
CommandType GetCommandType() const
{
return commandType_;
}
void SetFingerId(int32_t finger)
{
fingerId_ = finger;
}
int32_t GetFingerId() const
{
return fingerId_;
}
int32_t GetConsumedCount() const
{
return consumedCount_;
}
int32_t GetTotalCount() const
{
return totalCount_;
}
void SetCoordinateCurve(CoordinateCurve curve)
{
coordinateCurve_ = curve;
}
CoordinateCurve GetCoordinateCurve() const
{
return coordinateCurve_;
}
void MarkConsumedOnce()
{
consumedCount_++;
}
// inject event every 5ms, not use 7ms as we need consider the IPC consumed time
static const int32_t EVENT_INJECTING_INTERVAL = 5; // inject event every 5 ms
private:
void MarkConsumeBaseTimeLine(int64_t currentTime)
{
if (consumeBaseTimeLine_ < 0) {
consumeBaseTimeLine_ = currentTime;
}
}
int32_t eventInjectingInterval_ = EVENT_INJECTING_INTERVAL;
int32_t fingerId_ = 0;
int32_t duration_ = 0; // the total time for this command can be executed
int64_t consumeBaseTimeLine_ = -1; // the base time line for consume this command
bool isConsumedOut_ = false;
int32_t consumedCount_ = 0;
int32_t totalCount_ = 1;
CoordinateCurve coordinateCurve_ = CoordinateCurve::EASE_IN_OUT;
CommandType commandType_ = CommandType::UNKNOWN;
};
class WaitCommand : public BaseCommand {
public:
WaitCommand() = default;
~WaitCommand() override = default;
bool DoConsumeOnce(int64_t currentTime, ConsumeActionInfo& actionInfo) override;
std::string ToString() const override;
};
class BaseRawEventCommand : public BaseCommand {
public:
BaseRawEventCommand() = default;
~BaseRawEventCommand() override = default;
bool Feed(const std::vector<std::string>& data) override;
virtual void OnFeeded(bool durationSet, const std::vector<std::string>& data) {}
bool DoConsumeOnce(int64_t currentTime, ConsumeActionInfo& actionInfo) override;
std::string ToString() const override;
void SetTargetDisplayX(int32_t x)
{
targetDisplayX_ = x;
}
int32_t GetTargetDisplayX() const
{
return targetDisplayX_;
}
void SetTargetDisplayY(int32_t y)
{
targetDisplayY_ = y;
}
int32_t GetTargetDisplayY() const
{
return targetDisplayY_;
}
private:
int32_t targetDisplayX_ = 0;
int32_t targetDisplayY_ = 0;
};
class TouchDownCommand : public BaseRawEventCommand {
public:
TouchDownCommand() = default;
~TouchDownCommand() override = default;
};
class TouchUpCommand : public BaseRawEventCommand {
public:
TouchUpCommand() = default;
~TouchUpCommand() override = default;
};
class TouchMoveCommand : public BaseRawEventCommand {
public:
TouchMoveCommand() = default;
~TouchMoveCommand() override = default;
void OnFeeded(bool durationSet, const std::vector<std::string>& data) override;
static const int32_t DEFAULT_MOVE_DURATION = 1000;
};
class TouchCancelCommand : public BaseRawEventCommand {
public:
TouchCancelCommand() = default;
~TouchCancelCommand() override = default;
};
class CommandList final {
public:
CommandList() = default;
~CommandList() = default;
std::string ToString() const;
void AddCommand(std::shared_ptr<BaseCommand> command);
void Clear();
const std::vector<std::shared_ptr<BaseCommand>>& GetCommands() const;
bool ConsumeOnce(int64_t currentTime, ConsumeActionInfo& actionInfo);
void SetPointerID(int32_t pointerID)
{
pointerID_ = pointerID;
}
int32_t GetPointerID() const
{
return pointerID_;
}
bool IsAllConsumed() const;
private:
std::vector<std::shared_ptr<BaseCommand>> commands_;
int32_t pointerID_ = 0;
int32_t currentConsumingIndex_ = 0;
};
} // namespace Ace
} // namespace OHOS
#endif // ARKUI_INPUT_RAW_INPUT_INJECTOR_RAW_INPUT_COMMAND_H

View File

@ -0,0 +1,628 @@
/*
* Copyright (c) 2024 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 "raw_input_injector.h"
#include <chrono>
#include <getopt.h>
#include <iostream>
#include <thread>
#include "injector_utils.h"
#include "string_ex.h"
namespace OHOS {
namespace Ace {
namespace {
constexpr int32_t SLEEPTIME = 20;
constexpr int32_t OPT_CHARACTER_COUNT = 2;
} // namespace
void RawInputInjector::PrintAllCommands(int32_t argc, char* argv[])
{
if (!InjectorUtils::IsDebugOn()) {
return;
}
std::cout << "all args: " << std::endl;
for (int32_t i = 0; i < argc; i++) {
std::cout << " - args[" << i << "]: " << argv[i] << std::endl;
}
}
bool RawInputInjector::ExecuteInject(int32_t argc, char* argv[])
{
if (!ParseAndPackCommandQueue(argc, argv)) {
std::cout << "parse commands failed" << std::endl;
return false;
}
// alway return true if the parse successfully
bool ret = true;
if (!CheckCommandQueue()) {
std::cout << "the commands queue can not be handled" << std::endl;
return ret;
}
if (!ExecuteQueue()) {
std::cout << "execute commands failed" << std::endl;
}
std::this_thread::sleep_for(std::chrono::milliseconds(SLEEPTIME));
return ret;
}
int32_t RawInputInjector::GetOptFromCurrentPosAndMoveOn(int32_t argc, char* argv[])
{
int32_t opt = -1;
if (currentParsingPos_ >= argc) {
return opt;
}
if (argv[currentParsingPos_] == nullptr || strlen(argv[currentParsingPos_]) != OPT_CHARACTER_COUNT ||
argv[currentParsingPos_][0] != '-') {
return opt;
}
opt = argv[currentParsingPos_][1];
currentParsingPos_++;
return opt;
}
std::string RawInputInjector::GetParamFromCurrentPosAndMoveOn(int32_t argc, char* argv[])
{
if (currentParsingPos_ >= argc) {
return "";
}
if (argv[currentParsingPos_] == nullptr || strlen(argv[currentParsingPos_]) == 0 ||
argv[currentParsingPos_][0] == '-') {
return "";
}
std::string ret(argv[currentParsingPos_]);
currentParsingPos_++;
return ret;
}
bool RawInputInjector::ParseAndPackCommandQueue(int32_t argc, char* argv[])
{
PrintAllCommands(argc, argv);
int32_t opt = 0;
// check the first opt, it must be -R
opt = GetOptFromCurrentPosAndMoveOn(argc, argv);
if (opt != 'R') {
// quit
return false;
}
opt = GetOptFromCurrentPosAndMoveOn(argc, argv);
if (opt == 'D') {
InjectorUtils::SetDebugEnabled(true);
// move to next
opt = GetOptFromCurrentPosAndMoveOn(argc, argv);
}
switch (opt) {
case 'T':
ParseAndPackCommandForTouch(argc, argv);
break;
default:
break;
}
return true;
}
// rawinput -R -T -f 0 -w 333 -d 601 602 -w 603 -m 610 1120 1000 -w 5000 -u 610 1120 -f 1 -d 501 502 -w 503 -m 510 1520
// 5000 -w 5000 -u 510 1525
bool RawInputInjector::ParseAndPackCommandForTouch(int32_t argc, char* argv[])
{
int32_t opt = 0;
bool packRet = true;
// do not use the getopt for the next parsing as it will reorder the args, which will affect the parsing
while ((opt = GetOptFromCurrentPosAndMoveOn(argc, argv)) != -1) {
switch (opt) {
case 'f':
packRet = ParseFingerId(argc, argv);
break;
case 'd':
packRet = PackSingleCommandToQueueFromCurrentPos(CommandType::TOUCH_DOWN, argc, argv);
break;
case 'm':
packRet = PackSingleCommandToQueueFromCurrentPos(CommandType::TOUCH_MOVE, argc, argv);
break;
case 'u':
packRet = PackSingleCommandToQueueFromCurrentPos(CommandType::TOUCH_UP, argc, argv);
break;
case 'c':
packRet = PackSingleCommandToQueueFromCurrentPos(CommandType::TOUCH_CANCEL, argc, argv);
break;
case 'w':
packRet = PackSingleCommandToQueueFromCurrentPos(CommandType::COMMAND_WAIT, argc, argv);
break;
default:
std::cout << "unsupprted opt: -" << static_cast<char>(opt) << std::endl;
return false;
}
if (!packRet) {
std::cout << "pack single command failed for -" << opt << std::endl;
return false;
}
}
return true;
}
bool RawInputInjector::ParseFingerId(int32_t argc, char* argv[])
{
if (currentParsingPos_ >= argc) {
return false;
}
std::string fingerValue = GetParamFromCurrentPosAndMoveOn(argc, argv);
int32_t fingerID = 0;
if (!StrToInt(fingerValue, fingerID)) {
return false;
}
const auto& existFinger = commandMap_.find(fingerID);
if (existFinger != commandMap_.end()) {
return false;
}
CommandList commandList;
commandList.SetPointerID(fingerID);
commandMap_[fingerID] = std::move(commandList);
// mark the current handling finger
currentParsingFinger_ = fingerID;
return true;
}
bool RawInputInjector::PackSingleCommandToQueueFromCurrentPos(CommandType type, int32_t argc, char* argv[])
{
if (currentParsingPos_ >= argc) {
return false;
}
std::shared_ptr<BaseCommand> command = nullptr;
switch (type) {
case CommandType::TOUCH_DOWN:
command = std::make_shared<TouchDownCommand>();
break;
case CommandType::TOUCH_MOVE:
command = std::make_shared<TouchMoveCommand>();
break;
case CommandType::TOUCH_UP:
command = std::make_shared<TouchUpCommand>();
break;
case CommandType::TOUCH_CANCEL:
command = std::make_shared<TouchCancelCommand>();
break;
case CommandType::COMMAND_WAIT:
command = std::make_shared<WaitCommand>();
break;
default:
return false;
}
command->SetCommandType(type);
command->SetFingerId(currentParsingFinger_);
std::vector<std::string> data;
std::string parameter;
while ((parameter = GetParamFromCurrentPosAndMoveOn(argc, argv)) != "") {
data.push_back(parameter);
}
if (!command->Feed(data)) {
return false;
}
commandMap_[currentParsingFinger_].AddCommand(command);
return true;
}
bool RawInputInjector::CheckCommandQueue()
{
if (commandMap_.empty()) {
return false;
}
for (auto iter = commandMap_.begin(); iter != commandMap_.end(); ++iter) {
std::string dumpStr = "finger " + std::to_string(iter->first) + ":";
dumpStr += iter->second.ToString();
std::cout << dumpStr << std::endl;
}
return true;
}
bool RawInputInjector::ExecuteQueue()
{
// 先按照7ms步进间隔扫描整个队列生成所有的待注入的事件action信息
std::vector<std::vector<ConsumeActionInfo>> actionList;
if (!PrepareAllInjectingActions(actionList)) {
return false;
}
// dump all injecting actions
DumpAllInjectingActions(actionList);
// 遍历生成的事件序列,按照间隔依次执行注入
DoInject(actionList);
std::cout << "injecting done" << std::endl;
return true;
}
bool RawInputInjector::PrepareAllInjectingActions(std::vector<std::vector<ConsumeActionInfo>>& allActions)
{
int64_t currentTime = 0;
while (!IsAllConsumed()) {
std::vector<ConsumeActionInfo> actionList;
for (auto iter = commandMap_.begin(); iter != commandMap_.end(); ++iter) {
ConsumeActionInfo action;
if (iter->second.ConsumeOnce(currentTime, action)) {
actionList.push_back(action);
}
}
currentTime += BaseCommand::EVENT_INJECTING_INTERVAL;
allActions.push_back(std::move(actionList));
}
return true;
}
void RawInputInjector::DumpAllInjectingActions(const std::vector<std::vector<ConsumeActionInfo>>& allActions)
{
if (!InjectorUtils::IsDebugOn()) {
return;
}
if (allActions.empty()) {
return;
}
int32_t round = 0;
for (auto& actionList : allActions) {
std::string str = "round " + std::to_string(round) + ": ";
for (auto& action : actionList) {
str += ("finger " + std::to_string(action.finger) + " " +
BaseCommand::GetReadableCommandTypeName(action.type) + ", ");
}
std::cout << str << std::endl;
round++;
}
}
void RawInputInjector::DoInject(const std::vector<std::vector<ConsumeActionInfo>>& allActions)
{
if (allActions.empty()) {
return;
}
int64_t startTime = InjectorUtils::GetSysClockTime(); // todo: do we need to backforward some ms for robustness
int32_t intervalTimeMs = BaseCommand::EVENT_INJECTING_INTERVAL;
int64_t currentTime = startTime;
int32_t lastActivedFinger = 0;
int32_t round = 0;
for (auto& actionList : allActions) {
std::vector<InjectingInfo> activedInjectingInfos;
std::vector<InjectingInfo> allOtherInjectingInfos;
PackInjectActionForOneRound(
actionList, lastActivedFinger, currentTime, activedInjectingInfos, allOtherInjectingInfos);
// do the injecting
DumpInjectingInfo(round, activedInjectingInfos, allOtherInjectingInfos);
// update last activing finger for next round suggesting
if (!activedInjectingInfos.empty()) {
lastActivedFinger = activedInjectingInfos[0].finger;
}
InjectingExecutor::InjectOnePonterEvent(activedInjectingInfos, allOtherInjectingInfos);
// sleep 7ms
std::this_thread::sleep_for(std::chrono::milliseconds(intervalTimeMs));
// update current global status
UpdateGlobalStatus(actionList, activedInjectingInfos);
currentTime += intervalTimeMs;
round++;
}
}
void RawInputInjector::UpdateGlobalStatus(
const std::vector<ConsumeActionInfo>& actionList, const std::vector<InjectingInfo>& activedInjectingInfos)
{
if (activedInjectingInfos.empty()) {
return;
}
for (auto& info : activedInjectingInfos) {
bool isStartUpdateNeeded = false;
for (auto& action : actionList) {
if (action.finger == info.finger) {
isStartUpdateNeeded = (action.consumeIndex == action.totalCount);
break;
}
}
globalPointerStatus_.UpdatePointerStatusByPointerAction(
info.actionType, info.finger, info.x, info.y, isStartUpdateNeeded);
}
}
void RawInputInjector::DumpInjectingInfo(int32_t round, std::vector<InjectingInfo>& activedInjectingInfos,
std::vector<InjectingInfo>& otherInjectingInfos) const
{
if (!InjectorUtils::IsDebugOn()) {
return;
}
auto dumpInfoToString = [](const InjectingInfo& info, std::string& targetStr) {
targetStr += "[";
targetStr += "finger " + std::to_string(info.finger) + " ";
targetStr += InjectingExecutor::GetPointerActionName(info.actionType) + " ";
targetStr += "(x: " + std::to_string(info.x) + ", y: " + std::to_string(info.y) + ")";
targetStr += "] ";
};
std::string str = "round " + std::to_string(round) + ": ";
if (!activedInjectingInfos.empty()) {
str += "|-ACTIVE(" + std::to_string(activedInjectingInfos.size()) + "): ";
for (auto& info : activedInjectingInfos) {
dumpInfoToString(info, str);
}
}
if (!otherInjectingInfos.empty()) {
str += "|-OTHER(" + std::to_string(otherInjectingInfos.size()) + "): ";
for (auto& info : otherInjectingInfos) {
dumpInfoToString(info, str);
}
}
std::cout << str << std::endl;
}
void RawInputInjector::UpdateInjectInfoForTouchEvent(const ConsumeActionInfo& action, InjectingInfo& info) const
{
info.actionType = InjectingExecutor::GetPointerActionFromCommandType(action.type);
// for the immediate event, us target x/y directly
if (InjectingExecutor::IsEventNeedTriggerImmediatly(info.actionType)) {
info.x = action.targetDisplayX;
info.y = action.targetDisplayY;
return;
}
// for touch move event, calculate the next pos
if (action.type == CommandType::TOUCH_MOVE) {
UpdateInjectInfoForTouchMove(action, info);
return;
}
// error
std::cout << "fatal error, no handling" << std::endl;
}
void RawInputInjector::UpdateInjectInfoForTouchMove(const ConsumeActionInfo& action, InjectingInfo& info) const
{
if (action.type != CommandType::TOUCH_MOVE) {
std::cout << "fatal error, not touch move" << std::endl;
return;
}
// step 1: try to get the last point info which is already by simulated into system,
// if not exsit, use the target position directly
if (!globalPointerStatus_.IsPointerExist(action.finger)) {
info.x = action.targetDisplayX;
info.y = action.targetDisplayY;
return;
}
// step 2: get last point from globalPointerStatus_
PointerInfo lastPointerInfo = globalPointerStatus_.GetLastPointerInfo(action.finger);
// step 3: caluculate next point base on the last point
CalculatePosValueBaseOnLastPoint(lastPointerInfo, action, info);
}
void RawInputInjector::CalculatePosValueBaseOnLastPoint(
const PointerInfo& lastPoint, const ConsumeActionInfo& action, InjectingInfo& info) const
{
Point startPoint = { lastPoint.startDisplayX, lastPoint.startDisplayY };
Point targetPoint = { action.targetDisplayX, action.targetDisplayY };
std::vector<Point> controlPoints; // will support control points in the future
// prepare control points
controlPoints.push_back(startPoint);
// will support extra middle point in the future
controlPoints.push_back(targetPoint);
Point nextPoint = InjectorUtils::CalculateNextPosValueWithBezier(
controlPoints, action.consumeIndex, action.totalCount, action.curve);
info.x = static_cast<int32_t>(nextPoint.x);
info.y = static_cast<int32_t>(nextPoint.y);
}
void RawInputInjector::UpdateInjectInfoForWaitAction(const ConsumeActionInfo& action, InjectingInfo& info) const
{
// for wait action, always use the move action
info.actionType = InjectingExecutor::GetPointerActionFromCommandType(CommandType::TOUCH_MOVE);
if (!globalPointerStatus_.IsPointerExist(action.finger)) {
info.x = action.targetDisplayX;
info.y = action.targetDisplayY;
return;
}
PointerInfo lastPointerInfo = globalPointerStatus_.GetLastPointerInfo(action.finger);
info.x = lastPointerInfo.lastDisplayX;
info.y = lastPointerInfo.lastDisplayY;
return;
}
InjectingInfo RawInputInjector::GetInjectInfoFrom(const ConsumeActionInfo& action, int64_t currentTime) const
{
InjectingInfo info;
info.finger = action.finger;
info.actionTime = currentTime;
if (action.type == CommandType::COMMAND_WAIT) {
UpdateInjectInfoForWaitAction(action, info);
return info;
}
UpdateInjectInfoForTouchEvent(action, info);
return info;
}
void RawInputInjector::PackInjectActionForOneRound(const std::vector<ConsumeActionInfo>& actionList,
int32_t lastActivedFinger, int64_t currentTime, std::vector<InjectingInfo>& activedInjectingInfos,
std::vector<InjectingInfo>& otherInjectingInfos)
{
if (actionList.empty()) {
return;
}
int32_t estimatedFinger = EstimateActiveFinger(actionList, lastActivedFinger);
if (estimatedFinger < 0) {
return;
}
bool immediateEventExist = false;
for (auto& action : actionList) {
InjectingInfo info = GetInjectInfoFrom(action, currentTime);
if (InjectingExecutor::IsEventNeedTriggerImmediatly(info.actionType)) {
immediateEventExist = true;
activedInjectingInfos.push_back(info);
continue; // next
}
// if there is no any event such as down/up/cancel exist, let move as activing event
if (info.finger == estimatedFinger && !immediateEventExist) {
activedInjectingInfos.push_back(info);
} else {
otherInjectingInfos.push_back(info);
}
}
}
int32_t RawInputInjector::EstimateActiveFinger(
const std::vector<ConsumeActionInfo>& actionList, int32_t lastActivedFinger) const
{
if (actionList.empty()) {
return -1;
}
int32_t estimatedFinger = -1;
for (auto& action : actionList) {
// give other finger chance
if (action.finger != lastActivedFinger) {
estimatedFinger = action.finger;
break;
}
}
// if no last actived finger found, use the first directly
if (estimatedFinger == -1) {
estimatedFinger = actionList[0].finger;
}
return estimatedFinger;
}
bool RawInputInjector::IsAllConsumed() const
{
if (commandMap_.empty()) {
return true;
}
for (auto iter = commandMap_.begin(); iter != commandMap_.end(); ++iter) {
if (!(iter->second.IsAllConsumed())) {
return false;
}
}
return true;
}
void GlobalPointerStatus::UpdatePointerStatusByPointerAction(
int32_t pointerAction, int32_t fingerId, int32_t displayX, int32_t displayY, bool isStartUpdateNeeded)
{
CommandType commandType = InjectingExecutor::GetCommandTypeFromPointerAction(pointerAction);
switch (commandType) {
case CommandType::TOUCH_DOWN:
AddPointerInfo(fingerId, displayX, displayY);
return;
case CommandType::TOUCH_MOVE:
UpdatePointerInfo(fingerId, displayX, displayY, isStartUpdateNeeded);
return;
case CommandType::TOUCH_UP:
case CommandType::TOUCH_CANCEL:
RemovePointerInfo(fingerId);
return;
default:
return;
}
}
void GlobalPointerStatus::AddPointerInfo(int32_t id, int32_t x, int32_t y)
{
PointerInfo pointerStatus;
pointerStatus.fingerId = id;
pointerStatus.startDisplayX = x;
pointerStatus.startDisplayY = y;
pointerStatus.lastDisplayX = x;
pointerStatus.lastDisplayY = y;
pointerStatusList_.push_back(pointerStatus);
}
void GlobalPointerStatus::UpdatePointerInfo(int32_t id, int32_t x, int32_t y, bool isStartUpdateNeeded)
{
for (auto& pointerStatus : pointerStatusList_) {
if (pointerStatus.fingerId == id) {
pointerStatus.lastDisplayX = x;
pointerStatus.lastDisplayY = y;
if (isStartUpdateNeeded) {
pointerStatus.startDisplayX = x;
pointerStatus.startDisplayY = y;
}
return;
}
}
}
void GlobalPointerStatus::RemovePointerInfo(int32_t id)
{
auto iter = pointerStatusList_.begin();
while (iter != pointerStatusList_.end()) {
auto pointerStatus = *iter;
if (pointerStatus.fingerId == id) {
pointerStatusList_.erase(iter);
break;
}
++iter;
}
}
bool GlobalPointerStatus::IsPointerExist(int32_t fingerId) const
{
for (auto& pointerStatus : pointerStatusList_) {
if (pointerStatus.fingerId == fingerId) {
return true;
}
}
return false;
}
PointerInfo GlobalPointerStatus::GetLastPointerInfo(int32_t fingerId) const
{
for (auto& pointerStatus : pointerStatusList_) {
if (pointerStatus.fingerId == fingerId) {
return pointerStatus;
}
}
return PointerInfo();
}
} // namespace Ace
} // namespace OHOS

View File

@ -0,0 +1,108 @@
/*
* Copyright (c) 2024 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 ARKUI_INPUT_RAW_INPUT_INJECTOR_RAW_INPUT_INJECTOR_H
#define ARKUI_INPUT_RAW_INPUT_INJECTOR_RAW_INPUT_INJECTOR_H
#include <map>
#include <string>
#include <vector>
#include "injecting_executor.h"
#include "nocopyable.h"
#include "raw_input_command.h"
namespace OHOS {
namespace Ace {
struct PointerInfo {
int32_t startDisplayX = 0;
int32_t startDisplayY = 0;
int32_t lastDisplayX = 0;
int32_t lastDisplayY = 0;
int32_t fingerId = 0;
};
class GlobalPointerStatus {
public:
GlobalPointerStatus() = default;
~GlobalPointerStatus() = default;
void UpdatePointerStatusByPointerAction(
int32_t pointerAction, int32_t fingerId, int32_t displayX, int32_t displayY, bool isStartUpdateNeeded = false);
bool IsAnyPointerExistOnScreen() const
{
return pointerStatusList_.size() > 0;
}
const std::vector<PointerInfo>& GetPointerStatusList() const
{
return pointerStatusList_;
}
bool IsPointerExist(int32_t fingerId) const;
PointerInfo GetLastPointerInfo(int32_t fingerId) const;
private:
void AddPointerInfo(int32_t id, int32_t x, int32_t y);
void UpdatePointerInfo(int32_t id, int32_t x, int32_t y, bool isStartUpdateNeeded = false);
void RemovePointerInfo(int32_t id);
std::vector<PointerInfo> pointerStatusList_;
};
class RawInputInjector {
public:
RawInputInjector() = default;
DISALLOW_COPY_AND_MOVE(RawInputInjector);
bool ExecuteInject(int32_t argc, char* argv[]);
private:
void PrintAllCommands(int32_t argc, char* argv[]);
bool ParseAndPackCommandQueue(int32_t argc, char* argv[]);
bool ParseAndPackCommandForTouch(int32_t argc, char* argv[]);
bool ParseFingerId(int32_t argc, char* argv[]);
bool PackSingleCommandToQueueFromCurrentPos(CommandType type, int32_t argc, char* argv[]);
bool CheckCommandQueue();
bool ExecuteQueue();
bool PrepareAllInjectingActions(std::vector<std::vector<ConsumeActionInfo>>& allActions);
void DumpAllInjectingActions(const std::vector<std::vector<ConsumeActionInfo>>& allActions);
void DoInject(const std::vector<std::vector<ConsumeActionInfo>>& allActions);
void PackInjectActionForOneRound(const std::vector<ConsumeActionInfo>& actionList, int32_t lastActivedFinger,
int64_t currentTime, std::vector<InjectingInfo>& activedInjectingInfos,
std::vector<InjectingInfo>& otherInjectingInfos);
InjectingInfo GetInjectInfoFrom(const ConsumeActionInfo& action, int64_t currentTime) const;
void UpdateInjectInfoForTouchEvent(const ConsumeActionInfo& action, InjectingInfo& info) const;
void UpdateInjectInfoForTouchMove(const ConsumeActionInfo& action, InjectingInfo& info) const;
void UpdateInjectInfoForWaitAction(const ConsumeActionInfo& action, InjectingInfo& info) const;
void CalculatePosValueBaseOnLastPoint(
const PointerInfo& lastPoint, const ConsumeActionInfo& action, InjectingInfo& info) const;
void DumpInjectingInfo(int32_t round, std::vector<InjectingInfo>& activedInjectingInfos,
std::vector<InjectingInfo>& otherInjectingInfos) const;
int32_t EstimateActiveFinger(const std::vector<ConsumeActionInfo>& actionList, int32_t lastActivedFinger) const;
void UpdateGlobalStatus(
const std::vector<ConsumeActionInfo>& actionList, const std::vector<InjectingInfo>& activedInjectingInfos);
bool IsAllConsumed() const;
int32_t GetOptFromCurrentPosAndMoveOn(int32_t argc, char* argv[]);
std::string GetParamFromCurrentPosAndMoveOn(int32_t argc, char* argv[]);
GlobalPointerStatus globalPointerStatus_;
std::map<int32_t, CommandList> commandMap_;
int32_t currentParsingFinger_ = 0;
int32_t currentParsingPos_ = 1;
};
} // namespace Ace
} // namespace OHOS
#endif // ARKUI_INPUT_RAW_INPUT_INJECTOR_RAW_INPUT_INJECTOR_H