pub(crate) const USER_DEFAULT_SCREEN_DPI: f32 = 96.0;
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
pub(crate) fn size_from_lparam(lparam: isize) -> (u32, u32) {
let packed = lparam as u32;
(packed & 0xFFFF, (packed >> 16) & 0xFFFF)
}
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
pub(crate) fn dpi_scale_from_wparam(wparam: usize) -> f32 {
dpi_ratio((wparam & 0xFFFF) as u32)
}
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
pub(crate) fn dpi_ratio(dpi: u32) -> f32 {
if dpi == 0 {
1.0
} else {
dpi as f32 / USER_DEFAULT_SCREEN_DPI
}
}
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
pub(crate) fn pt_to_dip(size_pt: f32) -> f32 {
size_pt * USER_DEFAULT_SCREEN_DPI / 72.0
}
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
pub(crate) fn point_from_lparam(lparam: isize) -> (i16, i16) {
let packed = lparam as u32;
((packed & 0xFFFF) as i16, ((packed >> 16) & 0xFFFF) as i16)
}
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
pub(crate) fn wheel_delta_from_wparam(wparam: usize) -> i16 {
((wparam as u32 >> 16) & 0xFFFF) as i16
}
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
pub(crate) const WHEEL_DELTA: f32 = 120.0;
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
pub(crate) fn is_repeat_from_lparam(lparam: isize) -> bool {
(lparam as u32) & (1 << 30) != 0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn size_from_lparam_reads_width_from_the_low_word() {
let lparam = (720isize << 16) | 1280isize;
assert_eq!(size_from_lparam(lparam), (1280, 720));
}
#[test]
fn size_from_lparam_truncates_rather_than_sign_extending() {
let packed = ((34_000u32 << 16) | 3840u32) as i32 as isize;
assert!(packed < 0, "test setup: expected the sign bit to be set");
assert_eq!(size_from_lparam(packed), (3840, 34_000));
}
#[test]
fn size_from_lparam_handles_a_zero_client_rect() {
assert_eq!(size_from_lparam(0), (0, 0));
}
#[test]
fn dpi_scale_from_wparam_converts_dpi_to_a_scale_ratio() {
let wparam = (144usize << 16) | 144usize;
assert_eq!(dpi_scale_from_wparam(wparam), 1.5);
}
#[test]
fn dpi_scale_from_wparam_maps_the_96_dpi_baseline_to_100_percent() {
assert_eq!(dpi_scale_from_wparam((96usize << 16) | 96usize), 1.0);
}
#[test]
fn dpi_ratio_matches_the_standard_windows_scaling_steps() {
assert_eq!(dpi_ratio(96), 1.0);
assert_eq!(dpi_ratio(120), 1.25);
assert_eq!(dpi_ratio(144), 1.5);
assert_eq!(dpi_ratio(192), 2.0);
}
#[test]
fn dpi_ratio_falls_back_to_unscaled_instead_of_dividing_by_zero() {
let scale = dpi_ratio(0);
assert!(scale.is_finite(), "scale must never be inf/NaN");
assert_eq!(scale, 1.0);
}
#[test]
fn pt_to_dip_converts_points_to_dips_at_96_over_72() {
assert_eq!(pt_to_dip(72.0), 96.0);
assert!((pt_to_dip(11.0) - 14.666_667).abs() < 0.001);
}
#[test]
fn pt_to_dip_maps_zero_to_zero() {
assert_eq!(pt_to_dip(0.0), 0.0);
}
#[test]
fn point_from_lparam_reads_x_from_the_low_word() {
let lparam = (200isize << 16) | 100isize;
assert_eq!(point_from_lparam(lparam), (100, 200));
}
#[test]
fn point_from_lparam_sign_extends_negative_coordinates() {
let x = (-5i16) as u16 as isize;
let y = (-10i16) as u16 as isize;
let lparam = (y << 16) | x;
assert_eq!(point_from_lparam(lparam), (-5, -10));
}
#[test]
fn point_from_lparam_handles_the_origin() {
assert_eq!(point_from_lparam(0), (0, 0));
}
#[test]
fn wheel_delta_from_wparam_reads_forward_and_backward_notches() {
let forward = (120i16 as u16 as usize) << 16;
assert_eq!(wheel_delta_from_wparam(forward), 120);
let backward = ((-120i16) as u16 as usize) << 16;
assert_eq!(wheel_delta_from_wparam(backward), -120);
}
#[test]
fn wheel_delta_from_wparam_ignores_the_low_word_key_state_flags() {
let wparam = (120usize << 16) | 0x0009; assert_eq!(wheel_delta_from_wparam(wparam), 120);
}
#[test]
fn is_repeat_from_lparam_reads_bit_30() {
assert!(!is_repeat_from_lparam(0));
assert!(is_repeat_from_lparam(1 << 30));
assert!(is_repeat_from_lparam((1 << 30) | (1 << 31)));
assert!(!is_repeat_from_lparam(1 << 29));
}
}