wayk_proto 0.1.0

WaykNow packet encoder-decoder and sequencing utilities
Documentation
use byteorder::ReadBytesExt;
use core::mem;
use num_derive::FromPrimitive;
use std::io::{Cursor, Write};
use wayk_proto::{
    container::Vec16,
    error::*,
    message::connection_sequence::InputActionCode,
    serialization::{Decode, Encode},
};

#[derive(Encode, Decode, FromPrimitive, Debug, PartialEq, Clone, Copy)]
#[repr(u8)]
pub enum InputMessageType {
    Mouse = 0x01,
    Scroll = 0x02,
    Keyboard = 0x03,
    Unicode = 0x04,
    Toggle = 0x05,
    Action = 0x06,
}

#[derive(Encode, Decode, FromPrimitive, Debug, PartialEq, Clone, Copy)]
#[repr(u8)]
pub enum EventMouseFlags {
    None = 0x0,
    ButtonLeft = 0x01,
    ButtonRight = 0x02,
    ButtonMiddle = 0x04,
    ButtonX1 = 0x10,
    ButtonX2 = 0x20,
}

#[derive(Encode, Decode, Clone, Debug)]
pub struct NowInputEventMouse {
    subtype: InputMessageType,
    pub flags: EventMouseFlags,
    pub x: i16,
    pub y: i16,
}

impl NowInputEventMouse {
    pub fn new_with_flags_and_position(flags: EventMouseFlags, x: i16, y: i16) -> Self {
        Self {
            subtype: InputMessageType::Mouse,
            flags,
            x,
            y,
        }
    }
}

#[derive(Encode, Decode, Clone, Debug)]
pub struct NowInputEventScroll {
    subtype: InputMessageType,
    flags: u8,
    pub x: i16,
    pub y: i16,
}

impl NowInputEventScroll {
    pub fn new_with_position(x: i16, y: i16) -> Self {
        Self {
            subtype: InputMessageType::Scroll,
            flags: 0x0,
            x,
            y,
        }
    }
}

#[derive(Encode, Decode, Clone, Debug)]
pub struct NowInputEventKeyboard {
    subtype: InputMessageType,
    pub flags: u8,
    pub code: u16,
}

impl NowInputEventKeyboard {
    pub fn new_with_flags_and_code(flags: u8, code: u16) -> Self {
        Self {
            subtype: InputMessageType::Keyboard,
            flags,
            code,
        }
    }
}

#[derive(Clone, Debug)]
pub struct NowInputEventUnicode {
    subtype: InputMessageType,
    pub code: Vec<u8>,
}

impl<'a> Encode for NowInputEventUnicode {
    fn encoded_len(&self) -> usize {
        mem::size_of::<u8>() + mem::size_of::<u8>() + self.code.len()
    }

    fn encode_into<W: Write>(&self, writer: &mut W) -> Result<()> {
        self.subtype.encode_into(writer)?;
        let flags = (self.code.len() as u8 - 1) << 6;
        flags.encode_into(writer)?;
        writer.write_all(&self.code)?;
        Ok(())
    }
}

impl<'dec: 'a, 'a> Decode<'dec> for NowInputEventUnicode {
    fn decode_from(cursor: &mut Cursor<&'dec [u8]>) -> Result<Self> {
        let _subtype = cursor.read_u8()?;
        let flags = cursor.read_u8()?;

        let start_inclusive = cursor.position() as usize;

        let code_size = (flags >> 6) + 1;
        let end_exclusive = start_inclusive + code_size as usize;

        const SUBTYPE_FLAGS_BYTES: usize = 2;
        let bytes_left = (cursor.get_ref().len() - start_inclusive + SUBTYPE_FLAGS_BYTES) as usize;

        let code = if bytes_left == end_exclusive {
            cursor.get_ref()[start_inclusive..end_exclusive].to_vec()
        } else {
            return ProtoError::new(ProtoErrorKind::Decoding(
                "NowInputEventUnicode: bytes_left != end_exclusive",
            ));
        };

        Ok(NowInputEventUnicode {
            subtype: InputMessageType::Unicode,
            code,
        })
    }
}

impl NowInputEventUnicode {
    pub fn new(code: Vec<u8>) -> Self {
        Self {
            subtype: InputMessageType::Unicode,
            code,
        }
    }
}

#[derive(Encode, Decode, FromPrimitive, Debug, PartialEq, Clone, Copy)]
#[repr(u16)]
pub enum ToggleEventKeys {
    ScrollLock = 0x0001,
    NumLock = 0x0002,
    CapsLock = 0x0004,
    KanaLock = 0x0008,
}

#[derive(Encode, Decode, Clone, Debug)]
pub struct NowInputEventToggle {
    subtype: InputMessageType,
    flags: u8,
    pub code: u16,
}

impl NowInputEventToggle {
    pub fn new_with_code(code: u16) -> Self {
        Self {
            subtype: InputMessageType::Toggle,
            flags: 0x0,
            code,
        }
    }
}

#[derive(Encode, Decode, Clone, Debug)]
pub struct NowInputEventAction {
    subtype: InputMessageType,
    flags: u8,
    pub code: InputActionCode,
}

impl NowInputEventAction {
    pub fn new_with_code(code: InputActionCode) -> Self {
        Self {
            subtype: InputMessageType::Action,
            flags: 0x0,
            code,
        }
    }
}

#[derive(Debug, Clone, Encode, Decode)]
#[meta_enum = "InputMessageType"]
pub enum InputEvent {
    Mouse(NowInputEventMouse),
    Scroll(NowInputEventScroll),
    Keyboard(NowInputEventKeyboard),
    Unicode(NowInputEventUnicode),
    Toggle(NowInputEventToggle),
    Action(NowInputEventAction),
}

#[derive(Encode, Decode, Clone, Debug)]
pub struct NowInputMsg {
    input_event: Vec16<InputEvent>,
}

impl NowInputMsg {
    pub fn new_with_events(input_event: Vec<InputEvent>) -> Self {
        Self {
            input_event: Vec16(input_event),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{message::VirtChannelsCtx, packet::NowPacket};

    const TOGGLE_EVENT_FULL_PACKET: [u8; 10] = [0x06, 0x00, 0x43, 0x80, 0x01, 0x00, 0x05, 0x00, 0x02, 0x00];

    const MOUSE_SCROLL_EVENT_FULL_PACKET: [u8; 12] =
        [0x08, 0x00, 0x43, 0x80, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x78, 0x00];

    const KEYBOARD_EVENT_FULL_PACKET: [u8; 10] = [0x06, 0x00, 0x43, 0x80, 0x01, 0x00, 0x03, 0x01, 0x08, 0x00];

    const MOUSE_POSITION_EVENT_FULL_PACKET: [u8; 18] = [
        0x0e, 0x00, 0x43, 0x80, 0x02, 0x00, 0x01, 0x00, 0xe4, 0x05, 0x77, 0x02, 0x01, 0x00, 0xe0, 0x05, 0x70, 0x02,
    ];

    const UNICODE_EVENT_FULL_PACKET: [u8; 12] =
        [0x08, 0x00, 0x43, 0x80, 0x01, 0x00, 0x04, 0xC0, 0xe4, 0x05, 0x77, 0x02];

    #[test]
    fn input_event_mouse_encode() {
        let mouse_events = vec![
            InputEvent::Mouse(NowInputEventMouse::new_with_flags_and_position(
                EventMouseFlags::None,
                1508,
                631,
            )),
            InputEvent::Mouse(NowInputEventMouse::new_with_flags_and_position(
                EventMouseFlags::None,
                1504,
                624,
            )),
        ];

        let packet = NowPacket::from_message(NowInputMsg::new_with_events(mouse_events));

        assert_eq!(packet.encode().unwrap(), MOUSE_POSITION_EVENT_FULL_PACKET.to_vec());
    }

    #[test]
    fn input_event_mouse_decode_full_packet() {
        let mut buffer = Vec::new();
        let mut reader = Cursor::new(&MOUSE_POSITION_EVENT_FULL_PACKET[..]);
        match NowPacket::read_from(&mut reader, &mut buffer, &VirtChannelsCtx::new()) {
            Ok(_) => {}
            Err(e) => {
                e.print_trace();
                panic!("couldn't decode input mouse event packet");
            }
        }
    }

    #[test]
    fn input_event_toggle_encode() {
        let toggle_event = vec![InputEvent::Toggle(NowInputEventToggle::new_with_code(
            ToggleEventKeys::NumLock as u16,
        ))];

        let packet = NowPacket::from_message(NowInputMsg::new_with_events(toggle_event));

        assert_eq!(packet.encode().unwrap(), TOGGLE_EVENT_FULL_PACKET.to_vec());
    }

    #[test]
    fn input_event_toggle_decode() {
        let toggle_event = InputEvent::decode(&TOGGLE_EVENT_FULL_PACKET[6..]).unwrap();
        if let InputEvent::Toggle(toggle_event) = toggle_event {
            assert_eq!(toggle_event.subtype, InputMessageType::Toggle);
            assert_eq!(toggle_event.code, 2);
        } else {
            panic!("couldn't decode toggle message")
        }
    }

    #[test]
    fn input_event_keyboard_encode() {
        let kb_events = vec![InputEvent::Keyboard(NowInputEventKeyboard::new_with_flags_and_code(
            1, 8,
        ))];

        let packet = NowPacket::from_message(NowInputMsg::new_with_events(kb_events));

        assert_eq!(packet.encode().unwrap(), KEYBOARD_EVENT_FULL_PACKET.to_vec());
    }

    #[test]
    fn input_event_keyboard_decode() {
        let kb_event = InputEvent::decode(&KEYBOARD_EVENT_FULL_PACKET[6..]).unwrap();
        if let InputEvent::Keyboard(kb_event) = kb_event {
            assert_eq!(kb_event.subtype, InputMessageType::Keyboard);
            assert_eq!(kb_event.code, 8);
        } else {
            panic!("couldn't decode keyboard message")
        }
    }

    #[test]
    fn input_event_scroll_encode() {
        let scroll_events = vec![InputEvent::Scroll(NowInputEventScroll::new_with_position(0, 120))];

        let packet = NowPacket::from_message(NowInputMsg::new_with_events(scroll_events));

        assert_eq!(packet.encode().unwrap(), MOUSE_SCROLL_EVENT_FULL_PACKET.to_vec());
    }

    #[test]
    fn input_event_scroll_decode() {
        let scroll_event = InputEvent::decode(&MOUSE_SCROLL_EVENT_FULL_PACKET[6..]).unwrap();
        if let InputEvent::Scroll(scroll_event) = scroll_event {
            assert_eq!(scroll_event.subtype, InputMessageType::Scroll);
            assert_eq!(scroll_event.x, 0);
            assert_eq!(scroll_event.y, 120);
        } else {
            panic!("couldn't decode scroll message")
        }
    }

    #[test]
    fn input_event_unicode_encode() {
        let unicode_events = vec![InputEvent::Unicode(NowInputEventUnicode::new(vec![
            0xe4, 0x05, 0x77, 0x02,
        ]))];

        let packet = NowPacket::from_message(NowInputMsg::new_with_events(unicode_events));
        assert_eq!(packet.encode().unwrap(), UNICODE_EVENT_FULL_PACKET.to_vec());
    }

    #[test]
    fn input_event_unicode_decode() {
        let unicode_event = InputEvent::decode(&UNICODE_EVENT_FULL_PACKET[6..]).unwrap();
        if let InputEvent::Unicode(unicode_event) = unicode_event {
            assert_eq!(unicode_event.subtype, InputMessageType::Unicode);
            assert_eq!(unicode_event.code, vec![0xe4, 0x05, 0x77, 0x02]);
        } else {
            panic!("didnt decode unicode message")
        }
    }
}