in streaming/screen-sharing-agent/app/src/main/cpp/controller.cc [371:557]
void Controller::ProcessMotionEvent(const MotionEventMessage& message) {
nanoseconds event_time = UptimeNanos();
int32_t action = message.action();
Log::V("Controller::ProcessMotionEvent action:%d", action);
int32_t display_id = message.display_id();
DisplayInfo display_info = Agent::GetDisplayInfo(display_id);
if (!display_info.IsValid()) {
return;
}
// Wake up the device if the display was turned off.
if (action == AMOTION_EVENT_ACTION_DOWN) {
WakeUpDevice();
}
int32_t tool = message.is_mouse() ? AMOTION_EVENT_TOOL_TYPE_STYLUS : AMOTION_EVENT_TOOL_TYPE_FINGER;
if ((Agent::flags() & USE_UINPUT || input_event_injection_disabled_) && Agent::feature_level() > 36) {
// Inject event using a virtual drawing tablet.
auto& tablet = GetVirtualTablet(display_id, display_info.logical_size.width, display_info.logical_size.height);
switch (action) {
case AMOTION_EVENT_ACTION_HOVER_MOVE:
for (auto& pointer : message.pointers()) {
bool success = tablet.WriteMotionEvent(
pointer.pointer_id, AMOTION_EVENT_TOOL_TYPE_STYLUS, AMOTION_EVENT_ACTION_MOVE, pointer.x, pointer.y, event_time);
if (!success) {
Log::E("Error writing hover move event");
}
}
break;
case AMOTION_EVENT_ACTION_HOVER_ENTER:
tablet.StartHovering(event_time);
break;
case AMOTION_EVENT_ACTION_HOVER_EXIT:
tablet.StopHovering(event_time);
break;
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_MOVE:
{
int32_t pressure = action == AMOTION_EVENT_ACTION_UP ? 0 : VirtualInputDevice::MAX_PRESSURE;
int32_t major_axis_size = pressure == 0 ? 0 : FINGER_TOUCH_SIZE;
for (auto& pointer: message.pointers()) {
bool success = tablet.WriteTouchEvent(pointer.pointer_id, AMOTION_EVENT_TOOL_TYPE_STYLUS, action, pointer.x, pointer.y,
pressure, major_axis_size, event_time);
if (!success) {
Log::E("Error writing touch event");
}
}
}
break;
case AMOTION_EVENT_ACTION_SCROLL:
if (!message.pointers().empty()) {
auto& pointer = message.pointers()[0];
for (const auto& entry: pointer.axis_values) {
if (entry.first == AMOTION_EVENT_AXIS_VSCROLL) {
float amount = entry.second;
if (amount != 0) {
bool success = tablet.WriteVerticalScrollEvent(amount, event_time);
if (!success) {
Log::E("Error writing tablet vertical scroll event");
}
}
} else if (entry.first == AMOTION_EVENT_AXIS_HSCROLL) {
float amount = entry.second;
if (amount != 0) {
bool success = tablet.WriteHorizontalScrollEvent(amount, event_time);
if (!success) {
Log::E("Error writing tablet horizontal scroll event");
}
}
}
}
}
break;
default:
{
auto action_code = action & AMOTION_EVENT_ACTION_MASK;
if (action_code == AMOTION_EVENT_ACTION_POINTER_DOWN || action_code == AMOTION_EVENT_ACTION_POINTER_UP) {
auto pointer_id = action >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
action = action_code == AMOTION_EVENT_ACTION_POINTER_DOWN ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
int32_t pressure = action == AMOTION_EVENT_ACTION_UP ? 0 : VirtualInputDevice::MAX_PRESSURE;
int32_t major_axis_size = pressure == 0 ? 0 : FINGER_TOUCH_SIZE;
for (auto& pointer : message.pointers()) {
if (pointer.pointer_id == pointer_id) {
bool success = tablet.WriteTouchEvent(pointer_id, AMOTION_EVENT_TOOL_TYPE_STYLUS, action, pointer.x, pointer.y,
pressure, major_axis_size, event_time);
if (!success) {
Log::E("Error writing touch event");
}
break;
}
}
}
}
break;
}
} else {
// Inject event using InputManager.
MotionEvent event(jni_);
event.display_id = display_id;
event.action = action;
event.button_state = message.button_state();
event.event_time_millis = duration_cast<milliseconds>(event_time).count();;
if (action != AMOTION_EVENT_ACTION_HOVER_MOVE && action != AMOTION_EVENT_ACTION_HOVER_ENTER &&
action != AMOTION_EVENT_ACTION_HOVER_EXIT && action != AMOTION_EVENT_ACTION_SCROLL) {
if (action == AMOTION_EVENT_ACTION_DOWN) {
motion_event_start_time_ = event.event_time_millis;
}
if (motion_event_start_time_ == 0) {
Log::E("Motion event started with action %d instead of expected %d", action, AMOTION_EVENT_ACTION_DOWN);
motion_event_start_time_ = event.event_time_millis;
}
event.down_time_millis = motion_event_start_time_;
if (action == AMOTION_EVENT_ACTION_UP) {
motion_event_start_time_ = 0;
}
}
if (message.is_mouse() || action == AMOTION_EVENT_ACTION_HOVER_MOVE || message.action_button() != 0 || message.button_state() != 0) {
// AINPUT_SOURCE_MOUSE
// - when action_button() is non-zero, as the Android framework has special handling for mouse in performButtonActionOnTouchDown(),
// which opens the context menu on right click.
// - when message.button_state() is non-zero, otherwise drag operations initiated by touch down with AINPUT_SOURCE_MOUSE will not
// receive mouse move events.
event.source = AINPUT_SOURCE_MOUSE;
} else {
event.source = AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_TOUCHSCREEN;
}
for (auto& pointer: message.pointers()) {
JObject properties = pointer_properties_.GetElement(jni_, event.pointer_count);
pointer_helper_->SetPointerId(properties, pointer.pointer_id);
pointer_helper_->SetPointerToolType(properties, tool);
JObject coordinates = pointer_coordinates_.GetElement(jni_, event.pointer_count);
// We must clear first so that axis information from previous runs is not reused.
pointer_helper_->ClearPointerCoords(coordinates);
Point point = AdjustedDisplayCoordinates(pointer.x, pointer.y, display_info);
pointer_helper_->SetPointerCoords(coordinates, point.x, point.y);
float pressure = action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_UP ||
action == AMOTION_EVENT_ACTION_BUTTON_PRESS || action == AMOTION_EVENT_ACTION_BUTTON_RELEASE ? 1 : 0;
pointer_helper_->SetPointerPressure(coordinates, pressure);
for (auto const& [axis, value]: pointer.axis_values) {
pointer_helper_->SetAxisValue(coordinates, axis, value);
}
event.pointer_count++;
}
event.pointer_properties = pointer_properties_;
event.pointer_coordinates = pointer_coordinates_;
// InputManager doesn't allow ACTION_DOWN and ACTION_UP events with multiple pointers.
// They have to be converted to a sequence of pointer-specific events.
if (action == AMOTION_EVENT_ACTION_DOWN) {
if (message.action_button()) {
InjectMotionEvent(event);
event.action = AMOTION_EVENT_ACTION_BUTTON_PRESS;
event.action_button = message.action_button();
} else {
for (int i = 1; event.pointer_count = i, i < message.pointers().size(); i++) {
InjectMotionEvent(event);
event.action = AMOTION_EVENT_ACTION_POINTER_DOWN | (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
}
}
} else if (action == AMOTION_EVENT_ACTION_UP) {
if (message.action_button()) {
event.action = AMOTION_EVENT_ACTION_BUTTON_RELEASE;
event.action_button = message.action_button();
InjectMotionEvent(event);
event.action = AMOTION_EVENT_ACTION_UP;
event.action_button = 0;
} else {
for (int i = event.pointer_count; --i > 1;) {
event.action = AMOTION_EVENT_ACTION_POINTER_UP | (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
pointer_helper_->SetPointerPressure(pointer_coordinates_.GetElement(jni_, i), 0);
InjectMotionEvent(event);
event.pointer_count = i;
}
event.action = AMOTION_EVENT_ACTION_UP;
}
}
InjectMotionEvent(event);
}
if (action == AMOTION_EVENT_ACTION_UP) {
// This event may have started an app. Update the app-level display orientation.
Agent::SetVideoOrientation(display_id, DisplayStreamer::CURRENT_VIDEO_ORIENTATION);
}
}