sizing: Use physical dimensions of the display to determine optimal keyboard height.

Parameters fudged appropriately to preserve dimensions from the original design targting Librem5:

- 720×1440 results in 420px height, via max finger size
- 1440×720 results in 360px height, via not exceeding half the display

In absence of physical dimensions, a pixel is assumed to measure half the size as on the Librem5, and then shrunk by the current display scale factor.This gives the ability to test in nested phoc at selected scale factors like before (2x being most accurate), and keeps the right size in QEMU.
This commit is contained in:
Dorota Czaplejewicz
2020-02-29 15:21:42 +00:00
parent 3d1a641ca3
commit 1093e32325
2 changed files with 98 additions and 4 deletions

View File

@ -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<Mode>,
phys_size: Option<SizeMM>,
transform: Option<c::Transform>,
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<Size> {
use self::c::Transform;
match self {
OutputState {
current_mode: _,
transform: Some(transform),
phys_size: Some(SizeMM { width, height }),
scale: _,
} => Some(
match transform {

View File

@ -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<u32> {
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,