view src/bin/server.rs @ 19:ba09079686a0

Add support for different endianness between client and server.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Thu, 26 Aug 2021 23:43:36 +0200
parents 3f7b7a3ad8fe
children
line wrap: on
line source

// Tablet emulator, for people who don’t own one
// Copyright © 2020 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

use input_linux::Key;
use std::io::{self, ErrorKind};
use std::net::UdpSocket;
use tablet_emu::protocol::{Buttons, Event};
use tablet_emu::state::State;

pub fn run_server(address: &str) -> io::Result<()> {
    let mut state = match State::new() {
        Ok(state) => state,
        Err(err) => {
            match err.kind() {
                ErrorKind::NotFound => {
                    eprintln!("Couldn’t find /dev/uinput: {}", err);
                    eprintln!("Maybe you forgot to `modprobe uinput`?");
                }
                ErrorKind::PermissionDenied => {
                    eprintln!("Couldn’t open /dev/uinput for writing: {}", err);
                    eprintln!("Maybe you aren’t allowed to create input devices?");
                }
                _ => eprintln!("Couldn’t open /dev/uinput for writing: {}", err),
            }
            std::process::exit(1);
        }
    };

    let socket = UdpSocket::bind(address)?;
    println!("Listening on {:?}", socket);
    println!("Here is an example client: https://hg.linkmauve.fr/remote-gamepad");

    let mut last = Some((0., 0.));
    state.set_size(320, 240);
    loop {
        let mut buf: [u8; 16] = Default::default();
        let (amount, source) = socket.recv_from(&mut buf)?;
        if amount != std::mem::size_of::<Event>() {
            eprintln!("Invalid data length: {}", amount);
            continue;
        }
        let event: Event = bincode::deserialize(&buf).unwrap();
        println!("{:?} from {:?}", event, source);
        if event.buttons.contains(Buttons::A) {
            state.select_tool(Key::ButtonToolPen);
        } else if event.buttons.contains(Buttons::B) {
            state.select_tool(Key::ButtonToolRubber);
        } else if event.buttons.contains(Buttons::X) {
            state.select_tool(Key::ButtonToolBrush);
        } else if event.buttons.contains(Buttons::Y) {
            state.select_tool(Key::ButtonToolPencil);
        } else if event.buttons.contains(Buttons::SELECT) {
            state.select_tool(Key::ButtonToolAirbrush);
        } else if event.buttons.contains(Buttons::RESIZE) {
            println!(
                "set_size({}, {})",
                event.touch.0 as i32, event.touch.1 as i32
            );
            state.set_size(event.touch.0 as i32, event.touch.1 as i32);
        }
        let (x, y) = event.touch;
        if event.buttons.contains(Buttons::TOUCH) {
            if let None = last {
                state.press(x as f64, y as f64)?;
                last = Some((x as f64, y as f64));
                continue;
            }
        } else {
            if let Some((x, y)) = last {
                state.release(x, y)?;
                last = None;
                continue;
            }
        }
        state.motion(x as f64, y as f64)?;
        last = Some((x as f64, y as f64));
    }
}

pub fn main() {
    let args: Vec<_> = std::env::args().collect();
    let address = if args.len() > 1 {
        args[1].clone()
    } else {
        String::from("0.0.0.0:16150")
    };
    run_server(&address).unwrap();
}