Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ a library interface to the callers, thus avoiding erroneous ioctls, etc.
[features]
default = []
# Use features from libevdev version 1.10 and greater (libevdev_property_disable)
libevdev-1-10 = ["evdev-sys/libevdev-1-10"]
v1_10 = ["evdev-sys/v1_10"]

[dependencies]
serde = { version = "1.0", default-features = false, features=["derive"], optional = true }
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ to enable serialization support, enable the feature "serde"
evdev-rs = { version = "0.6.3", features = ["serde"] }
```

With a newer libevdev version (>= 1.10) enable the feature `libevdev-1-10` to
With a newer libevdev version (>= 1.10) enable the feature `v1_10` to
allow disabling a property. It also extends the `Enable` trait to `InputProp`,
enabling the use of `enable()`, `disable()` and `has()` for `InputProp` as well.

Expand Down
12 changes: 9 additions & 3 deletions evdev-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,17 @@ High level Rust bindings are available in the `evdev` crate
"""

[features]
libevdev-1-10 = []
v1_10 = []

[dependencies]
libc = "0.2.67"

[build-dependencies]
pkg-config = "0.3.17"
cc = "1.0.50"
system-deps = "7"

[package.metadata.system-deps.libevdev]
name = "libevdev"
version = "1"

[package.metadata.system-deps.libevdev.v1_10]
version = "1.10"
156 changes: 37 additions & 119 deletions evdev-sys/build.rs
Original file line number Diff line number Diff line change
@@ -1,146 +1,64 @@
use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::{env, fs, path::PathBuf, process::Command};

#[cfg(feature = "libevdev-1-10")]
// ver_str is string of the form "major.minor.patch"
fn parse_version(ver_str: &str) -> Option<(u32, u32, u32)> {
let mut major_minor_patch = ver_str
.split(".")
.map(|str| str.parse::<u32>().unwrap());
let major = major_minor_patch.next()?;
let minor = major_minor_patch.next()?;
let patch = major_minor_patch.next()?;
Some((major, minor, patch))
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
if env::var_os("TARGET") == env::var_os("HOST") {
let mut config = pkg_config::Config::new();
config.print_system_libs(false);

match config.probe("libevdev") {
Ok(lib) => {
// panic if feature 1.10 is enabled and the installed library
// is older than 1.10
#[cfg(feature = "libevdev-1-10")]
{
let (major, minor, patch) = parse_version(&lib.version)
.expect("Could not parse version information");
assert_eq!(major, 1, "evdev-rs works only with libevdev 1");
assert!(minor >= 10,
"Feature libevdev-1-10 was enabled, when compiling \
for a system with libevdev version {}.{}.{}",
major,
minor,
patch,
);
}
for path in &lib.include_paths {
println!("cargo:include={}", path.display());
}
return Ok(());
}
Err(e) => eprintln!(
"Couldn't find libevdev from pkgconfig ({:?}), \
compiling it from source...",
e
),
};
fn main() {
if env::var("SYSTEM_DEPS_LIBEVDEV_BUILD_INTERNAL").is_err() {
unsafe { env::set_var("SYSTEM_DEPS_LIBEVDEV_BUILD_INTERNAL", "auto") };
}
system_deps::Config::new()
.add_build_internal("libevdev", build_from_source)
.probe()
.unwrap();
}

if !Path::new("libevdev/.git").exists() {
let mut download = Command::new("git");
download.args(&["submodule", "update", "--init", "--depth", "1"]);
run_ignore_error(&mut download)?;
fn build_from_source(
lib: &str,
version: &str,
) -> Result<system_deps::Library, system_deps::BuildInternalClosureError> {
if !std::path::Path::new("libevdev/.git").exists() {
let _ = Command::new("git")
.args(["submodule", "update", "--init", "--depth", "1"])
.status();
}

let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
let src = env::current_dir()?;
let mut cp = Command::new("cp");
cp.arg("-r")
.arg(&src.join("libevdev/"))
.arg(&dst)
.current_dir(&src);
run(&mut cp)?;

println!("cargo:rustc-link-search={}/lib", dst.display());
println!("cargo:root={}", dst.display());
println!("cargo:include={}/include", dst.display());
println!("cargo:rerun-if-changed=libevdev");
let build_dir = dst.join("build");
let src = env::current_dir().unwrap();
let jobs = env::var("NUM_JOBS").unwrap_or_else(|_| "1".into());

println!("cargo:rustc-link-lib=static=evdev");
let cfg = cc::Build::new();
let compiler = cfg.get_compiler();
let mut cp = Command::new("cp");
run(cp.arg("-r").arg(src.join("libevdev/")).arg(&dst))?;

if !&dst.join("build").exists() {
fs::create_dir(&dst.join("build"))?;
if !build_dir.exists() {
fs::create_dir(&build_dir)
.map_err(|e| system_deps::BuildInternalClosureError::failed(&e.to_string()))?;
}

let mut autogen = Command::new("sh");
let mut cflags = OsString::new();
for arg in compiler.args() {
cflags.push(arg);
cflags.push(" ");
}
autogen
.env("CC", compiler.path())
.env("CFLAGS", cflags)
.current_dir(&dst.join("build"))
.arg(
dst.join("libevdev/autogen.sh")
.to_str()
.unwrap()
.replace("C:\\", "/c/")
.replace("\\", "/"),
);
.current_dir(&build_dir)
.arg(dst.join("libevdev/autogen.sh").to_str().unwrap())
.arg(format!("--prefix={}", dst.display()));
if let Ok(h) = env::var("HOST") {
autogen.arg(format!("--host={}", h));
}
if let Ok(t) = env::var("TARGET") {
autogen.arg(format!("--target={}", t));
}
autogen.arg(format!("--prefix={}", sanitize_sh(&dst)));
run(&mut autogen)?;

let mut make = Command::new("make");
make.arg(&format!("-j{}", env::var("NUM_JOBS").unwrap()))
.current_dir(&dst.join("build"));
run(&mut make)?;

run(make.arg(format!("-j{jobs}")).current_dir(&build_dir))?;
let mut install = Command::new("make");
install.arg("install").current_dir(&dst.join("build"));
run(&mut install)?;
Ok(())
}
run(install.arg("install").current_dir(&build_dir))?;

fn run(cmd: &mut Command) -> std::io::Result<()> {
println!("running: {:?}", cmd);
assert!(cmd.status()?.success());
Ok(())
}
println!("cargo:rerun-if-changed=libevdev");

fn run_ignore_error(cmd: &mut Command) -> std::io::Result<()> {
println!("running: {:?}", cmd);
let _ = cmd.status();
Ok(())
system_deps::Library::from_internal_pkg_config(dst.join("lib/pkgconfig"), lib, version)
}

fn sanitize_sh(path: &Path) -> String {
let path = path.to_str().unwrap().replace("\\", "/");
return change_drive(&path).unwrap_or(path);

fn change_drive(s: &str) -> Option<String> {
let mut ch = s.chars();
let drive = ch.next().unwrap_or('C');
if ch.next() != Some(':') {
return None;
}
if ch.next() != Some('/') {
return None;
}
Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
}
fn run(cmd: &mut Command) -> Result<(), system_deps::BuildInternalClosureError> {
cmd.status()
.ok()
.and_then(|s| s.success().then_some(()))
.ok_or_else(|| system_deps::BuildInternalClosureError::failed(&format!("{cmd:?} failed")))
}
2 changes: 1 addition & 1 deletion evdev-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ extern "C" {
pub fn libevdev_get_driver_version(ctx: *const libevdev) -> c_int;
pub fn libevdev_has_property(ctx: *const libevdev, prop: c_uint) -> c_int;
pub fn libevdev_enable_property(ctx: *mut libevdev, prop: c_uint) -> c_int;
#[cfg(feature = "libevdev-1-10")]
#[cfg(feature = "v1_10")]
pub fn libevdev_disable_property (ctx: *mut libevdev, prop: c_uint) -> c_int;
pub fn libevdev_has_event_type(ctx: *const libevdev, type_: c_uint) -> c_int;
pub fn libevdev_has_event_code(
Expand Down
4 changes: 2 additions & 2 deletions src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub trait Enable {
fn has<D: DeviceWrapper>(&self, device: &D) -> bool;
}

#[cfg(feature = "libevdev-1-10")]
#[cfg(feature = "v1_10")]
impl Enable for InputProp {
fn enable<D: DeviceWrapper>(&self, device: &D) -> io::Result<()> {
device.enable_property(self)
Expand Down Expand Up @@ -248,7 +248,7 @@ pub trait DeviceWrapper: Sized {
}
}

#[cfg(feature = "libevdev-1-10")]
#[cfg(feature = "v1_10")]
fn disable_property(&self, prop: &InputProp) -> io::Result<()> {
let result =
unsafe { raw::libevdev_disable_property(self.raw(), (*prop) as c_uint) };
Expand Down
12 changes: 6 additions & 6 deletions tests/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,28 +127,28 @@ fn device_has_property() {

#[test]
fn device_enable_disable() {
#[cfg(feature = "libevdev-1-10")]
#[cfg(feature = "v1_10")]
let prop = InputProp::INPUT_PROP_POINTER;
let ev_type = EventType::EV_KEY;
let code = EventCode::EV_KEY(EV_KEY::KEY_LEFTSHIFT);
let d = UninitDevice::new().unwrap();
#[cfg(feature = "libevdev-1-10")]
#[cfg(feature = "v1_10")]
assert!(!d.has(prop));
assert!(!d.has(ev_type));
assert!(!d.has(code));
#[cfg(feature = "libevdev-1-10")]
#[cfg(feature = "v1_10")]
d.enable(prop).unwrap();
d.enable(ev_type).unwrap();
d.enable(code).unwrap();
#[cfg(feature = "libevdev-1-10")]
#[cfg(feature = "v1_10")]
assert!(d.has(prop));
assert!(d.has(ev_type));
assert!(d.has(code));
#[cfg(feature = "libevdev-1-10")]
#[cfg(feature = "v1_10")]
d.disable(prop).unwrap();
d.disable(ev_type).unwrap();
d.disable(code).unwrap();
#[cfg(feature = "libevdev-1-10")]
#[cfg(feature = "v1_10")]
assert!(!d.has(prop));
assert!(!d.has(ev_type));
assert!(!d.has(code));
Expand Down