view src/uinput.rs @ 14:adab13145994

Add support for remote clients.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Mon, 02 Nov 2020 00:06:09 +0100
parents d43c31aff57c
children 478cf2a7d577
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 std::fs::{File, OpenOptions};
use crate::{MAX_X, MAX_Y};
use input_linux::{
    sys::input_event, sys::timeval, AbsoluteAxis, AbsoluteInfo, AbsoluteInfoSetup, EventKind,
    InputId, InputProperty, Key, MiscKind, SynchronizeKind, UInputHandle,
};

pub fn create_uinput_device() -> std::io::Result<UInputHandle<File>> {
    let file = OpenOptions::new().write(true).open("/dev/uinput")?;
    let dev = UInputHandle::new(file);

    dev.set_evbit(EventKind::Synchronize)?;
    dev.set_evbit(EventKind::Key)?;
    dev.set_evbit(EventKind::Absolute)?;
    dev.set_evbit(EventKind::Misc)?;
    dev.set_keybit(Key::ButtonToolPen)?;
    dev.set_keybit(Key::ButtonToolRubber)?;
    dev.set_keybit(Key::ButtonToolBrush)?;
    dev.set_keybit(Key::ButtonToolPencil)?;
    dev.set_keybit(Key::ButtonToolAirbrush)?;
    dev.set_keybit(Key::ButtonTouch)?;
    dev.set_keybit(Key::ButtonStylus)?;
    dev.set_keybit(Key::ButtonStylus2)?;
    dev.set_keybit(Key::ButtonStylus3)?;
    dev.set_mscbit(MiscKind::Serial)?;
    dev.set_propbit(InputProperty::Direct)?;

    dev.set_absbit(AbsoluteAxis::X)?;
    dev.set_absbit(AbsoluteAxis::Y)?;
    dev.set_absbit(AbsoluteAxis::Z)?;
    dev.set_absbit(AbsoluteAxis::Wheel)?;
    dev.set_absbit(AbsoluteAxis::Pressure)?;
    dev.set_absbit(AbsoluteAxis::Distance)?;
    dev.set_absbit(AbsoluteAxis::TiltX)?;
    dev.set_absbit(AbsoluteAxis::TiltY)?;
    dev.set_absbit(AbsoluteAxis::Misc)?;

    let id = InputId {
        bustype: 3,
        vendor: 0x56a,
        product: 0x350,
        version: 0xb,
    };

    let x = AbsoluteInfoSetup {
        axis: AbsoluteAxis::X,
        info: AbsoluteInfo {
            value: 0,
            minimum: 0,
            maximum: MAX_X,
            fuzz: 0,
            flat: 0,
            resolution: 200,
        },
    };
    let y = AbsoluteInfoSetup {
        axis: AbsoluteAxis::Y,
        info: AbsoluteInfo {
            value: 0,
            minimum: 0,
            maximum: MAX_Y,
            fuzz: 0,
            flat: 0,
            resolution: 200,
        },
    };
    let z = AbsoluteInfoSetup {
        axis: AbsoluteAxis::Z,
        info: AbsoluteInfo {
            value: 0,
            minimum: -900,
            maximum: 899,
            fuzz: 0,
            flat: 0,
            resolution: 287,
        },
    };
    let wheel = AbsoluteInfoSetup {
        axis: AbsoluteAxis::Wheel,
        info: AbsoluteInfo {
            value: 0,
            minimum: 0,
            maximum: 2047,
            fuzz: 0,
            flat: 0,
            resolution: 0,
        },
    };
    let pressure = AbsoluteInfoSetup {
        axis: AbsoluteAxis::Pressure,
        info: AbsoluteInfo {
            value: 0,
            minimum: 0,
            maximum: 8196,
            fuzz: 0,
            flat: 0,
            resolution: 0,
        },
    };
    let distance = AbsoluteInfoSetup {
        axis: AbsoluteAxis::Distance,
        info: AbsoluteInfo {
            value: 0,
            minimum: 0,
            maximum: 63,
            fuzz: 0,
            flat: 0,
            resolution: 0,
        },
    };
    let tilt_x = AbsoluteInfoSetup {
        axis: AbsoluteAxis::TiltX,
        info: AbsoluteInfo {
            value: 0,
            minimum: -64,
            maximum: 63,
            fuzz: 0,
            flat: 0,
            resolution: 57,
        },
    };
    let tilt_y = AbsoluteInfoSetup {
        axis: AbsoluteAxis::TiltY,
        info: AbsoluteInfo {
            value: 0,
            minimum: -64,
            maximum: 63,
            fuzz: 0,
            flat: 0,
            resolution: 57,
        },
    };
    let misc = AbsoluteInfoSetup {
        axis: AbsoluteAxis::Misc,
        info: AbsoluteInfo {
            value: 0,
            minimum: 0,
            maximum: 0,
            fuzz: 0,
            flat: 0,
            resolution: 0,
        },
    };

    dev.create(
        &id,
        b"TabletEmu",
        0,
        &[x, y, z, wheel, pressure, distance, tilt_x, tilt_y, misc],
    )?;
    Ok(dev)
}

fn input_event_new(type_: EventKind, code: u16, value: i32) -> input_event {
    input_event {
        time: timeval {
            tv_sec: 0,
            tv_usec: 0,
        },
        type_: type_ as u16,
        code,
        value,
    }
}

pub fn input_axis_new(code: AbsoluteAxis, value: i32) -> input_event {
    input_event_new(EventKind::Absolute, code as u16, value)
}

pub fn input_key_new(code: Key, value: i32) -> input_event {
    input_event_new(EventKind::Key, code as u16, value)
}

pub fn input_misc_new(code: MiscKind, value: i32) -> input_event {
    input_event_new(EventKind::Misc, code as u16, value)
}

pub fn input_synchronize_new(code: SynchronizeKind, value: i32) -> input_event {
    input_event_new(EventKind::Synchronize, code as u16, value)
}