#![cfg(target_os = "windows")]
use std::ffi::c_void;
use std::mem;
use std::ptr;
use windows::core::{PCWSTR, w};
use windows::Win32::Foundation::{HWND, LPARAM, LRESULT, WPARAM, RECT, POINT};
use windows::Win32::Graphics::Gdi::{
BeginPaint, EndPaint, InvalidateRect, PAINTSTRUCT, GetDC, ReleaseDC,
};
use windows::Win32::System::LibraryLoader::GetModuleHandleW;
use windows::Win32::UI::WindowsAndMessaging::{
CreateWindowExW, DefWindowProcW, DispatchMessageW, GetMessageW,
LoadCursorW, PostQuitMessage, RegisterClassW, ShowWindow, TranslateMessage,
UpdateWindow, CS_HREDRAW, CS_VREDRAW, CW_USEDEFAULT, IDC_ARROW,
MSG, SW_SHOW, WM_DESTROY, WM_PAINT, WM_SIZE, WM_LBUTTONDOWN,
WM_LBUTTONUP, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP,
WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_KEYDOWN, WM_KEYUP, WM_CHAR,
WNDCLASSW, WS_OVERLAPPEDWINDOW, GetWindowRect, SetWindowPos,
SWP_NOZORDER, SWP_NOMOVE, WINDOW_EX_STYLE, SetCursor,
IDC_IBEAM, IDC_CROSS, IDC_HAND, IDC_SIZEWE, IDC_SIZENS,
};
use windows::Win32::UI::Input::KeyboardAndMouse::{
GetKeyState, VK_SHIFT, VK_CONTROL, VK_MENU, VK_LWIN, VK_CAPITAL,
};
use crate::support::point::{Point, Extent};
use crate::view::{
View, BaseView, MouseButton, MouseButtonKind, KeyCode, KeyAction, KeyInfo,
TextInfo, CursorTracking, CursorType, DropInfo,
};
pub fn translate_key(vk: i32) -> KeyCode {
match vk {
0x41 => KeyCode::A,
0x42 => KeyCode::B,
0x43 => KeyCode::C,
0x44 => KeyCode::D,
0x45 => KeyCode::E,
0x46 => KeyCode::F,
0x47 => KeyCode::G,
0x48 => KeyCode::H,
0x49 => KeyCode::I,
0x4A => KeyCode::J,
0x4B => KeyCode::K,
0x4C => KeyCode::L,
0x4D => KeyCode::M,
0x4E => KeyCode::N,
0x4F => KeyCode::O,
0x50 => KeyCode::P,
0x51 => KeyCode::Q,
0x52 => KeyCode::R,
0x53 => KeyCode::S,
0x54 => KeyCode::T,
0x55 => KeyCode::U,
0x56 => KeyCode::V,
0x57 => KeyCode::W,
0x58 => KeyCode::X,
0x59 => KeyCode::Y,
0x5A => KeyCode::Z,
0x30 => KeyCode::Key0,
0x31 => KeyCode::Key1,
0x32 => KeyCode::Key2,
0x33 => KeyCode::Key3,
0x34 => KeyCode::Key4,
0x35 => KeyCode::Key5,
0x36 => KeyCode::Key6,
0x37 => KeyCode::Key7,
0x38 => KeyCode::Key8,
0x39 => KeyCode::Key9,
0x70 => KeyCode::F1,
0x71 => KeyCode::F2,
0x72 => KeyCode::F3,
0x73 => KeyCode::F4,
0x74 => KeyCode::F5,
0x75 => KeyCode::F6,
0x76 => KeyCode::F7,
0x77 => KeyCode::F8,
0x78 => KeyCode::F9,
0x79 => KeyCode::F10,
0x7A => KeyCode::F11,
0x7B => KeyCode::F12,
0x26 => KeyCode::Up,
0x28 => KeyCode::Down,
0x25 => KeyCode::Left,
0x27 => KeyCode::Right,
0x24 => KeyCode::Home,
0x23 => KeyCode::End,
0x21 => KeyCode::PageUp,
0x22 => KeyCode::PageDown,
0x2D => KeyCode::Insert,
0x2E => KeyCode::Delete,
0x08 => KeyCode::Backspace,
0x09 => KeyCode::Tab,
0x0D => KeyCode::Enter,
0x1B => KeyCode::Escape,
0x20 => KeyCode::Space,
0x10 => KeyCode::Shift,
0x11 => KeyCode::Control,
0x12 => KeyCode::Alt,
0x5B => KeyCode::LeftSuper,
0x5C => KeyCode::RightSuper,
0x14 => KeyCode::CapsLock,
0x90 => KeyCode::NumLock,
0x91 => KeyCode::ScrollLock,
_ => KeyCode::Unknown,
}
}
pub fn get_modifiers() -> i32 {
use crate::view::modifiers;
let mut mods = 0i32;
unsafe {
if GetKeyState(VK_SHIFT.0 as i32) < 0 {
mods |= modifiers::SHIFT;
}
if GetKeyState(VK_CONTROL.0 as i32) < 0 {
mods |= modifiers::CONTROL;
}
if GetKeyState(VK_MENU.0 as i32) < 0 {
mods |= modifiers::ALT;
}
if GetKeyState(VK_LWIN.0 as i32) < 0 {
mods |= modifiers::SUPER;
}
if GetKeyState(VK_CAPITAL.0 as i32) & 1 != 0 {
mods |= modifiers::CAPS_LOCK;
}
}
mods
}
pub fn set_cursor(cursor: CursorType) {
unsafe {
let cursor_id = match cursor {
CursorType::Arrow => IDC_ARROW,
CursorType::IBeam => IDC_IBEAM,
CursorType::CrossHair => IDC_CROSS,
CursorType::Hand => IDC_HAND,
CursorType::HResize => IDC_SIZEWE,
CursorType::VResize => IDC_SIZENS,
};
if let Ok(cursor) = LoadCursorW(None, cursor_id) {
SetCursor(cursor);
}
}
}
fn get_mouse_pos(lparam: LPARAM) -> Point {
let x = (lparam.0 & 0xFFFF) as i16 as f32;
let y = ((lparam.0 >> 16) & 0xFFFF) as i16 as f32;
Point::new(x, y)
}
unsafe extern "system" fn window_proc(
hwnd: HWND,
msg: u32,
wparam: WPARAM,
lparam: LPARAM,
) -> LRESULT {
match msg {
WM_DESTROY => {
PostQuitMessage(0);
LRESULT(0)
}
WM_PAINT => {
let mut ps = PAINTSTRUCT::default();
let _hdc = BeginPaint(hwnd, &mut ps);
EndPaint(hwnd, &ps);
LRESULT(0)
}
WM_SIZE => {
LRESULT(0)
}
WM_LBUTTONDOWN | WM_LBUTTONUP |
WM_RBUTTONDOWN | WM_RBUTTONUP |
WM_MBUTTONDOWN | WM_MBUTTONUP => {
LRESULT(0)
}
WM_MOUSEMOVE => {
LRESULT(0)
}
WM_MOUSEWHEEL => {
LRESULT(0)
}
WM_KEYDOWN | WM_KEYUP => {
LRESULT(0)
}
WM_CHAR => {
LRESULT(0)
}
_ => DefWindowProcW(hwnd, msg, wparam, lparam),
}
}
pub struct WindowsApp {
}
impl WindowsApp {
pub fn new() -> Option<Self> {
Some(Self {})
}
pub fn run(&self) {
unsafe {
let mut msg = MSG::default();
while GetMessageW(&mut msg, None, 0, 0).into() {
let _ = TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
}
pub fn stop(&self) {
unsafe {
PostQuitMessage(0);
}
}
}
pub struct WindowsWindow {
hwnd: HWND,
view: Option<View>,
}
impl WindowsWindow {
pub fn new(title: &str, size: Extent) -> Option<Self> {
unsafe {
let instance = GetModuleHandleW(None).ok()?;
let class_name = w!("MKGraphicWindow");
let wc = WNDCLASSW {
style: CS_HREDRAW | CS_VREDRAW,
lpfnWndProc: Some(window_proc),
hInstance: instance.into(),
lpszClassName: class_name,
hCursor: LoadCursorW(None, IDC_ARROW).ok()?,
..Default::default()
};
RegisterClassW(&wc);
let title_wide: Vec<u16> = title.encode_utf16().chain(std::iter::once(0)).collect();
let hwnd = CreateWindowExW(
WINDOW_EX_STYLE::default(),
class_name,
PCWSTR(title_wide.as_ptr()),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
size.x as i32,
size.y as i32,
None,
None,
instance,
None,
)?;
Some(Self {
hwnd,
view: Some(View::new(size)),
})
}
}
pub fn show(&self) {
unsafe {
let _ = ShowWindow(self.hwnd, SW_SHOW);
let _ = UpdateWindow(self.hwnd);
}
}
pub fn size(&self) -> Extent {
unsafe {
let mut rect = RECT::default();
let _ = GetWindowRect(self.hwnd, &mut rect);
Extent::new(
(rect.right - rect.left) as f32,
(rect.bottom - rect.top) as f32,
)
}
}
pub fn set_size(&self, size: Extent) {
unsafe {
let _ = SetWindowPos(
self.hwnd,
None,
0,
0,
size.x as i32,
size.y as i32,
SWP_NOZORDER | SWP_NOMOVE,
);
}
}
pub fn view(&self) -> Option<&View> {
self.view.as_ref()
}
pub fn view_mut(&mut self) -> Option<&mut View> {
self.view.as_mut()
}
pub fn handle(&self) -> HWND {
self.hwnd
}
}