Compare commits
9 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78e3ec164e | ||
|
|
b2a57bcf1d | ||
|
|
c50f57df15 | ||
|
|
ead55994d4 | ||
|
|
f857cede57 | ||
|
|
cf257a7707 | ||
|
|
5f2aa46ea9 | ||
|
|
a0d8bbd1f4 | ||
|
|
604d2e4134 |
7 changed files with 2075 additions and 76 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,2 +1 @@
|
||||||
Cargo.lock
|
|
||||||
target
|
target
|
||||||
|
|
|
||||||
1867
Cargo.lock
generated
Normal file
1867
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
19
Cargo.toml
19
Cargo.toml
|
|
@ -17,6 +17,7 @@ libc = "0.2"
|
||||||
linux-raw-sys = { version = "0.9", features = ["ioctl"] }
|
linux-raw-sys = { version = "0.9", features = ["ioctl"] }
|
||||||
memmap2 = "0.9"
|
memmap2 = "0.9"
|
||||||
polling = "3"
|
polling = "3"
|
||||||
|
xdg = "2.5.2"
|
||||||
reis = "0.4"
|
reis = "0.4"
|
||||||
rgb = "0.8"
|
rgb = "0.8"
|
||||||
signal-hook = "0.3"
|
signal-hook = "0.3"
|
||||||
|
|
@ -33,21 +34,21 @@ zbus = { version = "5", default-features = false, features = ["tokio"] }
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
bindgen = "0.71"
|
bindgen = "0.71"
|
||||||
|
|
||||||
[[bin]]
|
#[[bin]]
|
||||||
name = "ufkbd-evfb"
|
#name = "ufkbd-evfb"
|
||||||
path = "src/ufkbd_evfb.rs"
|
#path = "src/ufkbd_evfb.rs"
|
||||||
|
|
||||||
[[bin]]
|
#[[bin]]
|
||||||
name = "ufkbd-evfbo"
|
#name = "ufkbd-evfbo"
|
||||||
path = "src/ufkbd_evfbo.rs"
|
#path = "src/ufkbd_evfbo.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "ufkbd-gnome"
|
name = "ufkbd-gnome"
|
||||||
path = "src/ufkbd_gnome.rs"
|
path = "src/ufkbd_gnome.rs"
|
||||||
|
|
||||||
[[bin]]
|
#[[bin]]
|
||||||
name = "ufkbd-kde"
|
#name = "ufkbd-kde"
|
||||||
path = "src/ufkbd_kde.rs"
|
#path = "src/ufkbd_kde.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "ufkbd-sxmo"
|
name = "ufkbd-sxmo"
|
||||||
|
|
|
||||||
11
build.rs
11
build.rs
|
|
@ -23,16 +23,5 @@ fn main()
|
||||||
|
|
||||||
bindings.write_to_file(out_file).expect("Writing failure");
|
bindings.write_to_file(out_file).expect("Writing failure");
|
||||||
|
|
||||||
let builder = bindgen::builder();
|
|
||||||
|
|
||||||
let bindings = builder.header("/usr/include/linux/fb.h")
|
|
||||||
.generate()
|
|
||||||
.expect("The Linux headers must be installed");
|
|
||||||
|
|
||||||
let out_dir: PathBuf = env::var("OUT_DIR")
|
|
||||||
.expect("Environment variable $OUT_DIR must be defined")
|
|
||||||
.into();
|
|
||||||
let out_file = out_dir.join("linuxfb.rs");
|
|
||||||
|
|
||||||
bindings.write_to_file(out_file).expect("Writing failure");
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,15 @@
|
||||||
* Copyright (c) 2024, Richard Acayan. All rights reserved.
|
* Copyright (c) 2024, Richard Acayan. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::fs::File;
|
|
||||||
use rgb::alt::BGR;
|
use rgb::alt::BGR;
|
||||||
use rgb::alt::BGRA;
|
use rgb::alt::BGRA;
|
||||||
use rgb::RGB;
|
use rgb::RGB;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use std::fs::File;
|
||||||
use yaml_rust2::yaml::Hash;
|
use yaml_rust2::yaml::Hash;
|
||||||
use yaml_rust2::yaml::LoadError;
|
use yaml_rust2::yaml::LoadError;
|
||||||
use yaml_rust2::yaml::YamlDecoder;
|
|
||||||
use yaml_rust2::yaml::Yaml;
|
use yaml_rust2::yaml::Yaml;
|
||||||
|
use yaml_rust2::yaml::YamlDecoder;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct KeyboardColors {
|
pub struct KeyboardColors {
|
||||||
|
|
@ -25,8 +25,7 @@ pub struct KeyboardColors {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for KeyboardColors {
|
impl Default for KeyboardColors {
|
||||||
fn default() -> Self
|
fn default() -> Self {
|
||||||
{
|
|
||||||
Self {
|
Self {
|
||||||
background: RGB::new(0, 0, 0).into(),
|
background: RGB::new(0, 0, 0).into(),
|
||||||
keycap: RGB::new(0, 0, 0).into(),
|
keycap: RGB::new(0, 0, 0).into(),
|
||||||
|
|
@ -39,8 +38,7 @@ impl Default for KeyboardColors {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_color(yaml: &Yaml) -> Option<RGB<u8>>
|
fn parse_color(yaml: &Yaml) -> Option<RGB<u8>> {
|
||||||
{
|
|
||||||
let mut color_bytes = yaml
|
let mut color_bytes = yaml
|
||||||
.as_vec()?
|
.as_vec()?
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -50,7 +48,7 @@ fn parse_color(yaml: &Yaml) -> Option<RGB<u8>>
|
||||||
Some(RGB::new(
|
Some(RGB::new(
|
||||||
color_bytes.next()?,
|
color_bytes.next()?,
|
||||||
color_bytes.next()?,
|
color_bytes.next()?,
|
||||||
color_bytes.next()?
|
color_bytes.next()?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,12 +62,26 @@ pub struct Configuration {
|
||||||
wayland_height: i32,
|
wayland_height: i32,
|
||||||
wayland_im_enable: bool,
|
wayland_im_enable: bool,
|
||||||
|
|
||||||
|
key_padding: u64,
|
||||||
|
key_corner_radius: u64,
|
||||||
|
|
||||||
colors: KeyboardColors,
|
colors: KeyboardColors,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Configuration {
|
impl Configuration {
|
||||||
fn load_evfb(&mut self, yaml: &Hash)
|
fn get_configuration_file() -> Result<File, Box<dyn std::error::Error>> {
|
||||||
{
|
let xdg_dirs = xdg::BaseDirectories::with_prefix("unfettered-keyboard")?;
|
||||||
|
let config_file = xdg_dirs
|
||||||
|
.find_config_file("unfettered-keyboard.yaml")
|
||||||
|
.ok_or(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::NotFound,
|
||||||
|
"Config file not found",
|
||||||
|
))?;
|
||||||
|
println!("test{:?}", config_file);
|
||||||
|
Ok(File::open(config_file)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_evfb(&mut self, yaml: &Hash) {
|
||||||
let height = yaml.get(&Yaml::String(String::from("height")));
|
let height = yaml.get(&Yaml::String(String::from("height")));
|
||||||
if let Some(height) = height {
|
if let Some(height) = height {
|
||||||
let height = match height.as_f64() {
|
let height = match height.as_f64() {
|
||||||
|
|
@ -81,8 +93,7 @@ impl Configuration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_wayland(&mut self, yaml: &Hash)
|
fn load_wayland(&mut self, yaml: &Hash) {
|
||||||
{
|
|
||||||
let height = yaml.get(&Yaml::String(String::from("height")));
|
let height = yaml.get(&Yaml::String(String::from("height")));
|
||||||
if let Some(height) = height {
|
if let Some(height) = height {
|
||||||
let height = match height.as_i64() {
|
let height = match height.as_i64() {
|
||||||
|
|
@ -101,8 +112,7 @@ impl Configuration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_colors(&mut self, yaml: &Hash)
|
fn load_colors(&mut self, yaml: &Hash) {
|
||||||
{
|
|
||||||
if let Some(keycap) = yaml.get(&Yaml::String(String::from("keycap"))) {
|
if let Some(keycap) = yaml.get(&Yaml::String(String::from("keycap"))) {
|
||||||
self.colors.keycap = parse_color(keycap)
|
self.colors.keycap = parse_color(keycap)
|
||||||
.expect("Keycap color needs to be a list of 3 8-bit unsigned integers")
|
.expect("Keycap color needs to be a list of 3 8-bit unsigned integers")
|
||||||
|
|
@ -140,8 +150,7 @@ impl Configuration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load() -> Result<Self, LoadError>
|
pub fn load() -> Result<Self, LoadError> {
|
||||||
{
|
|
||||||
let mut cfg = Configuration {
|
let mut cfg = Configuration {
|
||||||
longpress: 600,
|
longpress: 600,
|
||||||
repeat: 25,
|
repeat: 25,
|
||||||
|
|
@ -151,12 +160,17 @@ impl Configuration {
|
||||||
wayland_im_enable: true,
|
wayland_im_enable: true,
|
||||||
evfb_height: 0.25,
|
evfb_height: 0.25,
|
||||||
|
|
||||||
|
key_padding: 2,
|
||||||
|
key_corner_radius: 5,
|
||||||
|
|
||||||
colors: KeyboardColors::default(),
|
colors: KeyboardColors::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(file) = File::open("/etc/unfettered-keyboard.yaml") {
|
if let Ok(file) = Self::get_configuration_file() {
|
||||||
let yaml = YamlDecoder::read(file).decode()?;
|
let yaml = YamlDecoder::read(file).decode()?;
|
||||||
let yaml = yaml[0].as_hash().expect("Top-level configuration should be a YAML mapping");
|
let yaml = yaml[0]
|
||||||
|
.as_hash()
|
||||||
|
.expect("Top-level configuration should be a YAML mapping");
|
||||||
|
|
||||||
let longpress = yaml.get(&Yaml::String(String::from("longpress_ms")));
|
let longpress = yaml.get(&Yaml::String(String::from("longpress_ms")));
|
||||||
if let Some(longpress) = longpress {
|
if let Some(longpress) = longpress {
|
||||||
|
|
@ -164,7 +178,8 @@ impl Configuration {
|
||||||
Some(l) => l.try_into().ok(),
|
Some(l) => l.try_into().ok(),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
let longpress = longpress.expect("Longpress time should be a 64-bit unsigned integer");
|
let longpress =
|
||||||
|
longpress.expect("Longpress time should be a 64-bit unsigned integer");
|
||||||
cfg.longpress = longpress;
|
cfg.longpress = longpress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -187,25 +202,56 @@ impl Configuration {
|
||||||
let keys = yaml.get(&Yaml::String(String::from("extra_keys")));
|
let keys = yaml.get(&Yaml::String(String::from("extra_keys")));
|
||||||
if let Some(keys) = keys {
|
if let Some(keys) = keys {
|
||||||
let keys = keys.as_vec().expect("Extra keys should be a list");
|
let keys = keys.as_vec().expect("Extra keys should be a list");
|
||||||
cfg.extra_keys = keys.iter().map(|y| String::from(y.as_str().unwrap())).collect();
|
cfg.extra_keys = keys
|
||||||
|
.iter()
|
||||||
|
.map(|y| String::from(y.as_str().unwrap()))
|
||||||
|
.collect();
|
||||||
cfg.extra_keys.sort_unstable();
|
cfg.extra_keys.sort_unstable();
|
||||||
}
|
}
|
||||||
|
|
||||||
let wl = yaml.get(&Yaml::String(String::from("wayland")));
|
let wl = yaml.get(&Yaml::String(String::from("wayland")));
|
||||||
if let Some(wl) = wl {
|
if let Some(wl) = wl {
|
||||||
let wl = wl.as_hash().expect("Wayland configuration should be a YAML mapping");
|
let wl = wl
|
||||||
|
.as_hash()
|
||||||
|
.expect("Wayland configuration should be a YAML mapping");
|
||||||
cfg.load_wayland(wl);
|
cfg.load_wayland(wl);
|
||||||
}
|
}
|
||||||
|
|
||||||
let evfb = yaml.get(&Yaml::String(String::from("evfb")));
|
let evfb = yaml.get(&Yaml::String(String::from("evfb")));
|
||||||
if let Some(evfb) = evfb {
|
if let Some(evfb) = evfb {
|
||||||
let evfb = evfb.as_hash().expect("Linux evdev-fbdev configuration should be a YAML mapping");
|
let evfb = evfb
|
||||||
|
.as_hash()
|
||||||
|
.expect("Linux evdev-fbdev configuration should be a YAML mapping");
|
||||||
cfg.load_evfb(evfb);
|
cfg.load_evfb(evfb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let key_padding = yaml.get(&Yaml::String(String::from("key_padding")));
|
||||||
|
if let Some(key_padding) = key_padding {
|
||||||
|
let key_padding = match key_padding.as_i64() {
|
||||||
|
Some(l) => l.try_into().ok(),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
let key_padding =
|
||||||
|
key_padding.expect("Key padding should be a 64-bit unsigned integer");
|
||||||
|
cfg.key_padding = key_padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
let key_corner_radius = yaml.get(&Yaml::String(String::from("key_corner_radius")));
|
||||||
|
if let Some(key_corner_radius) = key_corner_radius {
|
||||||
|
let key_corner_radius = match key_corner_radius.as_i64() {
|
||||||
|
Some(l) => l.try_into().ok(),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
let key_corner_radius = key_corner_radius
|
||||||
|
.expect("Key corner radius should be a 64-bit unsigned integer");
|
||||||
|
cfg.key_corner_radius = key_corner_radius;
|
||||||
|
}
|
||||||
|
|
||||||
let colors = yaml.get(&Yaml::String(String::from("colors")));
|
let colors = yaml.get(&Yaml::String(String::from("colors")));
|
||||||
if let Some(colors) = colors {
|
if let Some(colors) = colors {
|
||||||
let colors = colors.as_hash().expect("Color configuration should be a YAML mapping");
|
let colors = colors
|
||||||
|
.as_hash()
|
||||||
|
.expect("Color configuration should be a YAML mapping");
|
||||||
cfg.load_colors(colors);
|
cfg.load_colors(colors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -214,50 +260,52 @@ impl Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn longpress_ms(&self) -> u64
|
pub fn longpress_ms(&self) -> u64 {
|
||||||
{
|
|
||||||
self.longpress
|
self.longpress
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn repeat_ms(&self) -> u64
|
pub fn repeat_ms(&self) -> u64 {
|
||||||
{
|
|
||||||
self.repeat
|
self.repeat
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn layout(&self) -> &str
|
pub fn layout(&self) -> &str {
|
||||||
{
|
|
||||||
&self.layout
|
&self.layout
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn extra_keys(&self) -> &Vec<String>
|
pub fn extra_keys(&self) -> &Vec<String> {
|
||||||
{
|
|
||||||
&self.extra_keys
|
&self.extra_keys
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn wayland_height(&self) -> i32
|
pub fn wayland_height(&self) -> i32 {
|
||||||
{
|
|
||||||
self.wayland_height
|
self.wayland_height
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn wayland_im_enable(&self) -> bool
|
pub fn wayland_im_enable(&self) -> bool {
|
||||||
{
|
|
||||||
self.wayland_im_enable
|
self.wayland_im_enable
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn evfb_height(&self) -> f64
|
pub fn evfb_height(&self) -> f64 {
|
||||||
{
|
|
||||||
self.evfb_height
|
self.evfb_height
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn colors(&self) -> &KeyboardColors
|
pub fn colors(&self) -> &KeyboardColors {
|
||||||
{
|
|
||||||
&self.colors
|
&self.colors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn key_padding(&self) -> u64 {
|
||||||
|
self.key_padding
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn key_corner_radius(&self) -> u64 {
|
||||||
|
self.key_corner_radius
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,70 @@ fn fill_image(dest: &mut ImgRefMut<BGRA<u8>>, src: BGRA<u8>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn distance(x1: usize, y1: usize, x2: usize, y2: usize) -> f32
|
||||||
|
{
|
||||||
|
(((x1 as isize - x2 as isize).pow(2) + (y1 as isize - y2 as isize).pow(2)) as f32).sqrt()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_point_in_rounded_rectangle(
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
radius: usize,
|
||||||
|
) -> bool
|
||||||
|
{
|
||||||
|
// Check if the point is within the rectangle's main area
|
||||||
|
if x >= radius && x <= width - radius && y <= height {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if x <= width && y >= radius && y <= height - radius {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the corners
|
||||||
|
// Top-left corner
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if distance(x, y, radius, radius) < radius as f32 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top-right corner
|
||||||
|
if distance(x, y, width - radius, radius) < radius as f32 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom-left corner
|
||||||
|
if distance(x, y, radius, height - radius) < radius as f32 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom-right corner
|
||||||
|
if distance(x, y, width - radius, height - radius) < radius as f32 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn rounded_rectangle(dest: &mut ImgRefMut<BGRA<u8>>, src: BGRA<u8>, radius: usize)
|
||||||
|
{
|
||||||
|
let (width, height) = (dest.width(), dest.height());
|
||||||
|
|
||||||
|
for (y, row) in dest.rows_mut().enumerate() {
|
||||||
|
for (x, dest) in row.iter_mut().enumerate() {
|
||||||
|
if is_point_in_rounded_rectangle(x, y, width, height, radius) {
|
||||||
|
*dest = src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn bitmap_to_imgref(bitmap: &freetype::FT_Bitmap) -> ImgRef<u8>
|
fn bitmap_to_imgref(bitmap: &freetype::FT_Bitmap) -> ImgRef<u8>
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -93,6 +157,9 @@ pub struct Graphics<D: Display> {
|
||||||
x_scale: f64,
|
x_scale: f64,
|
||||||
y_scale: f64,
|
y_scale: f64,
|
||||||
|
|
||||||
|
key_padding: u64,
|
||||||
|
key_corner_radius: u64,
|
||||||
|
|
||||||
colors: KeyboardColors,
|
colors: KeyboardColors,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -217,6 +284,9 @@ impl<D: Display> Graphics<D> {
|
||||||
x_scale: 0.0,
|
x_scale: 0.0,
|
||||||
y_scale: 0.0,
|
y_scale: 0.0,
|
||||||
|
|
||||||
|
key_padding: cfg.key_padding(),
|
||||||
|
key_corner_radius: cfg.key_corner_radius(),
|
||||||
|
|
||||||
colors: cfg.colors().clone(),
|
colors: cfg.colors().clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -473,6 +543,9 @@ impl<D: Display> Graphics<D> {
|
||||||
let src = labels.get(label)
|
let src = labels.get(label)
|
||||||
.expect("Layout and size should be set before drawing");
|
.expect("Layout and size should be set before drawing");
|
||||||
|
|
||||||
|
assert!(src.img.height() > src.y, "Not enough space to draw label, reduce padding and/or corner radius");
|
||||||
|
|
||||||
|
|
||||||
let width = src.img.width();
|
let width = src.img.width();
|
||||||
let height = src.img.height() - src.y;
|
let height = src.img.height() - src.y;
|
||||||
|
|
||||||
|
|
@ -533,12 +606,13 @@ impl<D: Display> Graphics<D> {
|
||||||
x_scale: f64, y_scale: f64,
|
x_scale: f64, y_scale: f64,
|
||||||
img: &mut ImgRefMut<BGRA<u8>>,
|
img: &mut ImgRefMut<BGRA<u8>>,
|
||||||
key: &Key, mod_state: &[ModState],
|
key: &Key, mod_state: &[ModState],
|
||||||
|
key_padding: usize, key_corner_radius: usize,
|
||||||
colors: &KeyboardColors)
|
colors: &KeyboardColors)
|
||||||
{
|
{
|
||||||
let x1 = (key.x1 * x_scale) as usize;
|
let x1 = (key.x1 * x_scale) as usize + key_padding;
|
||||||
let y1 = (key.y1 * y_scale) as usize;
|
let y1 = (key.y1 * y_scale) as usize + key_padding;
|
||||||
let x2 = (key.x2 * x_scale) as usize;
|
let x2 = (key.x2 * x_scale) as usize - key_padding;
|
||||||
let y2 = (key.y2 * y_scale) as usize;
|
let y2 = (key.y2 * y_scale) as usize - key_padding;
|
||||||
|
|
||||||
let mut keyimg = img.sub_image_mut(x1, y1, x2 - x1, y2 - y1);
|
let mut keyimg = img.sub_image_mut(x1, y1, x2 - x1, y2 - y1);
|
||||||
|
|
||||||
|
|
@ -557,21 +631,30 @@ impl<D: Display> Graphics<D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if pressed {
|
if pressed {
|
||||||
fill_image(&mut keyimg, colors.keycap_pressed);
|
rounded_rectangle(&mut keyimg, colors.keycap_pressed, key_corner_radius);
|
||||||
} else {
|
} else {
|
||||||
fill_image(&mut keyimg, colors.keycap);
|
rounded_rectangle(&mut keyimg, colors.keycap, key_corner_radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let half_radius = key_corner_radius / 2;
|
||||||
|
let mut labelimg = keyimg.sub_image_mut(
|
||||||
|
half_radius,
|
||||||
|
half_radius,
|
||||||
|
keyimg.width() - half_radius * 2,
|
||||||
|
keyimg.height() - half_radius * 2
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
let color = Self::keypart_to_color(&key.parts[0], false, mod_state, colors);
|
let color = Self::keypart_to_color(&key.parts[0], false, mod_state, colors);
|
||||||
let label = key.parts[0].display_label();
|
let label = key.parts[0].display_label();
|
||||||
Self::draw_label_part(labels, Anchor::Center, Anchor::Center,
|
Self::draw_label_part(labels, Anchor::Center, Anchor::Center,
|
||||||
&mut keyimg, label, color.map(|c| c as f32 / 255.));
|
&mut labelimg, label, color.map(|c| c as f32 / 255.));
|
||||||
|
|
||||||
for i in 0..8 {
|
for i in 0..8 {
|
||||||
let color = Self::keypart_to_color(&key.parts[i + 1], true, mod_state, colors);
|
let color = Self::keypart_to_color(&key.parts[i + 1], true, mod_state, colors);
|
||||||
let label = key.parts[i + 1].display_label();
|
let label = key.parts[i + 1].display_label();
|
||||||
Self::draw_label_part(sublabels, ANCHORS[i].0, ANCHORS[i].1,
|
Self::draw_label_part(sublabels, ANCHORS[i].0, ANCHORS[i].1,
|
||||||
&mut keyimg, label, color.map(|c| c as f32 / 255.));
|
&mut labelimg, label, color.map(|c| c as f32 / 255.));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -586,7 +669,9 @@ impl<D: Display> Graphics<D> {
|
||||||
|
|
||||||
Self::draw_key(&self.labels, &self.sublabels,
|
Self::draw_key(&self.labels, &self.sublabels,
|
||||||
self.x_scale, self.y_scale,
|
self.x_scale, self.y_scale,
|
||||||
&mut img, key, mod_state, &self.colors);
|
&mut img, key, mod_state,
|
||||||
|
self.key_padding as usize, self.key_corner_radius as usize,
|
||||||
|
&self.colors);
|
||||||
|
|
||||||
self.disp.end(x1, y1, x2 - x1, y2 - y1);
|
self.disp.end(x1, y1, x2 - x1, y2 - y1);
|
||||||
}
|
}
|
||||||
|
|
@ -617,7 +702,9 @@ impl<D: Display> Graphics<D> {
|
||||||
for key in row {
|
for key in row {
|
||||||
Self::draw_key(&self.labels, &self.sublabels,
|
Self::draw_key(&self.labels, &self.sublabels,
|
||||||
self.x_scale, self.y_scale,
|
self.x_scale, self.y_scale,
|
||||||
&mut img, key, mod_state, &self.colors);
|
&mut img, key, mod_state,
|
||||||
|
self.key_padding as usize, self.key_corner_radius as usize,
|
||||||
|
&self.colors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ use std::os::raw::c_char;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
use xdg::BaseDirectories;
|
||||||
use xkeysym::Keysym;
|
use xkeysym::Keysym;
|
||||||
|
|
||||||
unsafe extern "C" fn start_elem(data: *mut c_void,
|
unsafe extern "C" fn start_elem(data: *mut c_void,
|
||||||
|
|
@ -725,18 +726,25 @@ impl Layout {
|
||||||
pub fn load(cfg: &Configuration) -> Result<Self, Error>
|
pub fn load(cfg: &Configuration) -> Result<Self, Error>
|
||||||
{
|
{
|
||||||
let extra_keys = cfg.extra_keys();
|
let extra_keys = cfg.extra_keys();
|
||||||
let dir = Path::new("/usr/share/unfettered-keyboard/layouts");
|
|
||||||
|
|
||||||
let path = dir.join(cfg.layout());
|
let base_dirs = BaseDirectories::with_prefix("unfettered-keyboard/layouts")?;
|
||||||
|
println!("{:?}",base_dirs);
|
||||||
|
|
||||||
|
let path = base_dirs.find_config_file(cfg.layout())
|
||||||
|
.ok_or(Error::new(ErrorKind::NotFound, "Main layout file not found"))?;
|
||||||
|
|
||||||
let main_layout = LayoutLoader::load(path, extra_keys)?;
|
let main_layout = LayoutLoader::load(path, extra_keys)?;
|
||||||
|
|
||||||
let path = dir.join("numeric.xml");
|
let path = base_dirs.find_config_file("numeric.xml")
|
||||||
|
.ok_or(Error::new(ErrorKind::NotFound, "Numeric layout file not found"))?;
|
||||||
let numeric = LayoutLoader::load(path, extra_keys)?;
|
let numeric = LayoutLoader::load(path, extra_keys)?;
|
||||||
|
|
||||||
let path = dir.join("greekmath.xml");
|
let path = base_dirs.find_config_file("greekmath.xml")
|
||||||
|
.ok_or(Error::new(ErrorKind::NotFound, "Greekmath layout file not found"))?;
|
||||||
let greekmath = LayoutLoader::load(path, extra_keys)?;
|
let greekmath = LayoutLoader::load(path, extra_keys)?;
|
||||||
|
|
||||||
let path = dir.join("bottom_row.xml");
|
let path = base_dirs.find_config_file("bottom_row.xml")
|
||||||
|
.ok_or(Error::new(ErrorKind::NotFound, "Bottom row layout file not found"))?;
|
||||||
let bottom_row = LayoutLoader::load(path, extra_keys)?;
|
let bottom_row = LayoutLoader::load(path, extra_keys)?;
|
||||||
|
|
||||||
let mut layout = Layout {
|
let mut layout = Layout {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue