1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* LICENSE BEGIN
    This file is part of the SixtyFPS Project -- https://sixtyfps.io
    Copyright (c) 2020 Olivier Goffart <olivier.goffart@sixtyfps.io>
    Copyright (c) 2020 Simon Hausmann <simon.hausmann@sixtyfps.io>

    SPDX-License-Identifier: GPL-3.0-only
    This file is also available under commercial licensing terms.
    Please contact info@sixtyfps.io for more information.
LICENSE END */
//! Functions usefull for testing
#![warn(missing_docs)]

use crate::input::{MouseEvent, MouseEventType};

/// SixtyFPS animations do not use real time, but use a mocked time.
/// Normally, the event loop update the time of the animation using
/// real time, but in tests, it is more convinient to use the fake time.
/// This function will add some milliseconds to the fake time
#[no_mangle]
pub extern "C" fn sixtyfps_mock_elapsed_time(time_in_ms: u64) {
    crate::animations::CURRENT_ANIMATION_DRIVER.with(|driver| {
        let mut tick = driver.current_tick();
        tick += instant::Duration::from_millis(time_in_ms);
        driver.update_animations(tick)
    })
}

/// Simulate a click on a position within the component.
#[no_mangle]
pub extern "C" fn sixtyfps_send_mouse_click(
    component: &crate::component::ComponentRc,
    x: f32,
    y: f32,
    window: &crate::eventloop::ComponentWindow,
) {
    let mut state = crate::input::MouseInputState::default();
    vtable::VRc::borrow_pin(component).as_ref().apply_layout(window.0.get_geometry());

    let pos = euclid::point2(x, y);

    state = crate::input::process_mouse_input(
        component.clone(),
        MouseEvent { pos, what: MouseEventType::MouseMoved },
        window,
        state,
    );
    state = crate::input::process_mouse_input(
        component.clone(),
        MouseEvent { pos, what: MouseEventType::MousePressed },
        window,
        state,
    );
    sixtyfps_mock_elapsed_time(50);
    crate::input::process_mouse_input(
        component.clone(),
        MouseEvent { pos, what: MouseEventType::MouseReleased },
        window,
        state,
    );
}

/// Simulate a change in keyboard modifiers pressed.
#[no_mangle]
pub extern "C" fn sixtyfps_set_keyboard_modifiers(
    window: &crate::eventloop::ComponentWindow,
    modifiers: crate::input::KeyboardModifiers,
) {
    window.set_current_keyboard_modifiers(modifiers)
}

/// Simulate a key down event.
#[no_mangle]
pub extern "C" fn sixtyfps_send_key_clicks(
    key_codes: &crate::slice::Slice<crate::input::KeyCode>,
    window: &crate::eventloop::ComponentWindow,
) {
    for key_code in key_codes.iter() {
        window.process_key_input(&crate::input::KeyEvent::KeyPressed {
            code: *key_code,
            modifiers: window.current_keyboard_modifiers(),
        });
        window.process_key_input(&crate::input::KeyEvent::KeyReleased {
            code: *key_code,
            modifiers: window.current_keyboard_modifiers(),
        });
    }
}

/// Simulate a character input event.
#[no_mangle]
pub extern "C" fn send_keyboard_string_sequence(
    sequence: &crate::SharedString,
    window: &crate::eventloop::ComponentWindow,
) {
    use std::convert::TryInto;

    let key_down = |maybe_code: &Option<crate::input::KeyCode>| {
        maybe_code.clone().map(|code| {
            window.process_key_input(&crate::input::KeyEvent::KeyPressed {
                code: code,
                modifiers: window.current_keyboard_modifiers(),
            });
        });
    };

    let key_up = |maybe_code: &Option<crate::input::KeyCode>| {
        maybe_code.clone().map(|code| {
            window.process_key_input(&crate::input::KeyEvent::KeyReleased {
                code: code,
                modifiers: window.current_keyboard_modifiers(),
            });
        });
    };

    for ch in sequence.chars() {
        let maybe_key_code = if ch.is_ascii_uppercase() {
            window.set_current_keyboard_modifiers(crate::input::SHIFT_MODIFIER.into());
            ch.to_ascii_lowercase().try_into()
        } else {
            ch.try_into()
        }
        .ok();

        key_down(&maybe_key_code);

        window.process_key_input(&crate::input::KeyEvent::CharacterInput {
            unicode_scalar: ch.into(),
            modifiers: window.current_keyboard_modifiers(),
        });

        key_up(&maybe_key_code);

        window.set_current_keyboard_modifiers(crate::input::NO_MODIFIER.into());
    }
}