rust-switcher 1.0.9

Windows keyboard layout switcher and text conversion utility
Documentation
use windows::{
    Win32::{
        Foundation::{HINSTANCE, HWND, LPARAM, RECT, WPARAM},
        Graphics::Gdi::{COLOR_WINDOW, GetSysColorBrush},
        UI::WindowsAndMessaging::{
            AdjustWindowRectEx, CS_HREDRAW, CS_VREDRAW, CreateWindowExW, DispatchMessageW,
            GetMessageW, GetSystemMetrics, HICON, ICON_BIG, ICON_SMALL, IMAGE_ICON, LR_SHARED,
            LoadImageW, MSG, RegisterClassExW, SM_CXICON, SM_CXSMICON, SM_CYICON, SM_CYSMICON,
            SendMessageW, TranslateMessage, WINDOW_EX_STYLE, WINDOW_STYLE, WM_SETICON, WNDCLASSEXW,
        },
    },
    core::{PCWSTR, Result, w},
};

use super::winutil::make_int_resource;
use crate::utils::helpers;

pub(crate) fn register_main_class(class_name: PCWSTR, hinstance: HINSTANCE) -> Result<()> {
    let wc = WNDCLASSEXW {
        cbSize: std::mem::size_of::<WNDCLASSEXW>() as u32,
        style: CS_HREDRAW | CS_VREDRAW,
        lpfnWndProc: Some(super::wndproc),
        lpszClassName: class_name,
        hInstance: hinstance,
        hbrBackground: unsafe { GetSysColorBrush(COLOR_WINDOW) },
        ..Default::default()
    };

    unsafe {
        if RegisterClassExW(&raw const wc) == 0 {
            return Err(helpers::last_error());
        }
    }
    Ok(())
}

pub(crate) fn compute_window_size(style: WINDOW_STYLE) -> Result<(i32, i32)> {
    const CLIENT_W: i32 = 760;
    const CLIENT_H: i32 = 230;

    let mut rect = RECT {
        left: 0,
        top: 0,
        right: CLIENT_W,
        bottom: CLIENT_H,
    };

    unsafe { AdjustWindowRectEx(&raw mut rect, style, false, WINDOW_EX_STYLE(0))? };

    Ok((rect.right - rect.left, rect.bottom - rect.top))
}

pub(crate) fn create_main_window(
    class_name: PCWSTR,
    hinstance: HINSTANCE,
    style: WINDOW_STYLE,
    x: i32,
    y: i32,
    window_w: i32,
    window_h: i32,
) -> Result<HWND> {
    unsafe {
        CreateWindowExW(
            WINDOW_EX_STYLE(0),
            class_name,
            w!("RustSwitcher"),
            style,
            x,
            y,
            window_w,
            window_h,
            None,
            None,
            Some(hinstance),
            None,
        )
    }
}

pub(crate) fn set_window_icons(hwnd: HWND, hinstance: HINSTANCE) {
    unsafe {
        let big = LoadImageW(
            Some(hinstance),
            make_int_resource(1),
            IMAGE_ICON,
            GetSystemMetrics(SM_CXICON),
            GetSystemMetrics(SM_CYICON),
            LR_SHARED,
        )
        .ok()
        .map(|h| HICON(h.0))
        .unwrap_or_default();

        let small = LoadImageW(
            Some(hinstance),
            make_int_resource(1),
            IMAGE_ICON,
            GetSystemMetrics(SM_CXSMICON),
            GetSystemMetrics(SM_CYSMICON),
            LR_SHARED,
        )
        .ok()
        .map(|h| HICON(h.0))
        .unwrap_or_default();

        if !big.0.is_null() {
            let _ = SendMessageW(
                hwnd,
                WM_SETICON,
                Some(WPARAM(ICON_BIG as usize)),
                Some(LPARAM(big.0 as isize)),
            );
        }

        if !small.0.is_null() {
            let _ = SendMessageW(
                hwnd,
                WM_SETICON,
                Some(WPARAM(ICON_SMALL as usize)),
                Some(LPARAM(small.0 as isize)),
            );
        }
    }
}

pub(crate) fn message_loop() -> Result<()> {
    unsafe {
        let mut msg = MSG::default();
        loop {
            let r = GetMessageW(&raw mut msg, None, 0, 0);
            if r.0 == -1 {
                return Err(helpers::last_error());
            }
            if r.0 == 0 {
                break;
            }
            let _ = TranslateMessage(&raw const msg);
            DispatchMessageW(&raw const msg);
        }
    }
    Ok(())
}