lighthouse-protocol 6.2.1

Protocol types for Project Lighthouse
Documentation
use serde::{Deserialize, Serialize};

use crate::Direction;

use super::{EventSource, GamepadEvent, KeyEvent, MidiEvent, MotionEvent, MouseEvent, OrientationEvent, UnknownEvent};

/// A user input event, as generated by the new frontend (LUNA).
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum InputEvent {
    Key(KeyEvent),
    Mouse(MouseEvent),
    Gamepad(GamepadEvent),
    Midi(MidiEvent),
    Orientation(OrientationEvent),
    Motion(MotionEvent),
    #[serde(untagged)]
    Unknown(UnknownEvent),
}

impl InputEvent {
    /// The event's source.
    pub fn source(&self) -> &EventSource {
        match self {
            InputEvent::Key(KeyEvent { source, .. }) => source,
            InputEvent::Mouse(MouseEvent { source, .. }) => source,
            InputEvent::Gamepad(GamepadEvent { source, .. }) => source,
            InputEvent::Orientation(OrientationEvent { source, .. }) => source,
            InputEvent::Motion(MotionEvent { source, .. }) => source,
            InputEvent::Midi(MidiEvent { source, .. }) => source,
            InputEvent::Unknown(UnknownEvent { source, .. }) => source,
        }
    }

    /// Parses the input event as an arbitrary direction.
    pub fn direction(&self) -> Option<Direction> {
        match self {
            InputEvent::Orientation(orientation) => orientation.direction(),
            _ => self.left_direction().or_else(|| self.right_direction()),
        }
    }

    /// The direction if the input event represents a WASD key, D-pad or left stick.
    /// Commonly used e.g. for movement in games.
    pub fn left_direction(&self) -> Option<Direction> {
        match self {
            InputEvent::Key(key) => key.wasd_direction(),
            InputEvent::Gamepad(gamepad) => gamepad.left_direction(),
            _ => None,
        }
    }

    /// The direction if the input event represents an arrow key or right stick.
    /// Commonly used e.g. for camera control in games.
    pub fn right_direction(&self) -> Option<Direction> {
        match self {
            InputEvent::Key(key) => key.arrow_direction(),
            InputEvent::Gamepad(gamepad) => gamepad.right_direction(),
            _ => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use serde_json::json;

    use crate::{Delta, EventSource, GamepadAxis2DEvent, GamepadAxisEvent, GamepadButtonEvent, GamepadControlEvent, GamepadEvent, InputEvent, KeyEvent, KeyModifiers, MouseButton, MouseEvent, OrientationEvent, Pos, UnknownEvent, Vec2};

    #[test]
    fn key_event() {
        assert_eq!(
            serde_json::from_value::<InputEvent>(json!({
                "type": "key",
                "source": 0,
                "down": true,
                "repeat": false,
                "code": "ArrowUp",
                "modifiers": {
                    "alt": false,
                    "ctrl": false,
                    "meta": false,
                    "shift": false,
                },
            })).unwrap(),
            InputEvent::Key(KeyEvent {
                source: EventSource::Int(0),
                down: true,
                repeat: false,
                code: "ArrowUp".into(),
                modifiers: KeyModifiers::default(),
            })
        );
    }

    #[test]
    fn mouse_event() {
        assert_eq!(
            serde_json::from_value::<InputEvent>(json!({
                "type": "mouse",
                "source": 1,
                "button": "left",
                "down": true,
                "pointerLocked": false,
                "pos": {
                    "x": 2,
                    "y": 4,
                },
                "movement": {
                    "x": 6,
                    "y": -3,
                },
            })).unwrap(),
            InputEvent::Mouse(MouseEvent {
                source: EventSource::Int(1),
                button: MouseButton::Left,
                down: true,
                pointer_locked: false,
                pos: Pos::new(2.0, 4.0),
                movement: Delta::new(6.0, -3.0),
            })
        );
    }

    #[test]
    fn gamepad_button_event() {
        assert_eq!(
            serde_json::from_value::<InputEvent>(json!({
                "type": "gamepad",
                "source": 1,
                "control": "button",
                "index": 42,
                "down": true,
                "value": 0.25,
            })).unwrap(),
            InputEvent::Gamepad(GamepadEvent {
                source: EventSource::Int(1),
                control: GamepadControlEvent::Button(GamepadButtonEvent {
                    index: 42,
                    down: true,
                    value: 0.25,
                }),
            })
        );
    }

    #[test]
    fn gamepad_axis_event() {
        assert_eq!(
            serde_json::from_value::<InputEvent>(json!({
                "type": "gamepad",
                "source": 1,
                "control": "axis",
                "index": 42,
                "value": 0.25,
            })).unwrap(),
            InputEvent::Gamepad(GamepadEvent {
                source: EventSource::Int(1),
                control: GamepadControlEvent::Axis(GamepadAxisEvent {
                    index: 42,
                    value: 0.25,
                }),
            })
        );
    }

    #[test]
    fn gamepad_axis_2d_event() {
        assert_eq!(
            serde_json::from_value::<InputEvent>(json!({
                "type": "gamepad",
                "source": 1,
                "control": "axis2d",
                "index": 42,
                "value": {
                    "x": 0.2,
                    "y": -0.2,
                },
            })).unwrap(),
            InputEvent::Gamepad(GamepadEvent {
                source: EventSource::Int(1),
                control: GamepadControlEvent::Axis2D(GamepadAxis2DEvent {
                    index: 42,
                    value: Vec2::new(0.2, -0.2),
                }),
            })
        );
    }

    #[test]
    fn orientation_event() {
        assert_eq!(
            serde_json::from_value::<InputEvent>(json!({
                "type": "orientation",
                "source": 1,
                "absolute": false,
                "alpha": null,
                "beta": 3.0,
                "gamma": -10.0,
            })).unwrap(),
            InputEvent::Orientation(OrientationEvent {
                source: EventSource::Int(1),
                absolute: Some(false),
                alpha: None,
                beta: Some(3.0),
                gamma: Some(-10.0),
            })
        )
    }

    #[test]
    fn unknown_event() {
        assert_eq!(
            serde_json::from_value::<InputEvent>(json!({
                "type": "someEventWeDoNotKnowAbout",
                "source": 1,
                "possibly": "abc",
                "more": "def",
                "fields": "ghi"
            })).unwrap(),
            InputEvent::Unknown(UnknownEvent {
                source: EventSource::Int(1),
                event_type: "someEventWeDoNotKnowAbout".into(),
            })
        )
    }
}