///|
/// Handle input.performActions.
fn BidiProtocol::handle_input_perform_actions(
self : BidiProtocol,
request_id : Int,
params : Json?,
) -> Bool {
let ctx_id = match self.validate_input_context(request_id, params) {
Some(id) => id
None => return false
}
let sources = match get_param_raw(params, "actions") {
Some(Array(items)) => items
_ => {
self.send_error(
request_id, "invalid argument", "actions must be an array",
)
return false
}
}
set_runtime_context(ctx_id)
set_runtime_context_frames(
ctx_id,
self.context_children.get(ctx_id).unwrap_or([]),
)
self.apply_effective_viewport_to_runtime_context(ctx_id, ctx_id)
let source_types : Array[String] = []
let source_actions_list : Array[Array[Json]] = []
let source_pointer_types : Array[String] = []
for source in sources {
let (source_type, source_actions, pointer_type) = match source {
Object(source_map) => {
let source_type = match source_map.get("type") {
Some(String(t)) =>
if t == "none" || t == "key" || t == "pointer" || t == "wheel" {
t
} else {
self.send_error(
request_id, "invalid argument", "input source type is invalid",
)
return false
}
_ => {
self.send_error(
request_id, "invalid argument", "input source type must be a string",
)
return false
}
}
match source_map.get("id") {
Some(String(_)) => ()
_ => {
self.send_error(
request_id, "invalid argument", "input source id must be a string",
)
return false
}
}
let actions = match source_map.get("actions") {
Some(Array(a)) => a
_ => {
self.send_error(
request_id, "invalid argument", "input source actions must be an array",
)
return false
}
}
let mut pointer_type = "mouse"
if source_type == "pointer" {
match source_map.get("parameters") {
Some(Object(pointer_params)) =>
match pointer_params.get("pointerType") {
Some(String(pt)) =>
if pt == "mouse" || pt == "pen" || pt == "touch" {
pointer_type = pt
} else {
self.send_error(
request_id, "invalid argument", "pointerType is invalid",
)
return false
}
Some(_) => {
self.send_error(
request_id, "invalid argument", "pointerType must be a string",
)
return false
}
None => ()
}
Some(_) => {
self.send_error(
request_id, "invalid argument", "pointer parameters must be an object",
)
return false
}
None => ()
}
self.input_pointer_type[ctx_id] = pointer_type
}
(source_type, actions, pointer_type)
}
_ => {
self.send_error(
request_id, "invalid argument", "input source must be an object",
)
return false
}
}
source_types.push(source_type)
source_actions_list.push(source_actions)
source_pointer_types.push(pointer_type)
}
let mut max_ticks = 0
for source_actions in source_actions_list {
if source_actions.length() > max_ticks {
max_ticks = source_actions.length()
}
}
for tick in 0..= source_actions.length() {
continue
}
let raw_action = source_actions[tick]
if self.manager.get_session(ctx_id) is None {
self.send_error(
request_id,
"no such frame",
"Unknown context: " + ctx_id,
)
return false
}
let action_map = match raw_action {
Object(m) => m
_ => {
self.send_error(
request_id, "invalid argument", "action entry must be an object",
)
return false
}
}
let action_type = match action_map.get("type") {
Some(String(t)) => t
_ => {
self.send_error(
request_id, "invalid argument", "action type must be a string",
)
return false
}
}
if action_type == "pause" {
let mut pause_duration_ms = 0
match action_map.get("duration") {
Some(duration) =>
match json_as_safe_int(duration, 0.0, 9007199254740991.0) {
Some(parsed) => pause_duration_ms = parsed
None => {
self.send_error(
request_id, "invalid argument", "pause duration must be a non-negative integer",
)
return false
}
}
None => ()
}
self.input_action_clock_ms[ctx_id] = self.input_action_clock_ms
.get(ctx_id)
.unwrap_or(0.0) +
pause_duration_ms.to_double()
continue
}
match source_type {
"none" => {
self.send_error(
request_id, "invalid argument", "none source supports only pause actions",
)
return false
}
"key" => {
if action_type != "keyDown" && action_type != "keyUp" {
self.send_error(
request_id, "invalid argument", "key action type is invalid",
)
return false
}
let key_value = match action_map.get("value") {
Some(String(v)) => v
_ => {
self.send_error(
request_id, "invalid argument", "key action value must be a string",
)
return false
}
}
if !input_is_single_grapheme(key_value) {
self.send_error(
request_id, "invalid argument", "key action value must be a single grapheme",
)
return false
}
let normalized_key = normalize_input_key(key_value)
if action_type == "keyUp" &&
!self.has_pressed_key(ctx_id, normalized_key) {
continue
}
let (ctrl, alt, shift, meta) = self.resolve_input_modifiers(
ctx_id,
normalized_key,
action_type == "keyDown",
)
dispatch_interaction_key_command(
bidi_key_interaction_command(action_type, normalized_key),
key_value,
ctrl,
alt,
shift,
meta,
)
if action_type == "keyDown" {
if self.handle_inline_attribute_navigation(ctx_id, "onkeydown") {
self.input_pressed_keys.remove(ctx_id)
continue
}
if self.context_has_window_close_onkeydown(ctx_id) {
if self.force_close_context_from_input(ctx_id) {
self.send_error(
request_id,
"no such frame",
"Unknown context: " + ctx_id,
)
return false
}
}
self.push_pressed_key(ctx_id, normalized_key)
} else {
self.remove_pressed_key(ctx_id, normalized_key)
}
}
"pointer" => {
if !(action_type == "pointerMove" ||
action_type == "pointerDown" ||
action_type == "pointerUp") {
self.send_error(
request_id, "invalid argument", "pointer action type is invalid",
)
return false
}
if !self.validate_pointer_common_properties(request_id, action_map) {
return false
}
if action_type == "pointerMove" {
let x = match action_map.get("x") {
Some(value) =>
match
json_as_safe_number(
value, -9007199254740991.0, 9007199254740991.0,
) {
Some(parsed) => parsed
None => {
self.send_error(
request_id, "invalid argument", "pointerMove x must be a number",
)
return false
}
}
None => {
self.send_error(
request_id, "invalid argument", "pointerMove x is required",
)
return false
}
}
let y = match action_map.get("y") {
Some(value) =>
match
json_as_safe_number(
value, -9007199254740991.0, 9007199254740991.0,
) {
Some(parsed) => parsed
None => {
self.send_error(
request_id, "invalid argument", "pointerMove y must be a number",
)
return false
}
}
None => {
self.send_error(
request_id, "invalid argument", "pointerMove y is required",
)
return false
}
}
let move_duration_ms = match action_map.get("duration") {
Some(value) =>
match json_as_safe_int(value, 0.0, 9007199254740991.0) {
Some(parsed) => parsed
None => {
self.send_error(
request_id, "invalid argument", "pointerMove duration must be a non-negative integer",
)
return false
}
}
None => 0
}
self.input_action_clock_ms[ctx_id] = self.input_action_clock_ms
.get(ctx_id)
.unwrap_or(0.0) +
move_duration_ms.to_double()
let (final_x, final_y, origin_target_shared) = match
self.resolve_pointer_origin(
request_id,
ctx_id,
action_map.get("origin"),
x,
y,
true,
) {
Some(resolved) => resolved
None => return false
}
let target_shared = if origin_target_shared != "" {
origin_target_shared
} else {
get_runtime_shared_node_at_point(final_x, final_y).unwrap_or("")
}
if !self.ensure_pointer_within_viewport(
request_id, final_x, final_y,
) {
return false
}
let previous_target_shared = self.input_pointer_target_shared
.get(ctx_id)
.unwrap_or("")
self.input_pointer_x[ctx_id] = final_x
self.input_pointer_y[ctx_id] = final_y
self.input_pointer_target_shared[ctx_id] = target_shared
let buttons = self.input_pointer_buttons.get(ctx_id).unwrap_or(0)
let width = match action_map.get("width") {
Some(value) =>
json_as_safe_int(value, 0.0, 9007199254740991.0)
.unwrap_or(1)
.to_double()
None => 1.0
}
let height = match action_map.get("height") {
Some(value) =>
json_as_safe_int(value, 0.0, 9007199254740991.0)
.unwrap_or(1)
.to_double()
None => 1.0
}
let pressure = match action_map.get("pressure") {
Some(Number(n, ..)) => n
_ =>
if button_state_contains(buttons, button_to_mask(0)) {
0.5
} else {
0.0
}
}
let tangential_pressure = match
action_map.get("tangentialPressure") {
Some(Number(n, ..)) => n
_ => 0.0
}
let twist = match action_map.get("twist") {
Some(value) =>
json_as_safe_int(value, 0.0, 359.0).unwrap_or(0).to_double()
None => 0.0
}
let altitude_angle = match action_map.get("altitudeAngle") {
Some(Number(n, ..)) => n
_ => 0.0
}
let azimuth_angle = match action_map.get("azimuthAngle") {
Some(Number(n, ..)) => n
_ => 0.0
}
if button_state_contains(buttons, button_to_mask(0)) {
let down_x = self.input_pointer_down_x
.get(ctx_id)
.unwrap_or(final_x)
let down_y = self.input_pointer_down_y
.get(ctx_id)
.unwrap_or(final_y)
let down_target = self.input_pointer_down_target_shared
.get(ctx_id)
.unwrap_or(target_shared)
if abs_double(final_x - down_x) > 0.5 ||
abs_double(final_y - down_y) > 0.5 ||
down_target != target_shared {
self.input_pointer_dragged[ctx_id] = true
}
}
let (ctrl, alt, shift, meta) = self.resolve_input_modifiers(
ctx_id, "", false,
)
input_set_pointer_event_properties(
width, height, pressure, tangential_pressure, twist, altitude_angle,
azimuth_angle,
)
let should_emit_move = pointer_type == "mouse" ||
button_state_contains(buttons, button_to_mask(0))
if should_emit_move {
dispatch_interaction_hover_sequence(
@interaction.pointer_hover_event_sequence(
pointer_type,
previous_target_shared != "" &&
previous_target_shared != target_shared,
target_shared != "" && previous_target_shared != target_shared,
target_shared != "",
),
previous_target_shared,
target_shared,
final_x,
final_y,
buttons,
pointer_type,
ctrl,
alt,
shift,
meta,
)
}
if button_state_contains(buttons, button_to_mask(0)) {
let drag_origin_x = self.input_pointer_down_x
.get(ctx_id)
.unwrap_or(final_x)
let drag_origin_y = self.input_pointer_down_y
.get(ctx_id)
.unwrap_or(final_y)
let drag_source = self.input_pointer_down_target_shared
.get(ctx_id)
.unwrap_or(
self.input_html_drag_source_shared.get(ctx_id).unwrap_or(""),
)
let drag_source = if drag_source != "" &&
has_runtime_shared_node(drag_source) {
drag_source
} else {
get_runtime_shared_node_at_point(drag_origin_x, drag_origin_y).unwrap_or(
drag_source,
)
}
if drag_source != "" {
self.input_html_drag_source_shared[ctx_id] = drag_source
}
if drag_source != "" {
let drag_active = self.input_html_drag_active
.get(ctx_id)
.unwrap_or(false)
let previous_drag_target = self.input_html_drag_over_shared
.get(ctx_id)
.unwrap_or("")
let move_plan = @interaction.drag_move_target_plan(
drag_source, previous_drag_target, target_shared,
)
let drag_target = move_plan.over_target
let drag_transfer_id = self.input_html_drag_transfer_id
.get(ctx_id)
.unwrap_or("")
let mut dragover_prevented = false
for
event in @interaction.drag_move_event_sequence(
emit_dragstart=!drag_active,
emit_dragleave=move_plan.emit_dragleave,
emit_dragenter=move_plan.emit_dragenter,
emit_dragover=move_plan.emit_dragover,
) {
let dispatch_target = match event.target {
@interaction.Source => drag_source
@interaction.PreviousTarget => previous_drag_target
@interaction.CurrentTarget => drag_target
}
if dispatch_target == "" {
continue
}
let related_target = match event.target {
@interaction.Source => drag_target
@interaction.PreviousTarget => drag_target
@interaction.CurrentTarget =>
if previous_drag_target != "" {
previous_drag_target
} else {
drag_source
}
}
let prevented = input_dispatch_drag_event(
dispatch_target,
event.event_type,
final_x,
final_y,
0,
buttons,
pointer_type,
ctrl,
alt,
shift,
meta,
related_target,
drag_transfer_id,
)
if event.event_type == "dragover" {
dragover_prevented = prevented
}
}
self.input_html_drag_active[ctx_id] = true
if drag_target != "" {
self.input_html_drag_over_shared[ctx_id] = drag_target
} else {
self.input_html_drag_over_shared.remove(ctx_id)
}
let accepted_target = @interaction.drag_accept_target(
drag_source, drag_target, dragover_prevented,
)
if accepted_target != "" {
self.input_html_drag_accept_shared[ctx_id] = accepted_target
} else {
self.input_html_drag_accept_shared.remove(ctx_id)
}
}
}
input_clear_pointer_event_properties()
} else {
let button = match action_map.get("button") {
Some(value) =>
match json_as_safe_int(value, 0.0, 9007199254740991.0) {
Some(parsed) => parsed
None => {
self.send_error(
request_id, "invalid argument", "pointer button must be a non-negative integer",
)
return false
}
}
None => {
self.send_error(
request_id, "invalid argument", "pointer button is required",
)
return false
}
}
let current_x = self.input_pointer_x.get(ctx_id).unwrap_or(0.0)
let current_y = self.input_pointer_y.get(ctx_id).unwrap_or(0.0)
let target_shared = self.input_pointer_target_shared
.get(ctx_id)
.unwrap_or("")
let old_buttons = self.input_pointer_buttons
.get(ctx_id)
.unwrap_or(0)
let width = match action_map.get("width") {
Some(value) =>
json_as_safe_int(value, 0.0, 9007199254740991.0)
.unwrap_or(1)
.to_double()
None => 1.0
}
let height = match action_map.get("height") {
Some(value) =>
json_as_safe_int(value, 0.0, 9007199254740991.0)
.unwrap_or(1)
.to_double()
None => 1.0
}
let tangential_pressure = match
action_map.get("tangentialPressure") {
Some(Number(n, ..)) => n
_ => 0.0
}
let twist = match action_map.get("twist") {
Some(value) =>
json_as_safe_int(value, 0.0, 359.0).unwrap_or(0).to_double()
None => 0.0
}
let altitude_angle = match action_map.get("altitudeAngle") {
Some(Number(n, ..)) => n
_ => 0.0
}
let azimuth_angle = match action_map.get("azimuthAngle") {
Some(Number(n, ..)) => n
_ => 0.0
}
if action_type == "pointerDown" {
let next_buttons = button_state_add(old_buttons, button)
self.input_pointer_buttons[ctx_id] = next_buttons
let (ctrl, alt, shift, meta) = self.resolve_input_modifiers(
ctx_id, "", false,
)
let pressure = match action_map.get("pressure") {
Some(Number(n, ..)) => n
_ => if button == 0 { 0.5 } else { 0.0 }
}
input_set_pointer_event_properties(
width, height, pressure, tangential_pressure, twist, altitude_angle,
azimuth_angle,
)
dispatch_interaction_pointer_sequence(
@interaction.pointer_press_event_sequence(pointer_type, button),
target_shared,
current_x,
current_y,
next_buttons,
pointer_type,
ctrl,
alt,
shift,
meta,
)
input_clear_pointer_event_properties()
if self.handle_inline_attribute_navigation(
ctx_id, "onpointerdown",
) {
continue
}
if self.context_has_window_close_onpointerdown(ctx_id) {
if !self.force_close_context_from_input(ctx_id) {
self.send_error(
request_id,
"no such frame",
"Unknown context: " + ctx_id,
)
return false
}
}
if self.handle_inline_attribute_navigation(ctx_id, "onmousedown") {
continue
}
if self.context_has_window_close_onmousedown(ctx_id) {
if !self.force_close_context_from_input(ctx_id) {
self.send_error(
request_id,
"no such frame",
"Unknown context: " + ctx_id,
)
return false
}
}
if button == 0 {
self.input_pointer_down_x[ctx_id] = current_x
self.input_pointer_down_y[ctx_id] = current_y
self.input_pointer_down_target_shared[ctx_id] = target_shared
self.input_pointer_dragged[ctx_id] = false
if target_shared != "" &&
runtime_shared_node_is_draggable(target_shared) {
self.input_html_drag_source_shared[ctx_id] = target_shared
self.input_html_drag_active[ctx_id] = false
self.input_html_drag_over_shared.remove(ctx_id)
self.input_html_drag_accept_shared.remove(ctx_id)
self.input_html_drag_transfer_id[ctx_id] = ctx_id
} else {
self.input_html_drag_source_shared.remove(ctx_id)
self.input_html_drag_active.remove(ctx_id)
self.input_html_drag_over_shared.remove(ctx_id)
self.input_html_drag_accept_shared.remove(ctx_id)
let drag_transfer_id = self.input_html_drag_transfer_id
.get(ctx_id)
.unwrap_or("")
if drag_transfer_id != "" {
input_clear_drag_transfer(drag_transfer_id)
}
self.input_html_drag_transfer_id.remove(ctx_id)
}
let now = self.input_action_clock_ms.get(ctx_id).unwrap_or(0.0)
let pending_double_click = match
self.input_last_click_time.get(ctx_id) {
Some(last_time) => {
let last_target = self.input_last_click_target_shared
.get(ctx_id)
.unwrap_or("")
let last_x = self.input_last_click_x
.get(ctx_id)
.unwrap_or(-999999.0)
let last_y = self.input_last_click_y
.get(ctx_id)
.unwrap_or(-999999.0)
now - last_time <= 640.0 &&
last_target == target_shared &&
abs_double(current_x - last_x) <= 4.0 &&
abs_double(current_y - last_y) <= 4.0
}
None => false
}
self.input_pending_double_click[ctx_id] = pending_double_click
} else {
self.input_pending_double_click.remove(ctx_id)
}
} else {
let next_buttons = button_state_remove(old_buttons, button)
self.input_pointer_buttons[ctx_id] = next_buttons
let (ctrl, alt, shift, meta) = self.resolve_input_modifiers(
ctx_id, "", false,
)
input_set_pointer_event_properties(
width, height, 0.0, tangential_pressure, twist, altitude_angle, azimuth_angle,
)
dispatch_interaction_pointer_sequence(
@interaction.pointer_release_event_sequence(
pointer_type, button,
),
target_shared,
current_x,
current_y,
next_buttons,
pointer_type,
ctrl,
alt,
shift,
meta,
)
input_clear_pointer_event_properties()
let is_mac_ctrl_left_click = button == 0 &&
ctrl &&
input_is_mac_platform()
if is_mac_ctrl_left_click {
dispatch_interaction_pointer_sequence(
@interaction.pointer_post_release_mouse_event_sequence(
button, true, false, false,
),
target_shared,
current_x,
current_y,
next_buttons,
pointer_type,
ctrl,
alt,
shift,
meta,
)
self.input_pending_double_click.remove(ctx_id)
if button == 0 {
self.input_pointer_down_x.remove(ctx_id)
self.input_pointer_down_y.remove(ctx_id)
self.input_pointer_down_target_shared.remove(ctx_id)
self.input_pointer_dragged.remove(ctx_id)
self.input_html_drag_source_shared.remove(ctx_id)
self.input_html_drag_active.remove(ctx_id)
self.input_html_drag_over_shared.remove(ctx_id)
self.input_html_drag_accept_shared.remove(ctx_id)
let drag_transfer_id = self.input_html_drag_transfer_id
.get(ctx_id)
.unwrap_or("")
if drag_transfer_id != "" {
input_clear_drag_transfer(drag_transfer_id)
}
self.input_html_drag_transfer_id.remove(ctx_id)
}
} else if button == 0 {
let drag_origin_x = self.input_pointer_down_x
.get(ctx_id)
.unwrap_or(current_x)
let drag_origin_y = self.input_pointer_down_y
.get(ctx_id)
.unwrap_or(current_y)
let drag_source = self.input_pointer_down_target_shared
.get(ctx_id)
.unwrap_or(
self.input_html_drag_source_shared.get(ctx_id).unwrap_or(""),
)
let drag_source = if drag_source != "" &&
has_runtime_shared_node(drag_source) {
drag_source
} else {
get_runtime_shared_node_at_point(drag_origin_x, drag_origin_y).unwrap_or(
drag_source,
)
}
if drag_source != "" {
self.input_html_drag_source_shared[ctx_id] = drag_source
}
let drag_active = self.input_html_drag_active
.get(ctx_id)
.unwrap_or(false)
let drag_over_target = self.input_html_drag_over_shared
.get(ctx_id)
.unwrap_or("")
let drag_accept_target = self.input_html_drag_accept_shared
.get(ctx_id)
.unwrap_or("")
let drag_transfer_id = self.input_html_drag_transfer_id
.get(ctx_id)
.unwrap_or("")
if drag_source != "" && drag_active {
let drop_target = @interaction.drag_drop_target(
drag_source, drag_over_target, drag_accept_target,
)
let drop_allowed = if drop_target != "" {
let state = input_drag_transfer_state(drag_transfer_id)
match state.find("/") {
Some(idx) => {
let effect_allowed = state
.unsafe_substring(start=0, end=idx)
.to_lower()
let drop_effect = state
.unsafe_substring(start=idx + 1, end=state.length())
.to_lower()
@interaction.is_drop_effect_compatible(
effect_allowed, drop_effect,
)
}
None => false
}
} else {
false
}
for
event in @interaction.drag_release_event_sequence(
emit_drop=drop_allowed,
) {
let dispatch_target = match event.target {
@interaction.Source => drag_source
@interaction.PreviousTarget => ""
@interaction.CurrentTarget => drop_target
}
if dispatch_target == "" {
continue
}
let related_target = match event.target {
@interaction.Source => drop_target
@interaction.PreviousTarget => ""
@interaction.CurrentTarget => drag_source
}
let _ = input_dispatch_drag_event(
dispatch_target,
event.event_type,
current_x,
current_y,
button,
next_buttons,
pointer_type,
ctrl,
alt,
shift,
meta,
related_target,
drag_transfer_id,
)
}
}
let was_dragged = self.input_pointer_dragged
.get(ctx_id)
.unwrap_or(false)
dispatch_interaction_pointer_sequence(
@interaction.pointer_post_release_mouse_event_sequence(
button,
false,
!was_dragged,
!was_dragged &&
self.input_pending_double_click.get(ctx_id).unwrap_or(false),
),
target_shared,
current_x,
current_y,
next_buttons,
pointer_type,
ctrl,
alt,
shift,
meta,
)
if !was_dragged {
self.input_last_click_time[ctx_id] = self.input_action_clock_ms
.get(ctx_id)
.unwrap_or(0.0)
self.input_last_click_x[ctx_id] = current_x
self.input_last_click_y[ctx_id] = current_y
self.input_last_click_target_shared[ctx_id] = target_shared
self.handle_pointer_click_navigation(
ctx_id, target_shared, current_x, current_y,
)
}
self.input_pending_double_click.remove(ctx_id)
self.input_pointer_down_x.remove(ctx_id)
self.input_pointer_down_y.remove(ctx_id)
self.input_pointer_down_target_shared.remove(ctx_id)
self.input_pointer_dragged.remove(ctx_id)
self.input_html_drag_source_shared.remove(ctx_id)
self.input_html_drag_active.remove(ctx_id)
self.input_html_drag_over_shared.remove(ctx_id)
self.input_html_drag_accept_shared.remove(ctx_id)
if drag_transfer_id != "" {
input_clear_drag_transfer(drag_transfer_id)
}
self.input_html_drag_transfer_id.remove(ctx_id)
} else if button == 2 {
dispatch_interaction_pointer_sequence(
@interaction.pointer_post_release_mouse_event_sequence(
button, true, false, false,
),
target_shared,
current_x,
current_y,
next_buttons,
pointer_type,
ctrl,
alt,
shift,
meta,
)
self.input_pending_double_click.remove(ctx_id)
} else {
dispatch_interaction_pointer_sequence(
@interaction.pointer_post_release_mouse_event_sequence(
button, false, false, false,
),
target_shared,
current_x,
current_y,
next_buttons,
pointer_type,
ctrl,
alt,
shift,
meta,
)
}
}
}
}
"wheel" => {
if action_type != "scroll" {
self.send_error(
request_id, "invalid argument", "wheel action type is invalid",
)
return false
}
let x = match action_map.get("x") {
Some(value) =>
match
json_as_safe_int(value, -9007199254740991.0, 9007199254740991.0) {
Some(parsed) => parsed
None => {
self.send_error(
request_id, "invalid argument", "wheel x must be an integer",
)
return false
}
}
None => {
self.send_error(
request_id, "invalid argument", "wheel x is required",
)
return false
}
}
let y = match action_map.get("y") {
Some(value) =>
match
json_as_safe_int(value, -9007199254740991.0, 9007199254740991.0) {
Some(parsed) => parsed
None => {
self.send_error(
request_id, "invalid argument", "wheel y must be an integer",
)
return false
}
}
None => {
self.send_error(
request_id, "invalid argument", "wheel y is required",
)
return false
}
}
let delta_x = match action_map.get("deltaX") {
Some(value) =>
match
json_as_safe_int(value, -9007199254740991.0, 9007199254740991.0) {
Some(parsed) => parsed
None => {
self.send_error(
request_id, "invalid argument", "wheel deltaX must be an integer",
)
return false
}
}
None => {
self.send_error(
request_id, "invalid argument", "wheel deltaX is required",
)
return false
}
}
let delta_y = match action_map.get("deltaY") {
Some(value) =>
match
json_as_safe_int(value, -9007199254740991.0, 9007199254740991.0) {
Some(parsed) => parsed
None => {
self.send_error(
request_id, "invalid argument", "wheel deltaY must be an integer",
)
return false
}
}
None => {
self.send_error(
request_id, "invalid argument", "wheel deltaY is required",
)
return false
}
}
let (final_x, final_y, target_shared) = match
self.resolve_pointer_origin(
request_id,
ctx_id,
action_map.get("origin"),
x.to_double(),
y.to_double(),
false,
) {
Some(resolved) => resolved
None => return false
}
if !self.ensure_pointer_within_viewport(request_id, final_x, final_y) {
return false
}
let (ctrl, alt, shift, meta) = self.resolve_input_modifiers(
ctx_id, "", false,
)
input_dispatch_wheel_event(
target_shared,
final_x,
final_y,
delta_x.to_double(),
delta_y.to_double(),
ctrl,
alt,
shift,
meta,
)
}
_ => ()
}
}
}
true
}