diff --git a/src/outputs.rs b/src/outputs.rs index 29f4e78c..39b06e92 100644 --- a/src/outputs.rs +++ b/src/outputs.rs @@ -129,7 +129,7 @@ pub mod c { outputs: COutputs, wl_output: WlOutput, _x: i32, _y: i32, - _phys_width: i32, _phys_height: i32, + phys_width: i32, phys_height: i32, _subpixel: i32, _make: *const c_char, _model: *const c_char, transform: i32, @@ -145,8 +145,23 @@ pub mod c { let output_state: Option<&mut OutputState> = find_output_mut(&mut collection, wl_output) .map(|o| &mut o.pending); + match output_state { - Some(state) => { state.transform = Some(transform) }, + Some(state) => { + state.transform = Some(transform); + state.phys_size = { + if (phys_width > 0) & (phys_height > 0) { + Some(SizeMM { width: phys_width, height: phys_height }) + } else { + log_print!( + logging::Level::Surprise, + "Impossible physical dimensions: {}mm × {}mm", + phys_width, phys_height, + ); + None + } + } + }, None => log_print!( logging::Level::Warning, "Got geometry on unknown output", @@ -299,6 +314,12 @@ pub struct Size { pub height: u32, } +#[derive(Clone)] +pub struct SizeMM { + pub width: i32, + pub height: i32, +} + /// wl_output mode #[derive(Clone)] struct Mode { @@ -309,6 +330,7 @@ struct Mode { #[derive(Clone)] pub struct OutputState { current_mode: Option, + phys_size: Option, transform: Option, pub scale: i32, } @@ -323,6 +345,7 @@ impl OutputState { fn uninitialized() -> OutputState { OutputState { current_mode: None, + phys_size: None, transform: None, scale: 1, } @@ -334,6 +357,35 @@ impl OutputState { OutputState { current_mode: Some(Mode { width, height } ), transform: Some(transform), + phys_size: _, + scale: _, + } => Some( + match transform { + Transform::Normal + | Transform::Rotated180 + | Transform::Flipped + | Transform::FlippedRotated180 => Size { + width: *width as u32, + height: *height as u32, + }, + _ => Size { + width: *height as u32, + height: *width as u32, + }, + } + ), + _ => None, + } + } + + /// Returns transformed dimensions + pub fn get_phys_size(&self) -> Option { + use self::c::Transform; + match self { + OutputState { + current_mode: _, + transform: Some(transform), + phys_size: Some(SizeMM { width, height }), scale: _, } => Some( match transform { diff --git a/src/ui_manager.rs b/src/ui_manager.rs index c7af6521..5f56fcf1 100644 --- a/src/ui_manager.rs +++ b/src/ui_manager.rs @@ -8,6 +8,8 @@ */ use std::cmp::min; + +use ::logging; use ::outputs::c::OutputHandle; mod c { @@ -57,6 +59,43 @@ pub struct Manager { } impl Manager { + /// The largest ideal heigth for the keyboard as a whole + /// judged by the ease of hitting targets within. + /// Ideally related to finger size, the crammedness of the layout, + /// distance from display, and motor skills of the user. + // FIXME: Start by making this aware of display's dpi, + // then layout number of rows. + fn get_max_target_height(&self) -> u32 { + let layout_rows = 4; // FIXME: use number from layout. + let (scale, px_size, phys_size) = (&self.output).as_ref() + .and_then(|o| o.get_state()) + .map(|os| (os.scale as u32, os.get_pixel_size(), os.get_phys_size())) + .unwrap_or((1, None, None)); + + let finger_height_px = match (px_size, phys_size) { + (Some(px_size), Some(phys_size)) => { + // Fudged to result in 420px from the original design. + // That gives about 9.5mm per finger height. + // Maybe floats are not the best choice here, + // but it gets rounded ASAP. Consider rationals. + let keyboard_fraction_of_display: f64 = 420. / 1440.; + let keyboard_mm = keyboard_fraction_of_display * 130.; + let finger_height_mm = keyboard_mm / 4.; + // TODO: Take into account target shape/area, not just height. + finger_height_mm * px_size.height as f64 / phys_size.height as f64 + }, + (_, None) => scale as f64 * 52.5, // match total 420px at scale 2 from original design + (None, Some(_)) => { + log_print!( + logging::Level::Surprise, + "Output has physical size data but no pixel info", + ); + scale as f64 * 52.5 + }, + }; + (layout_rows as f64 * finger_height_px) as u32 + } + fn get_perceptual_height(&self) -> Option { let output_info = (&self.output).as_ref() .and_then(|o| o.get_state()) @@ -71,8 +110,11 @@ impl Manager { 360 }; - // Don't exceed half the display size - min(height, px_size.height / 2) / scale + // Don't exceed half the display size. + let height = min(height, px_size.height / 2); + // Don't waste screen space by exceeding best target height. + let height = min(height, self.get_max_target_height()); + height / scale }), Some((scale, None)) => Some(360 / scale), None => None,