chore(rustfmt): use nightly (#2325)

Stable rustfmt lacks a lot of features resulting in worse formatted
code, thus use nightly formatter.
This commit is contained in:
Kirill Chibisov 2024-04-26 19:11:44 +04:00 committed by GitHub
parent 7006c7ceca
commit 7b0c7b6cb2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
154 changed files with 3439 additions and 5891 deletions

View file

@ -3,21 +3,13 @@
use std::{ffi::c_void, ptr};
use crate::utils::Lazy;
use windows_sys::{
core::PCSTR,
Win32::{
Foundation::{BOOL, HWND, NTSTATUS, S_OK},
System::{
LibraryLoader::{GetProcAddress, LoadLibraryA},
SystemInformation::OSVERSIONINFOW,
},
UI::{
Accessibility::{HCF_HIGHCONTRASTON, HIGHCONTRASTA},
Controls::SetWindowTheme,
WindowsAndMessaging::{SystemParametersInfoA, SPI_GETHIGHCONTRAST},
},
},
};
use windows_sys::core::PCSTR;
use windows_sys::Win32::Foundation::{BOOL, HWND, NTSTATUS, S_OK};
use windows_sys::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryA};
use windows_sys::Win32::System::SystemInformation::OSVERSIONINFOW;
use windows_sys::Win32::UI::Accessibility::{HCF_HIGHCONTRASTON, HIGHCONTRASTA};
use windows_sys::Win32::UI::Controls::SetWindowTheme;
use windows_sys::Win32::UI::WindowsAndMessaging::{SystemParametersInfoA, SPI_GETHIGHCONTRAST};
use crate::window::Theme;
@ -72,11 +64,7 @@ pub fn try_theme(hwnd: HWND, preferred_theme: Option<Theme>) -> Theme {
None => should_use_dark_mode(),
};
let theme = if is_dark_mode {
Theme::Dark
} else {
Theme::Light
};
let theme = if is_dark_mode { Theme::Dark } else { Theme::Light };
let theme_name = match theme {
Theme::Dark => DARK_THEME_NAME.as_ptr(),
Theme::Light => LIGHT_THEME_NAME.as_ptr(),
@ -161,11 +149,7 @@ fn should_apps_use_dark_mode() -> bool {
}
fn is_high_contrast() -> bool {
let mut hc = HIGHCONTRASTA {
cbSize: 0,
dwFlags: 0,
lpszDefaultScheme: ptr::null_mut(),
};
let mut hc = HIGHCONTRASTA { cbSize: 0, dwFlags: 0, lpszDefaultScheme: ptr::null_mut() };
let ok = unsafe {
SystemParametersInfoA(

View file

@ -3,14 +3,10 @@
use std::ffi::c_void;
use windows_sys::{
core::{IUnknown, GUID, HRESULT},
Win32::{
Foundation::{BOOL, HWND, POINTL},
System::Com::{
IAdviseSink, IDataObject, IEnumFORMATETC, IEnumSTATDATA, FORMATETC, STGMEDIUM,
},
},
use windows_sys::core::{IUnknown, GUID, HRESULT};
use windows_sys::Win32::Foundation::{BOOL, HWND, POINTL};
use windows_sys::Win32::System::Com::{
IAdviseSink, IDataObject, IEnumFORMATETC, IEnumSTATDATA, FORMATETC, STGMEDIUM,
};
#[repr(C)]
@ -138,10 +134,10 @@ pub const CLSID_TaskbarList: GUID = GUID {
};
pub const IID_ITaskbarList: GUID = GUID {
data1: 0x56FDF342,
data2: 0xFD6D,
data3: 0x11D0,
data4: [0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90],
data1: 0x56fdf342,
data2: 0xfd6d,
data3: 0x11d0,
data4: [0x95, 0x8a, 0x00, 0x60, 0x97, 0xc9, 0xa0, 0x90],
};
pub const IID_ITaskbarList2: GUID = GUID {

View file

@ -2,19 +2,15 @@
use std::sync::Once;
use windows_sys::Win32::{
Foundation::{HWND, S_OK},
Graphics::Gdi::{
GetDC, GetDeviceCaps, MonitorFromWindow, HMONITOR, LOGPIXELSX, MONITOR_DEFAULTTONEAREST,
},
UI::{
HiDpi::{
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2,
MDT_EFFECTIVE_DPI, PROCESS_PER_MONITOR_DPI_AWARE,
},
WindowsAndMessaging::IsProcessDPIAware,
},
use windows_sys::Win32::Foundation::{HWND, S_OK};
use windows_sys::Win32::Graphics::Gdi::{
GetDC, GetDeviceCaps, MonitorFromWindow, HMONITOR, LOGPIXELSX, MONITOR_DEFAULTTONEAREST,
};
use windows_sys::Win32::UI::HiDpi::{
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2,
MDT_EFFECTIVE_DPI, PROCESS_PER_MONITOR_DPI_AWARE,
};
use windows_sys::Win32::UI::WindowsAndMessaging::IsProcessDPIAware;
use crate::platform_impl::platform::util::{
ENABLE_NON_CLIENT_DPI_SCALING, GET_DPI_FOR_MONITOR, GET_DPI_FOR_WINDOW, SET_PROCESS_DPI_AWARE,

View file

@ -1,31 +1,24 @@
use std::{
ffi::{c_void, OsString},
os::windows::ffi::OsStringExt,
path::PathBuf,
ptr,
sync::atomic::{AtomicUsize, Ordering},
};
use std::ffi::{c_void, OsString};
use std::os::windows::ffi::OsStringExt;
use std::path::PathBuf;
use std::ptr;
use std::sync::atomic::{AtomicUsize, Ordering};
use windows_sys::{
core::{IUnknown, GUID, HRESULT},
Win32::{
Foundation::{DV_E_FORMATETC, HWND, POINTL, S_OK},
System::{
Com::{IDataObject, DVASPECT_CONTENT, FORMATETC, TYMED_HGLOBAL},
Ole::{CF_HDROP, DROPEFFECT_COPY, DROPEFFECT_NONE},
},
UI::Shell::{DragFinish, DragQueryFileW, HDROP},
},
};
use windows_sys::core::{IUnknown, GUID, HRESULT};
use windows_sys::Win32::Foundation::{DV_E_FORMATETC, HWND, POINTL, S_OK};
use windows_sys::Win32::System::Com::{IDataObject, DVASPECT_CONTENT, FORMATETC, TYMED_HGLOBAL};
use windows_sys::Win32::System::Ole::{CF_HDROP, DROPEFFECT_COPY, DROPEFFECT_NONE};
use windows_sys::Win32::UI::Shell::{DragFinish, DragQueryFileW, HDROP};
use tracing::debug;
use crate::platform_impl::platform::{
definitions::{IDataObjectVtbl, IDropTarget, IDropTargetVtbl, IUnknownVtbl},
WindowId,
use crate::platform_impl::platform::definitions::{
IDataObjectVtbl, IDropTarget, IDropTargetVtbl, IUnknownVtbl,
};
use crate::platform_impl::platform::WindowId;
use crate::{event::Event, window::WindowId as RootWindowId};
use crate::event::Event;
use crate::window::WindowId as RootWindowId;
#[repr(C)]
pub struct FileDropHandlerData {
@ -34,7 +27,8 @@ pub struct FileDropHandlerData {
window: HWND,
send_event: Box<dyn Fn(Event<()>)>,
cursor_effect: u32,
hovered_is_valid: bool, /* If the currently hovered item is not valid there must not be any `HoveredFileCancelled` emitted */
hovered_is_valid: bool, /* If the currently hovered item is not valid there must not be any
* `HoveredFileCancelled` emitted */
}
pub struct FileDropHandler {
@ -45,18 +39,14 @@ pub struct FileDropHandler {
impl FileDropHandler {
pub fn new(window: HWND, send_event: Box<dyn Fn(Event<()>)>) -> FileDropHandler {
let data = Box::new(FileDropHandlerData {
interface: IDropTarget {
lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl,
},
interface: IDropTarget { lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl },
refcount: AtomicUsize::new(1),
window,
send_event,
cursor_effect: DROPEFFECT_NONE,
hovered_is_valid: false,
});
FileDropHandler {
data: Box::into_raw(data),
}
FileDropHandler { data: Box::into_raw(data) }
}
// Implement IUnknown
@ -104,11 +94,8 @@ impl FileDropHandler {
})
};
drop_handler.hovered_is_valid = hdrop.is_some();
drop_handler.cursor_effect = if drop_handler.hovered_is_valid {
DROPEFFECT_COPY
} else {
DROPEFFECT_NONE
};
drop_handler.cursor_effect =
if drop_handler.hovered_is_valid { DROPEFFECT_COPY } else { DROPEFFECT_NONE };
unsafe {
*pdwEffect = drop_handler.cursor_effect;
}
@ -190,7 +177,7 @@ impl FileDropHandler {
let hdrop = unsafe { medium.u.hGlobal as HDROP };
// The second parameter (0xFFFFFFFF) instructs the function to return the item count
let item_count = unsafe { DragQueryFileW(hdrop, 0xFFFFFFFF, ptr::null_mut(), 0) };
let item_count = unsafe { DragQueryFileW(hdrop, 0xffffffff, ptr::null_mut(), 0) };
for i in 0..item_count {
// Get the length of the path string NOT including the terminating null character.

File diff suppressed because it is too large Load diff

View file

@ -1,24 +1,18 @@
use std::{
any::Any,
cell::{Cell, RefCell},
collections::VecDeque,
mem, panic,
rc::Rc,
sync::{Arc, Mutex},
time::Instant,
};
use std::any::Any;
use std::cell::{Cell, RefCell};
use std::collections::VecDeque;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::time::Instant;
use std::{mem, panic};
use windows_sys::Win32::Foundation::HWND;
use crate::{
dpi::PhysicalSize,
event::{Event, InnerSizeWriter, StartCause, WindowEvent},
platform_impl::platform::{
event_loop::{WindowData, GWL_USERDATA},
get_window_long,
},
window::WindowId,
};
use crate::dpi::PhysicalSize;
use crate::event::{Event, InnerSizeWriter, StartCause, WindowEvent};
use crate::platform_impl::platform::event_loop::{WindowData, GWL_USERDATA};
use crate::platform_impl::platform::get_window_long;
use crate::window::WindowId;
use super::ControlFlow;
@ -187,12 +181,12 @@ impl<T> EventLoopRunner<T> {
Err(e) => {
self.panic_error.set(Some(e));
None
}
},
},
Some(e) => {
self.panic_error.set(Some(e));
None
}
},
}
} else {
self.panic_error.set(panic_error);
@ -212,22 +206,16 @@ impl<T> EventLoopRunner<T> {
}
pub(crate) fn send_event(&self, event: Event<T>) {
if let Event::WindowEvent {
event: WindowEvent::RedrawRequested,
..
} = event
{
if let Event::WindowEvent { event: WindowEvent::RedrawRequested, .. } = event {
self.call_event_handler(event);
// As a rule, to ensure that `pump_events` can't block an external event loop
// for too long, we always guarantee that `pump_events` will return control to
// the external loop asap after a `RedrawRequested` event is dispatched.
self.interrupt_msg_dispatch.set(true);
} else if self.should_buffer() {
// If the runner is already borrowed, we're in the middle of an event loop invocation. Add
// the event to a buffer to be processed later.
self.event_buffer
.borrow_mut()
.push_back(BufferedEvent::from_event(event))
// If the runner is already borrowed, we're in the middle of an event loop invocation.
// Add the event to a buffer to be processed later.
self.event_buffer.borrow_mut().push_back(BufferedEvent::from_event(event))
} else {
self.call_event_handler(event);
self.dispatch_buffered_events();
@ -240,8 +228,10 @@ impl<T> EventLoopRunner<T> {
fn call_event_handler(&self, event: Event<T>) {
self.catch_unwind(|| {
let mut event_handler = self.event_handler.take()
.expect("either event handler is re-entrant (likely), or no event handler is registered (very unlikely)");
let mut event_handler = self.event_handler.take().expect(
"either event handler is re-entrant (likely), or no event handler is registered \
(very unlikely)",
);
event_handler(event);
@ -290,10 +280,7 @@ impl<T> EventLoopRunner<T> {
fn move_state_to(&self, new_runner_state: RunnerState) {
use RunnerState::{Destroyed, HandlingMainEvents, Idle, Uninitialized};
match (
self.runner_state.replace(new_runner_state),
new_runner_state,
) {
match (self.runner_state.replace(new_runner_state), new_runner_state) {
(Uninitialized, Uninitialized)
| (Idle, Idle)
| (HandlingMainEvents, HandlingMainEvents)
@ -302,38 +289,38 @@ impl<T> EventLoopRunner<T> {
// State transitions that initialize the event loop.
(Uninitialized, HandlingMainEvents) => {
self.call_new_events(true);
}
},
(Uninitialized, Idle) => {
self.call_new_events(true);
self.call_event_handler(Event::AboutToWait);
self.last_events_cleared.set(Instant::now());
}
},
(Uninitialized, Destroyed) => {
self.call_new_events(true);
self.call_event_handler(Event::AboutToWait);
self.last_events_cleared.set(Instant::now());
self.call_event_handler(Event::LoopExiting);
}
},
(_, Uninitialized) => panic!("cannot move state to Uninitialized"),
// State transitions that start the event handling process.
(Idle, HandlingMainEvents) => {
self.call_new_events(false);
}
},
(Idle, Destroyed) => {
self.call_event_handler(Event::LoopExiting);
}
},
(HandlingMainEvents, Idle) => {
// This is always the last event we dispatch before waiting for new events
self.call_event_handler(Event::AboutToWait);
self.last_events_cleared.set(Instant::now());
}
},
(HandlingMainEvents, Destroyed) => {
self.call_event_handler(Event::AboutToWait);
self.last_events_cleared.set(Instant::now());
self.call_event_handler(Event::LoopExiting);
}
},
(Destroyed, _) => panic!("cannot move state from Destroyed"),
}
@ -341,7 +328,7 @@ impl<T> EventLoopRunner<T> {
fn call_new_events(&self, init: bool) {
let start_cause = match (init, self.control_flow(), self.exit.get()) {
(true, _, _) => StartCause::Init,
(true, ..) => StartCause::Init,
(false, ControlFlow::Poll, None) => StartCause::Poll,
(false, _, Some(_)) | (false, ControlFlow::Wait, None) => StartCause::WaitCancelled {
requested_resume: None,
@ -359,7 +346,7 @@ impl<T> EventLoopRunner<T> {
start: self.last_events_cleared.get(),
}
}
}
},
};
self.call_event_handler(Event::NewEvents(start_cause));
// NB: For consistency all platforms must emit a 'resumed' event even though Windows
@ -375,21 +362,12 @@ impl<T> BufferedEvent<T> {
pub fn from_event(event: Event<T>) -> BufferedEvent<T> {
match event {
Event::WindowEvent {
event:
WindowEvent::ScaleFactorChanged {
scale_factor,
inner_size_writer,
},
event: WindowEvent::ScaleFactorChanged { scale_factor, inner_size_writer },
window_id,
} => BufferedEvent::ScaleFactorChanged(
window_id,
scale_factor,
*inner_size_writer
.new_inner_size
.upgrade()
.unwrap()
.lock()
.unwrap(),
*inner_size_writer.new_inner_size.upgrade().unwrap().lock().unwrap(),
),
event => BufferedEvent::Event(event),
}
@ -422,7 +400,7 @@ impl<T> BufferedEvent<T> {
window_flags.set_size((window_id.0).0, inner_size);
}
}
},
}
}
}

View file

@ -1,23 +1,22 @@
use std::{ffi::c_void, fmt, io, mem, path::Path, sync::Arc};
use std::ffi::c_void;
use std::path::Path;
use std::sync::Arc;
use std::{fmt, io, mem};
use cursor_icon::CursorIcon;
use windows_sys::{
core::PCWSTR,
Win32::{
Foundation::HWND,
Graphics::Gdi::{
CreateBitmap, CreateCompatibleBitmap, DeleteObject, GetDC, ReleaseDC, SetBitmapBits,
},
UI::WindowsAndMessaging::{
CreateIcon, CreateIconIndirect, DestroyCursor, DestroyIcon, LoadImageW, SendMessageW,
HCURSOR, HICON, ICONINFO, ICON_BIG, ICON_SMALL, IMAGE_ICON, LR_DEFAULTSIZE,
LR_LOADFROMFILE, WM_SETICON,
},
},
use windows_sys::core::PCWSTR;
use windows_sys::Win32::Foundation::HWND;
use windows_sys::Win32::Graphics::Gdi::{
CreateBitmap, CreateCompatibleBitmap, DeleteObject, GetDC, ReleaseDC, SetBitmapBits,
};
use windows_sys::Win32::UI::WindowsAndMessaging::{
CreateIcon, CreateIconIndirect, DestroyCursor, DestroyIcon, LoadImageW, SendMessageW, HCURSOR,
HICON, ICONINFO, ICON_BIG, ICON_SMALL, IMAGE_ICON, LR_DEFAULTSIZE, LR_LOADFROMFILE, WM_SETICON,
};
use crate::cursor::CursorImage;
use crate::dpi::PhysicalSize;
use crate::icon::*;
use crate::{cursor::CursorImage, dpi::PhysicalSize};
use super::util;
@ -142,9 +141,7 @@ impl WinIcon {
}
fn from_handle(handle: HICON) -> Self {
Self {
inner: Arc::new(RaiiIcon { handle }),
}
Self { inner: Arc::new(RaiiIcon { handle }) }
}
}

View file

@ -1,27 +1,19 @@
use std::{
ffi::{c_void, OsString},
os::windows::prelude::OsStringExt,
ptr::null_mut,
};
use std::ffi::{c_void, OsString};
use std::os::windows::prelude::OsStringExt;
use std::ptr::null_mut;
use windows_sys::Win32::{
Foundation::{POINT, RECT},
Globalization::HIMC,
UI::{
Input::Ime::{
ImmAssociateContextEx, ImmGetCompositionStringW, ImmGetContext, ImmReleaseContext,
ImmSetCandidateWindow, ImmSetCompositionWindow, ATTR_TARGET_CONVERTED,
ATTR_TARGET_NOTCONVERTED, CANDIDATEFORM, CFS_EXCLUDE, CFS_POINT, COMPOSITIONFORM,
GCS_COMPATTR, GCS_COMPSTR, GCS_CURSORPOS, GCS_RESULTSTR, IACE_CHILDREN, IACE_DEFAULT,
},
WindowsAndMessaging::{GetSystemMetrics, SM_IMMENABLED},
},
use windows_sys::Win32::Foundation::{POINT, RECT};
use windows_sys::Win32::Globalization::HIMC;
use windows_sys::Win32::UI::Input::Ime::{
ImmAssociateContextEx, ImmGetCompositionStringW, ImmGetContext, ImmReleaseContext,
ImmSetCandidateWindow, ImmSetCompositionWindow, ATTR_TARGET_CONVERTED,
ATTR_TARGET_NOTCONVERTED, CANDIDATEFORM, CFS_EXCLUDE, CFS_POINT, COMPOSITIONFORM, GCS_COMPATTR,
GCS_COMPSTR, GCS_CURSORPOS, GCS_RESULTSTR, IACE_CHILDREN, IACE_DEFAULT,
};
use windows_sys::Win32::UI::WindowsAndMessaging::{GetSystemMetrics, SM_IMMENABLED};
use crate::{
dpi::{Position, Size},
platform::windows::HWND,
};
use crate::dpi::{Position, Size};
use crate::platform::windows::HWND;
pub struct ImeContext {
hwnd: HWND,
@ -60,7 +52,8 @@ impl ImeContext {
if first.is_some() && last.is_none() {
last = Some(text.len());
} else if first.is_none() {
// IME haven't split words and select any clause yet, so trying to retrieve normal cursor.
// IME haven't split words and select any clause yet, so trying to retrieve normal
// cursor.
let cursor = unsafe { self.get_composition_cursor(&text) };
first = cursor;
last = cursor;
@ -120,12 +113,7 @@ impl ImeContext {
let (x, y) = spot.to_physical::<i32>(scale_factor).into();
let (width, height): (i32, i32) = size.to_physical::<i32>(scale_factor).into();
let rc_area = RECT {
left: x,
top: y,
right: x + width,
bottom: y + height,
};
let rc_area = RECT { left: x, top: y, right: x + width, bottom: y + height };
let candidate_form = CANDIDATEFORM {
dwIndex: 0,
dwStyle: CFS_EXCLUDE,

View file

@ -1,50 +1,39 @@
use std::{
char,
ffi::OsString,
mem::MaybeUninit,
os::windows::ffi::OsStringExt,
sync::{
atomic::{AtomicU32, Ordering::Relaxed},
Mutex, MutexGuard,
},
};
use std::char;
use std::ffi::OsString;
use std::mem::MaybeUninit;
use std::os::windows::ffi::OsStringExt;
use std::sync::atomic::AtomicU32;
use std::sync::atomic::Ordering::Relaxed;
use std::sync::{Mutex, MutexGuard};
use windows_sys::Win32::{
Foundation::{HWND, LPARAM, WPARAM},
System::SystemServices::LANG_KOREAN,
UI::{
Input::KeyboardAndMouse::{
GetAsyncKeyState, GetKeyState, GetKeyboardLayout, GetKeyboardState, MapVirtualKeyExW,
MAPVK_VK_TO_VSC_EX, MAPVK_VSC_TO_VK_EX, VIRTUAL_KEY, VK_ABNT_C2, VK_ADD, VK_CAPITAL,
VK_CLEAR, VK_CONTROL, VK_DECIMAL, VK_DELETE, VK_DIVIDE, VK_DOWN, VK_END, VK_F4,
VK_HOME, VK_INSERT, VK_LCONTROL, VK_LEFT, VK_LMENU, VK_LSHIFT, VK_LWIN, VK_MENU,
VK_MULTIPLY, VK_NEXT, VK_NUMLOCK, VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3,
VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, VK_NUMPAD8, VK_NUMPAD9, VK_PRIOR,
VK_RCONTROL, VK_RETURN, VK_RIGHT, VK_RMENU, VK_RSHIFT, VK_RWIN, VK_SCROLL, VK_SHIFT,
VK_SUBTRACT, VK_UP,
},
TextServices::HKL,
WindowsAndMessaging::{
PeekMessageW, MSG, PM_NOREMOVE, WM_CHAR, WM_DEADCHAR, WM_KEYDOWN, WM_KEYFIRST,
WM_KEYLAST, WM_KEYUP, WM_KILLFOCUS, WM_SETFOCUS, WM_SYSCHAR, WM_SYSDEADCHAR,
WM_SYSKEYDOWN, WM_SYSKEYUP,
},
},
use windows_sys::Win32::Foundation::{HWND, LPARAM, WPARAM};
use windows_sys::Win32::System::SystemServices::LANG_KOREAN;
use windows_sys::Win32::UI::Input::KeyboardAndMouse::{
GetAsyncKeyState, GetKeyState, GetKeyboardLayout, GetKeyboardState, MapVirtualKeyExW,
MAPVK_VK_TO_VSC_EX, MAPVK_VSC_TO_VK_EX, VIRTUAL_KEY, VK_ABNT_C2, VK_ADD, VK_CAPITAL, VK_CLEAR,
VK_CONTROL, VK_DECIMAL, VK_DELETE, VK_DIVIDE, VK_DOWN, VK_END, VK_F4, VK_HOME, VK_INSERT,
VK_LCONTROL, VK_LEFT, VK_LMENU, VK_LSHIFT, VK_LWIN, VK_MENU, VK_MULTIPLY, VK_NEXT, VK_NUMLOCK,
VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
VK_NUMPAD8, VK_NUMPAD9, VK_PRIOR, VK_RCONTROL, VK_RETURN, VK_RIGHT, VK_RMENU, VK_RSHIFT,
VK_RWIN, VK_SCROLL, VK_SHIFT, VK_SUBTRACT, VK_UP,
};
use windows_sys::Win32::UI::TextServices::HKL;
use windows_sys::Win32::UI::WindowsAndMessaging::{
PeekMessageW, MSG, PM_NOREMOVE, WM_CHAR, WM_DEADCHAR, WM_KEYDOWN, WM_KEYFIRST, WM_KEYLAST,
WM_KEYUP, WM_KILLFOCUS, WM_SETFOCUS, WM_SYSCHAR, WM_SYSDEADCHAR, WM_SYSKEYDOWN, WM_SYSKEYUP,
};
use smol_str::SmolStr;
use tracing::{trace, warn};
use unicode_segmentation::UnicodeSegmentation;
use crate::{
event::{ElementState, KeyEvent},
keyboard::{Key, KeyCode, KeyLocation, NamedKey, NativeKey, NativeKeyCode, PhysicalKey},
platform_impl::platform::{
event_loop::ProcResult,
keyboard_layout::{Layout, LayoutCache, WindowsModifiers, LAYOUT_CACHE},
loword, primarylangid, KeyEventExtra,
},
use crate::event::{ElementState, KeyEvent};
use crate::keyboard::{Key, KeyCode, KeyLocation, NamedKey, NativeKey, NativeKeyCode, PhysicalKey};
use crate::platform_impl::platform::event_loop::ProcResult;
use crate::platform_impl::platform::keyboard_layout::{
Layout, LayoutCache, WindowsModifiers, LAYOUT_CACHE,
};
use crate::platform_impl::platform::{loword, primarylangid, KeyEventExtra};
pub type ExScancode = u16;
@ -60,16 +49,16 @@ pub struct MessageAsKeyEvent {
/// window message. Therefore, this type keeps track of certain information from previous events so
/// that a `KeyEvent` can be constructed when the last event related to a keypress is received.
///
/// `PeekMessage` is sometimes used to determine whether the next window message still belongs to the
/// current keypress. If it doesn't and the current state represents a key event waiting to be
/// `PeekMessage` is sometimes used to determine whether the next window message still belongs to
/// the current keypress. If it doesn't and the current state represents a key event waiting to be
/// dispatched, then said event is considered complete and is dispatched.
///
/// The sequence of window messages for a key press event is the following:
/// - Exactly one WM_KEYDOWN / WM_SYSKEYDOWN
/// - Zero or one WM_DEADCHAR / WM_SYSDEADCHAR
/// - Zero or more WM_CHAR / WM_SYSCHAR. These messages each come with a UTF-16 code unit which when
/// put together in the sequence they arrived in, forms the text which is the result of pressing the
/// key.
/// put together in the sequence they arrived in, forms the text which is the result of pressing
/// the key.
///
/// Key release messages are a bit different due to the fact that they don't contribute to
/// text input. The "sequence" only consists of one WM_KEYUP / WM_SYSKEYUP event.
@ -79,10 +68,7 @@ pub struct KeyEventBuilder {
}
impl Default for KeyEventBuilder {
fn default() -> Self {
KeyEventBuilder {
event_info: Mutex::new(None),
pending: Default::default(),
}
KeyEventBuilder { event_info: Mutex::new(None), pending: Default::default() }
}
}
impl KeyEventBuilder {
@ -110,13 +96,13 @@ impl KeyEventBuilder {
let kbd_state = get_async_kbd_state();
let key_events = Self::synthesize_kbd_state(ElementState::Pressed, &kbd_state);
MatchResult::MessagesToDispatch(self.pending.complete_multi(key_events))
}
},
WM_KILLFOCUS => {
// sythesize keyup events
let kbd_state = get_kbd_state();
let key_events = Self::synthesize_kbd_state(ElementState::Released, &kbd_state);
MatchResult::MessagesToDispatch(self.pending.complete_multi(key_events))
}
},
WM_KEYDOWN | WM_SYSKEYDOWN => {
if msg_kind == WM_SYSKEYDOWN && wparam as VIRTUAL_KEY == VK_F4 {
// Don't dispatch Alt+F4 to the application.
@ -162,39 +148,36 @@ impl KeyEventBuilder {
let ev = event_info.finalize();
return MatchResult::MessagesToDispatch(self.pending.complete_pending(
pending_token,
MessageAsKeyEvent {
event: ev,
is_synthetic: false,
},
MessageAsKeyEvent { event: ev, is_synthetic: false },
));
}
MatchResult::TokenToRemove(pending_token)
}
},
WM_DEADCHAR | WM_SYSDEADCHAR => {
let pending_token = self.pending.add_pending();
*result = ProcResult::Value(0);
// At this point, we know that there isn't going to be any more events related to
// this key press
// At this point, we know that there isn't going to be any more events related
// to this key press
let event_info = self.event_info.lock().unwrap().take().unwrap();
let ev = event_info.finalize();
MatchResult::MessagesToDispatch(self.pending.complete_pending(
pending_token,
MessageAsKeyEvent {
event: ev,
is_synthetic: false,
},
MessageAsKeyEvent { event: ev, is_synthetic: false },
))
}
},
WM_CHAR | WM_SYSCHAR => {
let mut event_info = self.event_info.lock().unwrap();
if event_info.is_none() {
trace!("Received a CHAR message but no `event_info` was available. The message is probably IME, returning.");
trace!(
"Received a CHAR message but no `event_info` was available. The \
message is probably IME, returning."
);
return MatchResult::Nothing;
}
let pending_token = self.pending.add_pending();
*result = ProcResult::Value(0);
let is_high_surrogate = (0xD800..=0xDBFF).contains(&wparam);
let is_low_surrogate = (0xDC00..=0xDFFF).contains(&wparam);
let is_high_surrogate = (0xd800..=0xdbff).contains(&wparam);
let is_low_surrogate = (0xdc00..=0xdfff).contains(&wparam);
let is_utf16 = is_high_surrogate || is_low_surrogate;
@ -210,7 +193,7 @@ impl KeyEventBuilder {
None => {
warn!("The event_info was None when it was expected to be some");
return MatchResult::TokenToRemove(pending_token);
}
},
};
let start_offset = utf16parts.len();
let new_size = utf16parts.len() + 2;
@ -221,16 +204,17 @@ impl KeyEventBuilder {
utf16parts.resize(new_size, 0);
}
}
// It's important that we unlock the mutex, and create the pending event token before
// calling `next_msg`
// It's important that we unlock the mutex, and create the pending event token
// before calling `next_msg`
std::mem::drop(event_info);
let next_msg = next_kbd_msg(hwnd);
let more_char_coming = next_msg
.map(|m| matches!(m.message, WM_CHAR | WM_SYSCHAR))
.unwrap_or(false);
if more_char_coming {
// No need to produce an event just yet, because there are still more characters that
// need to appended to this keyobard event
// No need to produce an event just yet, because there are still more
// characters that need to appended to this keyobard
// event
MatchResult::TokenToRemove(pending_token)
} else {
let mut event_info = self.event_info.lock().unwrap();
@ -239,7 +223,7 @@ impl KeyEventBuilder {
None => {
warn!("The event_info was None when it was expected to be some");
return MatchResult::TokenToRemove(pending_token);
}
},
};
let mut layouts = LAYOUT_CACHE.lock().unwrap();
// It's okay to call `ToUnicode` here, because at this point the dead key
@ -271,13 +255,10 @@ impl KeyEventBuilder {
let ev = event_info.finalize();
MatchResult::MessagesToDispatch(self.pending.complete_pending(
pending_token,
MessageAsKeyEvent {
event: ev,
is_synthetic: false,
},
MessageAsKeyEvent { event: ev, is_synthetic: false },
))
}
}
},
WM_KEYUP | WM_SYSKEYUP => {
let pending_token = self.pending.add_pending();
*result = ProcResult::Value(0);
@ -289,9 +270,11 @@ impl KeyEventBuilder {
ElementState::Released,
&mut layouts,
);
// We MUST release the layout lock before calling `next_kbd_msg`, otherwise it may deadlock
// We MUST release the layout lock before calling `next_kbd_msg`, otherwise it
// may deadlock
drop(layouts);
// It's important that we create the pending token before reading the next message.
// It's important that we create the pending token before reading the next
// message.
let next_msg = next_kbd_msg(hwnd);
let mut valid_event_info = Some(event_info);
if let Some(next_msg) = next_msg {
@ -309,14 +292,11 @@ impl KeyEventBuilder {
let event = event_info.finalize();
return MatchResult::MessagesToDispatch(self.pending.complete_pending(
pending_token,
MessageAsKeyEvent {
event,
is_synthetic: false,
},
MessageAsKeyEvent { event, is_synthetic: false },
));
}
MatchResult::TokenToRemove(pending_token)
}
},
_ => MatchResult::Nothing,
}
};
@ -352,12 +332,11 @@ impl KeyEventBuilder {
let num_lock_on = kbd_state[VK_NUMLOCK as usize] & 1 != 0;
// We are synthesizing the press event for caps-lock first for the following reasons:
// 1. If caps-lock is *not* held down but *is* active, then we have to
// synthesize all printable keys, respecting the caps-lock state.
// 2. If caps-lock is held down, we could choose to sythesize its
// keypress after every other key, in which case all other keys *must*
// be sythesized as if the caps-lock state was be the opposite
// of what it currently is.
// 1. If caps-lock is *not* held down but *is* active, then we have to synthesize all
// printable keys, respecting the caps-lock state.
// 2. If caps-lock is held down, we could choose to sythesize its keypress after every other
// key, in which case all other keys *must* be sythesized as if the caps-lock state was
// be the opposite of what it currently is.
// --
// For the sake of simplicity we are choosing to always sythesize
// caps-lock first, and always use the current caps-lock state
@ -399,14 +378,8 @@ impl KeyEventBuilder {
}
};
let do_modifier = |key_events: &mut Vec<_>, layouts: &mut _| {
const CLEAR_MODIFIER_VKS: [VIRTUAL_KEY; 6] = [
VK_LCONTROL,
VK_LSHIFT,
VK_LMENU,
VK_RCONTROL,
VK_RSHIFT,
VK_RMENU,
];
const CLEAR_MODIFIER_VKS: [VIRTUAL_KEY; 6] =
[VK_LCONTROL, VK_LSHIFT, VK_LMENU, VK_RCONTROL, VK_RSHIFT, VK_RMENU];
for vk in CLEAR_MODIFIER_VKS.iter() {
if is_key_pressed!(*vk) {
let event = Self::create_synthetic(
@ -431,11 +404,11 @@ impl KeyEventBuilder {
ElementState::Pressed => {
do_non_modifier(&mut key_events, &mut layouts);
do_modifier(&mut key_events, &mut layouts);
}
},
ElementState::Released => {
do_modifier(&mut key_events, &mut layouts);
do_non_modifier(&mut key_events, &mut layouts);
}
},
}
key_events
@ -455,11 +428,8 @@ impl KeyEventBuilder {
}
let scancode = scancode as ExScancode;
let physical_key = scancode_to_physicalkey(scancode as u32);
let mods = if caps_lock_on {
WindowsModifiers::CAPS_LOCK
} else {
WindowsModifiers::empty()
};
let mods =
if caps_lock_on { WindowsModifiers::CAPS_LOCK } else { WindowsModifiers::empty() };
let layout = layouts.layouts.get(&(locale_id as u64)).unwrap();
let logical_key = layout.get_key(mods, num_lock_on, vk, &physical_key);
let key_without_modifiers =
@ -484,10 +454,7 @@ impl KeyEventBuilder {
let mut event = event_info.finalize();
event.logical_key = logical_key;
event.platform_specific.text_with_all_modifiers = text;
Some(MessageAsKeyEvent {
event,
is_synthetic: true,
})
Some(MessageAsKeyEvent { event, is_synthetic: true })
}
}
@ -600,7 +567,7 @@ impl PartialKeyEventInfo {
} else {
Key::Unidentified(NativeKey::Unidentified)
}
}
},
key => key,
}
};
@ -637,10 +604,10 @@ impl PartialKeyEventInfo {
text = Some(SmolStr::new(string));
}
}
}
},
PartialText::Text(s) => {
text = s.map(SmolStr::new);
}
},
}
let logical_key = match self.logical_key {
@ -651,7 +618,7 @@ impl PartialKeyEventInfo {
} else {
Key::Character(s.clone())
}
}
},
None => Key::Unidentified(NativeKey::Windows(self.vkey)),
},
PartialLogicalKey::This(v) => v,
@ -677,7 +644,8 @@ struct KeyLParam {
pub scancode: u8,
pub extended: bool,
/// This is `previous_state XOR transition_state`. See the lParam for WM_KEYDOWN and WM_KEYUP for further details.
/// This is `previous_state XOR transition_state`. See the lParam for WM_KEYDOWN and WM_KEYUP
/// for further details.
pub is_repeat: bool,
}
@ -685,7 +653,7 @@ fn destructure_key_lparam(lparam: LPARAM) -> KeyLParam {
let previous_state = (lparam >> 30) & 0x01;
let transition_state = (lparam >> 31) & 0x01;
KeyLParam {
scancode: ((lparam >> 16) & 0xFF) as u8,
scancode: ((lparam >> 16) & 0xff) as u8,
extended: ((lparam >> 24) & 0x01) != 0,
is_repeat: (previous_state ^ transition_state) != 0,
}
@ -693,7 +661,7 @@ fn destructure_key_lparam(lparam: LPARAM) -> KeyLParam {
#[inline]
fn new_ex_scancode(scancode: u8, extended: bool) -> ExScancode {
(scancode as u16) | (if extended { 0xE000 } else { 0 })
(scancode as u16) | (if extended { 0xe000 } else { 0 })
}
#[inline]
@ -742,13 +710,11 @@ fn get_async_kbd_state() -> [u8; 256] {
/// the next event is a right Alt (AltGr) event. If this is the case, the current event must be the
/// fake Ctrl event.
fn is_current_fake(curr_info: &PartialKeyEventInfo, next_msg: MSG, layout: &Layout) -> bool {
let curr_is_ctrl = matches!(
curr_info.logical_key,
PartialLogicalKey::This(Key::Named(NamedKey::Control))
);
let curr_is_ctrl =
matches!(curr_info.logical_key, PartialLogicalKey::This(Key::Named(NamedKey::Control)));
if layout.has_alt_graph {
let next_code = ex_scancode_from_lparam(next_msg.lParam);
let next_is_altgr = next_code == 0xE038; // 0xE038 is right alt
let next_is_altgr = next_code == 0xe038; // 0xE038 is right alt
if curr_is_ctrl && next_is_altgr {
return true;
}
@ -792,10 +758,7 @@ impl<T> PendingEventQueue<T> {
pub fn add_pending(&self) -> PendingMessageToken {
let token = self.next_token();
let mut pending = self.pending.lock().unwrap();
pending.push(IdentifiedPendingMessage {
token,
msg: PendingMessage::Incomplete,
});
pending.push(IdentifiedPendingMessage { token, msg: PendingMessage::Incomplete });
token
}
@ -862,15 +825,20 @@ impl<T> PendingEventQueue<T> {
}
fn drain_pending(pending: &mut Vec<IdentifiedPendingMessage<T>>) -> Vec<T> {
pending.drain(..).map(|m| {
match m.msg {
pending
.drain(..)
.map(|m| match m.msg {
PendingMessage::Complete(msg) => msg,
PendingMessage::Incomplete => {
panic!("Found an incomplete pending message when collecting messages. This indicates a bug in winit.")
}
}
}).collect()
panic!(
"Found an incomplete pending message when collecting messages. This \
indicates a bug in winit."
)
},
})
.collect()
}
fn next_token(&self) -> PendingMessageToken {
// It's okay for the u32 to overflow here. Yes, that could mean
// that two different messages have the same token,
@ -884,10 +852,7 @@ impl<T> PendingEventQueue<T> {
}
impl<T> Default for PendingEventQueue<T> {
fn default() -> Self {
PendingEventQueue {
pending: Mutex::new(Vec::new()),
next_id: AtomicU32::new(0),
}
PendingEventQueue { pending: Mutex::new(Vec::new()), next_id: AtomicU32::new(0) }
}
}
@ -902,13 +867,8 @@ impl<T> Default for PendingEventQueue<T> {
pub fn next_kbd_msg(hwnd: HWND) -> Option<MSG> {
unsafe {
let mut next_msg = MaybeUninit::uninit();
let peek_retval = PeekMessageW(
next_msg.as_mut_ptr(),
hwnd,
WM_KEYFIRST,
WM_KEYLAST,
PM_NOREMOVE,
);
let peek_retval =
PeekMessageW(next_msg.as_mut_ptr(), hwnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE);
(peek_retval != 0).then(|| next_msg.assume_init())
}
}
@ -916,7 +876,7 @@ pub fn next_kbd_msg(hwnd: HWND) -> Option<MSG> {
fn get_location(scancode: ExScancode, hkl: HKL) -> KeyLocation {
const ABNT_C2: VIRTUAL_KEY = VK_ABNT_C2 as VIRTUAL_KEY;
let extension = 0xE000;
let extension = 0xe000;
let extended = (scancode & extension) == extension;
let vkey = unsafe { MapVirtualKeyExW(scancode as u32, MAPVK_VSC_TO_VK_EX, hkl) as VIRTUAL_KEY };
@ -934,7 +894,7 @@ fn get_location(scancode: ExScancode, hkl: HKL) -> KeyLocation {
} else {
KeyLocation::Numpad
}
}
},
VK_NUMPAD0 | VK_NUMPAD1 | VK_NUMPAD2 | VK_NUMPAD3 | VK_NUMPAD4 | VK_NUMPAD5
| VK_NUMPAD6 | VK_NUMPAD7 | VK_NUMPAD8 | VK_NUMPAD9 | VK_DECIMAL | VK_DIVIDE
| VK_MULTIPLY | VK_SUBTRACT | VK_ADD | ABNT_C2 => KeyLocation::Numpad,
@ -957,17 +917,17 @@ pub(crate) fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32>
NativeKeyCode::Windows(scancode) => Some(scancode as u32),
_ => None,
};
}
},
};
match code {
KeyCode::Backquote => Some(0x0029),
KeyCode::Backslash => Some(0x002B),
KeyCode::Backspace => Some(0x000E),
KeyCode::BracketLeft => Some(0x001A),
KeyCode::BracketRight => Some(0x001B),
KeyCode::Backslash => Some(0x002b),
KeyCode::Backspace => Some(0x000e),
KeyCode::BracketLeft => Some(0x001a),
KeyCode::BracketRight => Some(0x001b),
KeyCode::Comma => Some(0x0033),
KeyCode::Digit0 => Some(0x000B),
KeyCode::Digit0 => Some(0x000b),
KeyCode::Digit1 => Some(0x0002),
KeyCode::Digit2 => Some(0x0003),
KeyCode::Digit3 => Some(0x0004),
@ -976,14 +936,14 @@ pub(crate) fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32>
KeyCode::Digit6 => Some(0x0007),
KeyCode::Digit7 => Some(0x0008),
KeyCode::Digit8 => Some(0x0009),
KeyCode::Digit9 => Some(0x000A),
KeyCode::Equal => Some(0x000D),
KeyCode::Digit9 => Some(0x000a),
KeyCode::Equal => Some(0x000d),
KeyCode::IntlBackslash => Some(0x0056),
KeyCode::IntlRo => Some(0x0073),
KeyCode::IntlYen => Some(0x007D),
KeyCode::KeyA => Some(0x001E),
KeyCode::IntlYen => Some(0x007d),
KeyCode::KeyA => Some(0x001e),
KeyCode::KeyB => Some(0x0030),
KeyCode::KeyC => Some(0x002E),
KeyCode::KeyC => Some(0x002e),
KeyCode::KeyD => Some(0x0020),
KeyCode::KeyE => Some(0x0012),
KeyCode::KeyF => Some(0x0021),
@ -999,84 +959,84 @@ pub(crate) fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32>
KeyCode::KeyP => Some(0x0019),
KeyCode::KeyQ => Some(0x0010),
KeyCode::KeyR => Some(0x0013),
KeyCode::KeyS => Some(0x001F),
KeyCode::KeyS => Some(0x001f),
KeyCode::KeyT => Some(0x0014),
KeyCode::KeyU => Some(0x0016),
KeyCode::KeyV => Some(0x002F),
KeyCode::KeyV => Some(0x002f),
KeyCode::KeyW => Some(0x0011),
KeyCode::KeyX => Some(0x002D),
KeyCode::KeyX => Some(0x002d),
KeyCode::KeyY => Some(0x0015),
KeyCode::KeyZ => Some(0x002C),
KeyCode::Minus => Some(0x000C),
KeyCode::KeyZ => Some(0x002c),
KeyCode::Minus => Some(0x000c),
KeyCode::Period => Some(0x0034),
KeyCode::Quote => Some(0x0028),
KeyCode::Semicolon => Some(0x0027),
KeyCode::Slash => Some(0x0035),
KeyCode::AltLeft => Some(0x0038),
KeyCode::AltRight => Some(0xE038),
KeyCode::CapsLock => Some(0x003A),
KeyCode::ContextMenu => Some(0xE05D),
KeyCode::ControlLeft => Some(0x001D),
KeyCode::ControlRight => Some(0xE01D),
KeyCode::Enter => Some(0x001C),
KeyCode::SuperLeft => Some(0xE05B),
KeyCode::SuperRight => Some(0xE05C),
KeyCode::ShiftLeft => Some(0x002A),
KeyCode::AltRight => Some(0xe038),
KeyCode::CapsLock => Some(0x003a),
KeyCode::ContextMenu => Some(0xe05d),
KeyCode::ControlLeft => Some(0x001d),
KeyCode::ControlRight => Some(0xe01d),
KeyCode::Enter => Some(0x001c),
KeyCode::SuperLeft => Some(0xe05b),
KeyCode::SuperRight => Some(0xe05c),
KeyCode::ShiftLeft => Some(0x002a),
KeyCode::ShiftRight => Some(0x0036),
KeyCode::Space => Some(0x0039),
KeyCode::Tab => Some(0x000F),
KeyCode::Tab => Some(0x000f),
KeyCode::Convert => Some(0x0079),
KeyCode::Lang1 => {
if is_korean {
Some(0xE0F2)
Some(0xe0f2)
} else {
Some(0x0072)
}
}
},
KeyCode::Lang2 => {
if is_korean {
Some(0xE0F1)
Some(0xe0f1)
} else {
Some(0x0071)
}
}
},
KeyCode::KanaMode => Some(0x0070),
KeyCode::NonConvert => Some(0x007B),
KeyCode::Delete => Some(0xE053),
KeyCode::End => Some(0xE04F),
KeyCode::Home => Some(0xE047),
KeyCode::Insert => Some(0xE052),
KeyCode::PageDown => Some(0xE051),
KeyCode::PageUp => Some(0xE049),
KeyCode::ArrowDown => Some(0xE050),
KeyCode::ArrowLeft => Some(0xE04B),
KeyCode::ArrowRight => Some(0xE04D),
KeyCode::ArrowUp => Some(0xE048),
KeyCode::NumLock => Some(0xE045),
KeyCode::NonConvert => Some(0x007b),
KeyCode::Delete => Some(0xe053),
KeyCode::End => Some(0xe04f),
KeyCode::Home => Some(0xe047),
KeyCode::Insert => Some(0xe052),
KeyCode::PageDown => Some(0xe051),
KeyCode::PageUp => Some(0xe049),
KeyCode::ArrowDown => Some(0xe050),
KeyCode::ArrowLeft => Some(0xe04b),
KeyCode::ArrowRight => Some(0xe04d),
KeyCode::ArrowUp => Some(0xe048),
KeyCode::NumLock => Some(0xe045),
KeyCode::Numpad0 => Some(0x0052),
KeyCode::Numpad1 => Some(0x004F),
KeyCode::Numpad1 => Some(0x004f),
KeyCode::Numpad2 => Some(0x0050),
KeyCode::Numpad3 => Some(0x0051),
KeyCode::Numpad4 => Some(0x004B),
KeyCode::Numpad5 => Some(0x004C),
KeyCode::Numpad6 => Some(0x004D),
KeyCode::Numpad4 => Some(0x004b),
KeyCode::Numpad5 => Some(0x004c),
KeyCode::Numpad6 => Some(0x004d),
KeyCode::Numpad7 => Some(0x0047),
KeyCode::Numpad8 => Some(0x0048),
KeyCode::Numpad9 => Some(0x0049),
KeyCode::NumpadAdd => Some(0x004E),
KeyCode::NumpadComma => Some(0x007E),
KeyCode::NumpadAdd => Some(0x004e),
KeyCode::NumpadComma => Some(0x007e),
KeyCode::NumpadDecimal => Some(0x0053),
KeyCode::NumpadDivide => Some(0xE035),
KeyCode::NumpadEnter => Some(0xE01C),
KeyCode::NumpadDivide => Some(0xe035),
KeyCode::NumpadEnter => Some(0xe01c),
KeyCode::NumpadEqual => Some(0x0059),
KeyCode::NumpadMultiply => Some(0x0037),
KeyCode::NumpadSubtract => Some(0x004A),
KeyCode::NumpadSubtract => Some(0x004a),
KeyCode::Escape => Some(0x0001),
KeyCode::F1 => Some(0x003B),
KeyCode::F2 => Some(0x003C),
KeyCode::F3 => Some(0x003D),
KeyCode::F4 => Some(0x003E),
KeyCode::F5 => Some(0x003F),
KeyCode::F1 => Some(0x003b),
KeyCode::F2 => Some(0x003c),
KeyCode::F3 => Some(0x003d),
KeyCode::F4 => Some(0x003e),
KeyCode::F5 => Some(0x003f),
KeyCode::F6 => Some(0x0040),
KeyCode::F7 => Some(0x0041),
KeyCode::F8 => Some(0x0042),
@ -1090,36 +1050,36 @@ pub(crate) fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32>
KeyCode::F16 => Some(0x0067),
KeyCode::F17 => Some(0x0068),
KeyCode::F18 => Some(0x0069),
KeyCode::F19 => Some(0x006A),
KeyCode::F20 => Some(0x006B),
KeyCode::F21 => Some(0x006C),
KeyCode::F22 => Some(0x006D),
KeyCode::F23 => Some(0x006E),
KeyCode::F19 => Some(0x006a),
KeyCode::F20 => Some(0x006b),
KeyCode::F21 => Some(0x006c),
KeyCode::F22 => Some(0x006d),
KeyCode::F23 => Some(0x006e),
KeyCode::F24 => Some(0x0076),
KeyCode::PrintScreen => Some(0xE037),
//KeyCode::PrintScreen => Some(0x0054), // Alt + PrintScreen
KeyCode::PrintScreen => Some(0xe037),
// KeyCode::PrintScreen => Some(0x0054), // Alt + PrintScreen
KeyCode::ScrollLock => Some(0x0046),
KeyCode::Pause => Some(0x0045),
//KeyCode::Pause => Some(0xE046), // Ctrl + Pause
KeyCode::BrowserBack => Some(0xE06A),
KeyCode::BrowserFavorites => Some(0xE066),
KeyCode::BrowserForward => Some(0xE069),
KeyCode::BrowserHome => Some(0xE032),
KeyCode::BrowserRefresh => Some(0xE067),
KeyCode::BrowserSearch => Some(0xE065),
KeyCode::BrowserStop => Some(0xE068),
KeyCode::LaunchApp1 => Some(0xE06B),
KeyCode::LaunchApp2 => Some(0xE021),
KeyCode::LaunchMail => Some(0xE06C),
KeyCode::MediaPlayPause => Some(0xE022),
KeyCode::MediaSelect => Some(0xE06D),
KeyCode::MediaStop => Some(0xE024),
KeyCode::MediaTrackNext => Some(0xE019),
KeyCode::MediaTrackPrevious => Some(0xE010),
KeyCode::Power => Some(0xE05E),
KeyCode::AudioVolumeDown => Some(0xE02E),
KeyCode::AudioVolumeMute => Some(0xE020),
KeyCode::AudioVolumeUp => Some(0xE030),
// KeyCode::Pause => Some(0xE046), // Ctrl + Pause
KeyCode::BrowserBack => Some(0xe06a),
KeyCode::BrowserFavorites => Some(0xe066),
KeyCode::BrowserForward => Some(0xe069),
KeyCode::BrowserHome => Some(0xe032),
KeyCode::BrowserRefresh => Some(0xe067),
KeyCode::BrowserSearch => Some(0xe065),
KeyCode::BrowserStop => Some(0xe068),
KeyCode::LaunchApp1 => Some(0xe06b),
KeyCode::LaunchApp2 => Some(0xe021),
KeyCode::LaunchMail => Some(0xe06c),
KeyCode::MediaPlayPause => Some(0xe022),
KeyCode::MediaSelect => Some(0xe06d),
KeyCode::MediaStop => Some(0xe024),
KeyCode::MediaTrackNext => Some(0xe019),
KeyCode::MediaTrackPrevious => Some(0xe010),
KeyCode::Power => Some(0xe05e),
KeyCode::AudioVolumeDown => Some(0xe02e),
KeyCode::AudioVolumeMute => Some(0xe020),
KeyCode::AudioVolumeUp => Some(0xe030),
_ => None,
}
}
@ -1131,12 +1091,12 @@ pub(crate) fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
PhysicalKey::Code(match scancode {
0x0029 => KeyCode::Backquote,
0x002B => KeyCode::Backslash,
0x000E => KeyCode::Backspace,
0x001A => KeyCode::BracketLeft,
0x001B => KeyCode::BracketRight,
0x002b => KeyCode::Backslash,
0x000e => KeyCode::Backspace,
0x001a => KeyCode::BracketLeft,
0x001b => KeyCode::BracketRight,
0x0033 => KeyCode::Comma,
0x000B => KeyCode::Digit0,
0x000b => KeyCode::Digit0,
0x0002 => KeyCode::Digit1,
0x0003 => KeyCode::Digit2,
0x0004 => KeyCode::Digit3,
@ -1145,14 +1105,14 @@ pub(crate) fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
0x0007 => KeyCode::Digit6,
0x0008 => KeyCode::Digit7,
0x0009 => KeyCode::Digit8,
0x000A => KeyCode::Digit9,
0x000D => KeyCode::Equal,
0x000a => KeyCode::Digit9,
0x000d => KeyCode::Equal,
0x0056 => KeyCode::IntlBackslash,
0x0073 => KeyCode::IntlRo,
0x007D => KeyCode::IntlYen,
0x001E => KeyCode::KeyA,
0x007d => KeyCode::IntlYen,
0x001e => KeyCode::KeyA,
0x0030 => KeyCode::KeyB,
0x002E => KeyCode::KeyC,
0x002e => KeyCode::KeyC,
0x0020 => KeyCode::KeyD,
0x0012 => KeyCode::KeyE,
0x0021 => KeyCode::KeyF,
@ -1168,74 +1128,74 @@ pub(crate) fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
0x0019 => KeyCode::KeyP,
0x0010 => KeyCode::KeyQ,
0x0013 => KeyCode::KeyR,
0x001F => KeyCode::KeyS,
0x001f => KeyCode::KeyS,
0x0014 => KeyCode::KeyT,
0x0016 => KeyCode::KeyU,
0x002F => KeyCode::KeyV,
0x002f => KeyCode::KeyV,
0x0011 => KeyCode::KeyW,
0x002D => KeyCode::KeyX,
0x002d => KeyCode::KeyX,
0x0015 => KeyCode::KeyY,
0x002C => KeyCode::KeyZ,
0x000C => KeyCode::Minus,
0x002c => KeyCode::KeyZ,
0x000c => KeyCode::Minus,
0x0034 => KeyCode::Period,
0x0028 => KeyCode::Quote,
0x0027 => KeyCode::Semicolon,
0x0035 => KeyCode::Slash,
0x0038 => KeyCode::AltLeft,
0xE038 => KeyCode::AltRight,
0x003A => KeyCode::CapsLock,
0xE05D => KeyCode::ContextMenu,
0x001D => KeyCode::ControlLeft,
0xE01D => KeyCode::ControlRight,
0x001C => KeyCode::Enter,
0xE05B => KeyCode::SuperLeft,
0xE05C => KeyCode::SuperRight,
0x002A => KeyCode::ShiftLeft,
0xe038 => KeyCode::AltRight,
0x003a => KeyCode::CapsLock,
0xe05d => KeyCode::ContextMenu,
0x001d => KeyCode::ControlLeft,
0xe01d => KeyCode::ControlRight,
0x001c => KeyCode::Enter,
0xe05b => KeyCode::SuperLeft,
0xe05c => KeyCode::SuperRight,
0x002a => KeyCode::ShiftLeft,
0x0036 => KeyCode::ShiftRight,
0x0039 => KeyCode::Space,
0x000F => KeyCode::Tab,
0x000f => KeyCode::Tab,
0x0079 => KeyCode::Convert,
0x0072 => KeyCode::Lang1, // for non-Korean layout
0xE0F2 => KeyCode::Lang1, // for Korean layout
0xe0f2 => KeyCode::Lang1, // for Korean layout
0x0071 => KeyCode::Lang2, // for non-Korean layout
0xE0F1 => KeyCode::Lang2, // for Korean layout
0xe0f1 => KeyCode::Lang2, // for Korean layout
0x0070 => KeyCode::KanaMode,
0x007B => KeyCode::NonConvert,
0xE053 => KeyCode::Delete,
0xE04F => KeyCode::End,
0xE047 => KeyCode::Home,
0xE052 => KeyCode::Insert,
0xE051 => KeyCode::PageDown,
0xE049 => KeyCode::PageUp,
0xE050 => KeyCode::ArrowDown,
0xE04B => KeyCode::ArrowLeft,
0xE04D => KeyCode::ArrowRight,
0xE048 => KeyCode::ArrowUp,
0xE045 => KeyCode::NumLock,
0x007b => KeyCode::NonConvert,
0xe053 => KeyCode::Delete,
0xe04f => KeyCode::End,
0xe047 => KeyCode::Home,
0xe052 => KeyCode::Insert,
0xe051 => KeyCode::PageDown,
0xe049 => KeyCode::PageUp,
0xe050 => KeyCode::ArrowDown,
0xe04b => KeyCode::ArrowLeft,
0xe04d => KeyCode::ArrowRight,
0xe048 => KeyCode::ArrowUp,
0xe045 => KeyCode::NumLock,
0x0052 => KeyCode::Numpad0,
0x004F => KeyCode::Numpad1,
0x004f => KeyCode::Numpad1,
0x0050 => KeyCode::Numpad2,
0x0051 => KeyCode::Numpad3,
0x004B => KeyCode::Numpad4,
0x004C => KeyCode::Numpad5,
0x004D => KeyCode::Numpad6,
0x004b => KeyCode::Numpad4,
0x004c => KeyCode::Numpad5,
0x004d => KeyCode::Numpad6,
0x0047 => KeyCode::Numpad7,
0x0048 => KeyCode::Numpad8,
0x0049 => KeyCode::Numpad9,
0x004E => KeyCode::NumpadAdd,
0x007E => KeyCode::NumpadComma,
0x004e => KeyCode::NumpadAdd,
0x007e => KeyCode::NumpadComma,
0x0053 => KeyCode::NumpadDecimal,
0xE035 => KeyCode::NumpadDivide,
0xE01C => KeyCode::NumpadEnter,
0xe035 => KeyCode::NumpadDivide,
0xe01c => KeyCode::NumpadEnter,
0x0059 => KeyCode::NumpadEqual,
0x0037 => KeyCode::NumpadMultiply,
0x004A => KeyCode::NumpadSubtract,
0x004a => KeyCode::NumpadSubtract,
0x0001 => KeyCode::Escape,
0x003B => KeyCode::F1,
0x003C => KeyCode::F2,
0x003D => KeyCode::F3,
0x003E => KeyCode::F4,
0x003F => KeyCode::F5,
0x003b => KeyCode::F1,
0x003c => KeyCode::F2,
0x003d => KeyCode::F3,
0x003e => KeyCode::F4,
0x003f => KeyCode::F5,
0x0040 => KeyCode::F6,
0x0041 => KeyCode::F7,
0x0042 => KeyCode::F8,
@ -1249,36 +1209,36 @@ pub(crate) fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
0x0067 => KeyCode::F16,
0x0068 => KeyCode::F17,
0x0069 => KeyCode::F18,
0x006A => KeyCode::F19,
0x006B => KeyCode::F20,
0x006C => KeyCode::F21,
0x006D => KeyCode::F22,
0x006E => KeyCode::F23,
0x006a => KeyCode::F19,
0x006b => KeyCode::F20,
0x006c => KeyCode::F21,
0x006d => KeyCode::F22,
0x006e => KeyCode::F23,
0x0076 => KeyCode::F24,
0xE037 => KeyCode::PrintScreen,
0xe037 => KeyCode::PrintScreen,
0x0054 => KeyCode::PrintScreen, // Alt + PrintScreen
0x0046 => KeyCode::ScrollLock,
0x0045 => KeyCode::Pause,
0xE046 => KeyCode::Pause, // Ctrl + Pause
0xE06A => KeyCode::BrowserBack,
0xE066 => KeyCode::BrowserFavorites,
0xE069 => KeyCode::BrowserForward,
0xE032 => KeyCode::BrowserHome,
0xE067 => KeyCode::BrowserRefresh,
0xE065 => KeyCode::BrowserSearch,
0xE068 => KeyCode::BrowserStop,
0xE06B => KeyCode::LaunchApp1,
0xE021 => KeyCode::LaunchApp2,
0xE06C => KeyCode::LaunchMail,
0xE022 => KeyCode::MediaPlayPause,
0xE06D => KeyCode::MediaSelect,
0xE024 => KeyCode::MediaStop,
0xE019 => KeyCode::MediaTrackNext,
0xE010 => KeyCode::MediaTrackPrevious,
0xE05E => KeyCode::Power,
0xE02E => KeyCode::AudioVolumeDown,
0xE020 => KeyCode::AudioVolumeMute,
0xE030 => KeyCode::AudioVolumeUp,
0xe046 => KeyCode::Pause, // Ctrl + Pause
0xe06a => KeyCode::BrowserBack,
0xe066 => KeyCode::BrowserFavorites,
0xe069 => KeyCode::BrowserForward,
0xe032 => KeyCode::BrowserHome,
0xe067 => KeyCode::BrowserRefresh,
0xe065 => KeyCode::BrowserSearch,
0xe068 => KeyCode::BrowserStop,
0xe06b => KeyCode::LaunchApp1,
0xe021 => KeyCode::LaunchApp2,
0xe06c => KeyCode::LaunchMail,
0xe022 => KeyCode::MediaPlayPause,
0xe06d => KeyCode::MediaSelect,
0xe024 => KeyCode::MediaStop,
0xe019 => KeyCode::MediaTrackNext,
0xe010 => KeyCode::MediaTrackPrevious,
0xe05e => KeyCode::Power,
0xe02e => KeyCode::AudioVolumeDown,
0xe020 => KeyCode::AudioVolumeMute,
0xe030 => KeyCode::AudioVolumeUp,
_ => return PhysicalKey::Unidentified(NativeKeyCode::Windows(scancode as u16)),
})
}

View file

@ -1,60 +1,49 @@
use std::{
collections::{hash_map::Entry, HashMap, HashSet},
ffi::OsString,
os::windows::ffi::OsStringExt,
sync::Mutex,
};
use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::sync::Mutex;
use crate::utils::Lazy;
use smol_str::SmolStr;
use windows_sys::Win32::{
System::SystemServices::{LANG_JAPANESE, LANG_KOREAN},
UI::{
Input::KeyboardAndMouse::{
GetKeyState, GetKeyboardLayout, MapVirtualKeyExW, ToUnicodeEx, MAPVK_VK_TO_VSC_EX,
VIRTUAL_KEY, VK_ACCEPT, VK_ADD, VK_APPS, VK_ATTN, VK_BACK, VK_BROWSER_BACK,
VK_BROWSER_FAVORITES, VK_BROWSER_FORWARD, VK_BROWSER_HOME, VK_BROWSER_REFRESH,
VK_BROWSER_SEARCH, VK_BROWSER_STOP, VK_CANCEL, VK_CAPITAL, VK_CLEAR, VK_CONTROL,
VK_CONVERT, VK_CRSEL, VK_DECIMAL, VK_DELETE, VK_DIVIDE, VK_DOWN, VK_END, VK_EREOF,
VK_ESCAPE, VK_EXECUTE, VK_EXSEL, VK_F1, VK_F10, VK_F11, VK_F12, VK_F13, VK_F14, VK_F15,
VK_F16, VK_F17, VK_F18, VK_F19, VK_F2, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, VK_F3,
VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_FINAL, VK_GAMEPAD_A, VK_GAMEPAD_B,
VK_GAMEPAD_DPAD_DOWN, VK_GAMEPAD_DPAD_LEFT, VK_GAMEPAD_DPAD_RIGHT, VK_GAMEPAD_DPAD_UP,
VK_GAMEPAD_LEFT_SHOULDER, VK_GAMEPAD_LEFT_THUMBSTICK_BUTTON,
VK_GAMEPAD_LEFT_THUMBSTICK_DOWN, VK_GAMEPAD_LEFT_THUMBSTICK_LEFT,
VK_GAMEPAD_LEFT_THUMBSTICK_RIGHT, VK_GAMEPAD_LEFT_THUMBSTICK_UP,
VK_GAMEPAD_LEFT_TRIGGER, VK_GAMEPAD_MENU, VK_GAMEPAD_RIGHT_SHOULDER,
VK_GAMEPAD_RIGHT_THUMBSTICK_BUTTON, VK_GAMEPAD_RIGHT_THUMBSTICK_DOWN,
VK_GAMEPAD_RIGHT_THUMBSTICK_LEFT, VK_GAMEPAD_RIGHT_THUMBSTICK_RIGHT,
VK_GAMEPAD_RIGHT_THUMBSTICK_UP, VK_GAMEPAD_RIGHT_TRIGGER, VK_GAMEPAD_VIEW,
VK_GAMEPAD_X, VK_GAMEPAD_Y, VK_HANGUL, VK_HANJA, VK_HELP, VK_HOME, VK_ICO_00,
VK_ICO_CLEAR, VK_ICO_HELP, VK_INSERT, VK_JUNJA, VK_KANA, VK_KANJI, VK_LAUNCH_APP1,
VK_LAUNCH_APP2, VK_LAUNCH_MAIL, VK_LAUNCH_MEDIA_SELECT, VK_LBUTTON, VK_LCONTROL,
VK_LEFT, VK_LMENU, VK_LSHIFT, VK_LWIN, VK_MBUTTON, VK_MEDIA_NEXT_TRACK,
VK_MEDIA_PLAY_PAUSE, VK_MEDIA_PREV_TRACK, VK_MEDIA_STOP, VK_MENU, VK_MODECHANGE,
VK_MULTIPLY, VK_NAVIGATION_ACCEPT, VK_NAVIGATION_CANCEL, VK_NAVIGATION_DOWN,
VK_NAVIGATION_LEFT, VK_NAVIGATION_MENU, VK_NAVIGATION_RIGHT, VK_NAVIGATION_UP,
VK_NAVIGATION_VIEW, VK_NEXT, VK_NONAME, VK_NONCONVERT, VK_NUMLOCK, VK_NUMPAD0,
VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
VK_NUMPAD8, VK_NUMPAD9, VK_OEM_1, VK_OEM_102, VK_OEM_2, VK_OEM_3, VK_OEM_4, VK_OEM_5,
VK_OEM_6, VK_OEM_7, VK_OEM_8, VK_OEM_ATTN, VK_OEM_AUTO, VK_OEM_AX, VK_OEM_BACKTAB,
VK_OEM_CLEAR, VK_OEM_COMMA, VK_OEM_COPY, VK_OEM_CUSEL, VK_OEM_ENLW, VK_OEM_FINISH,
VK_OEM_FJ_LOYA, VK_OEM_FJ_MASSHOU, VK_OEM_FJ_ROYA, VK_OEM_FJ_TOUROKU, VK_OEM_JUMP,
VK_OEM_MINUS, VK_OEM_NEC_EQUAL, VK_OEM_PA1, VK_OEM_PA2, VK_OEM_PA3, VK_OEM_PERIOD,
VK_OEM_PLUS, VK_OEM_RESET, VK_OEM_WSCTRL, VK_PA1, VK_PACKET, VK_PAUSE, VK_PLAY,
VK_PRINT, VK_PRIOR, VK_PROCESSKEY, VK_RBUTTON, VK_RCONTROL, VK_RETURN, VK_RIGHT,
VK_RMENU, VK_RSHIFT, VK_RWIN, VK_SCROLL, VK_SELECT, VK_SEPARATOR, VK_SHIFT, VK_SLEEP,
VK_SNAPSHOT, VK_SPACE, VK_SUBTRACT, VK_TAB, VK_UP, VK_VOLUME_DOWN, VK_VOLUME_MUTE,
VK_VOLUME_UP, VK_XBUTTON1, VK_XBUTTON2, VK_ZOOM,
},
TextServices::HKL,
},
use windows_sys::Win32::System::SystemServices::{LANG_JAPANESE, LANG_KOREAN};
use windows_sys::Win32::UI::Input::KeyboardAndMouse::{
GetKeyState, GetKeyboardLayout, MapVirtualKeyExW, ToUnicodeEx, MAPVK_VK_TO_VSC_EX, VIRTUAL_KEY,
VK_ACCEPT, VK_ADD, VK_APPS, VK_ATTN, VK_BACK, VK_BROWSER_BACK, VK_BROWSER_FAVORITES,
VK_BROWSER_FORWARD, VK_BROWSER_HOME, VK_BROWSER_REFRESH, VK_BROWSER_SEARCH, VK_BROWSER_STOP,
VK_CANCEL, VK_CAPITAL, VK_CLEAR, VK_CONTROL, VK_CONVERT, VK_CRSEL, VK_DECIMAL, VK_DELETE,
VK_DIVIDE, VK_DOWN, VK_END, VK_EREOF, VK_ESCAPE, VK_EXECUTE, VK_EXSEL, VK_F1, VK_F10, VK_F11,
VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, VK_F19, VK_F2, VK_F20, VK_F21, VK_F22,
VK_F23, VK_F24, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_FINAL, VK_GAMEPAD_A,
VK_GAMEPAD_B, VK_GAMEPAD_DPAD_DOWN, VK_GAMEPAD_DPAD_LEFT, VK_GAMEPAD_DPAD_RIGHT,
VK_GAMEPAD_DPAD_UP, VK_GAMEPAD_LEFT_SHOULDER, VK_GAMEPAD_LEFT_THUMBSTICK_BUTTON,
VK_GAMEPAD_LEFT_THUMBSTICK_DOWN, VK_GAMEPAD_LEFT_THUMBSTICK_LEFT,
VK_GAMEPAD_LEFT_THUMBSTICK_RIGHT, VK_GAMEPAD_LEFT_THUMBSTICK_UP, VK_GAMEPAD_LEFT_TRIGGER,
VK_GAMEPAD_MENU, VK_GAMEPAD_RIGHT_SHOULDER, VK_GAMEPAD_RIGHT_THUMBSTICK_BUTTON,
VK_GAMEPAD_RIGHT_THUMBSTICK_DOWN, VK_GAMEPAD_RIGHT_THUMBSTICK_LEFT,
VK_GAMEPAD_RIGHT_THUMBSTICK_RIGHT, VK_GAMEPAD_RIGHT_THUMBSTICK_UP, VK_GAMEPAD_RIGHT_TRIGGER,
VK_GAMEPAD_VIEW, VK_GAMEPAD_X, VK_GAMEPAD_Y, VK_HANGUL, VK_HANJA, VK_HELP, VK_HOME, VK_ICO_00,
VK_ICO_CLEAR, VK_ICO_HELP, VK_INSERT, VK_JUNJA, VK_KANA, VK_KANJI, VK_LAUNCH_APP1,
VK_LAUNCH_APP2, VK_LAUNCH_MAIL, VK_LAUNCH_MEDIA_SELECT, VK_LBUTTON, VK_LCONTROL, VK_LEFT,
VK_LMENU, VK_LSHIFT, VK_LWIN, VK_MBUTTON, VK_MEDIA_NEXT_TRACK, VK_MEDIA_PLAY_PAUSE,
VK_MEDIA_PREV_TRACK, VK_MEDIA_STOP, VK_MENU, VK_MODECHANGE, VK_MULTIPLY, VK_NAVIGATION_ACCEPT,
VK_NAVIGATION_CANCEL, VK_NAVIGATION_DOWN, VK_NAVIGATION_LEFT, VK_NAVIGATION_MENU,
VK_NAVIGATION_RIGHT, VK_NAVIGATION_UP, VK_NAVIGATION_VIEW, VK_NEXT, VK_NONAME, VK_NONCONVERT,
VK_NUMLOCK, VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6,
VK_NUMPAD7, VK_NUMPAD8, VK_NUMPAD9, VK_OEM_1, VK_OEM_102, VK_OEM_2, VK_OEM_3, VK_OEM_4,
VK_OEM_5, VK_OEM_6, VK_OEM_7, VK_OEM_8, VK_OEM_ATTN, VK_OEM_AUTO, VK_OEM_AX, VK_OEM_BACKTAB,
VK_OEM_CLEAR, VK_OEM_COMMA, VK_OEM_COPY, VK_OEM_CUSEL, VK_OEM_ENLW, VK_OEM_FINISH,
VK_OEM_FJ_LOYA, VK_OEM_FJ_MASSHOU, VK_OEM_FJ_ROYA, VK_OEM_FJ_TOUROKU, VK_OEM_JUMP,
VK_OEM_MINUS, VK_OEM_NEC_EQUAL, VK_OEM_PA1, VK_OEM_PA2, VK_OEM_PA3, VK_OEM_PERIOD, VK_OEM_PLUS,
VK_OEM_RESET, VK_OEM_WSCTRL, VK_PA1, VK_PACKET, VK_PAUSE, VK_PLAY, VK_PRINT, VK_PRIOR,
VK_PROCESSKEY, VK_RBUTTON, VK_RCONTROL, VK_RETURN, VK_RIGHT, VK_RMENU, VK_RSHIFT, VK_RWIN,
VK_SCROLL, VK_SELECT, VK_SEPARATOR, VK_SHIFT, VK_SLEEP, VK_SNAPSHOT, VK_SPACE, VK_SUBTRACT,
VK_TAB, VK_UP, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, VK_XBUTTON1, VK_XBUTTON2, VK_ZOOM,
};
use windows_sys::Win32::UI::TextServices::HKL;
use crate::{
keyboard::{Key, KeyCode, ModifiersState, NamedKey, NativeKey, PhysicalKey},
platform_impl::{loword, primarylangid, scancode_to_physicalkey},
};
use crate::keyboard::{Key, KeyCode, ModifiersState, NamedKey, NativeKey, PhysicalKey};
use crate::platform_impl::{loword, primarylangid, scancode_to_physicalkey};
pub(crate) static LAYOUT_CACHE: Lazy<Mutex<LayoutCache>> =
Lazy::new(|| Mutex::new(LayoutCache::default()));
@ -279,7 +268,7 @@ impl LayoutCache {
Entry::Vacant(entry) => {
let layout = Self::prepare_layout(locale_id);
(locale_id, entry.insert(layout))
}
},
}
}
@ -288,18 +277,9 @@ impl LayoutCache {
let filter_out_altgr = layout.has_alt_graph && key_pressed(VK_RMENU);
let mut mods = ModifiersState::empty();
mods.set(ModifiersState::SHIFT, key_pressed(VK_SHIFT));
mods.set(
ModifiersState::CONTROL,
key_pressed(VK_CONTROL) && !filter_out_altgr,
);
mods.set(
ModifiersState::ALT,
key_pressed(VK_MENU) && !filter_out_altgr,
);
mods.set(
ModifiersState::SUPER,
key_pressed(VK_LWIN) || key_pressed(VK_RWIN),
);
mods.set(ModifiersState::CONTROL, key_pressed(VK_CONTROL) && !filter_out_altgr);
mods.set(ModifiersState::ALT, key_pressed(VK_MENU) && !filter_out_altgr);
mods.set(ModifiersState::SUPER, key_pressed(VK_LWIN) || key_pressed(VK_RWIN));
mods
}
@ -361,9 +341,7 @@ impl LayoutCache {
let scancode = unsafe { MapVirtualKeyExW(vk, MAPVK_VK_TO_VSC_EX, locale_id as HKL) };
let unicode = Self::to_unicode_string(&key_state, vk, scancode, locale_id);
if let ToUnicodeResult::Str(s) = unicode {
layout
.numlock_on_keys
.insert(vk as VIRTUAL_KEY, Key::Character(SmolStr::new(s)));
layout.numlock_on_keys.insert(vk as VIRTUAL_KEY, Key::Character(SmolStr::new(s)));
}
}
@ -403,16 +381,17 @@ impl LayoutCache {
_ => {
keys_for_this_mod.insert(key_code, preliminary_key);
continue;
}
},
}
let unicode = Self::to_unicode_string(&key_state, vk, scancode, locale_id);
let key = match unicode {
ToUnicodeResult::Str(str) => Key::Character(SmolStr::new(str)),
ToUnicodeResult::Dead(dead_char) => {
//println!("{:?} - {:?} produced dead {:?}", key_code, mod_state, dead_char);
// println!("{:?} - {:?} produced dead {:?}", key_code, mod_state,
// dead_char);
Key::Dead(dead_char)
}
},
ToUnicodeResult::None => {
let has_alt = mod_state.contains(WindowsModifiers::ALT);
let has_ctrl = mod_state.contains(WindowsModifiers::CONTROL);
@ -424,7 +403,7 @@ impl LayoutCache {
// Just use the unidentified key, we got earlier
preliminary_key
}
}
},
};
// Check for alt graph.
@ -750,10 +729,11 @@ fn keycode_to_vkey(keycode: KeyCode, hkl: u64) -> VIRTUAL_KEY {
/// a `Key`, with only the information passed in as arguments, are converted.
///
/// In other words: this function does not need to "prepare" the current layout in order to do
/// the conversion, but as such it cannot convert certain keys, like language-specific character keys.
/// the conversion, but as such it cannot convert certain keys, like language-specific character
/// keys.
///
/// The result includes all non-character keys defined within `Key` plus characters from numpad keys.
/// For example, backspace and tab are included.
/// The result includes all non-character keys defined within `Key` plus characters from numpad
/// keys. For example, backspace and tab are included.
fn vkey_to_non_char_key(
vkey: VIRTUAL_KEY,
native_code: NativeKey,
@ -787,7 +767,7 @@ fn vkey_to_non_char_key(
VK_PAUSE => Key::Named(NamedKey::Pause),
VK_CAPITAL => Key::Named(NamedKey::CapsLock),
//VK_HANGEUL => Key::Named(NamedKey::HangulMode), // Deprecated in favour of VK_HANGUL
// VK_HANGEUL => Key::Named(NamedKey::HangulMode), // Deprecated in favour of VK_HANGUL
// VK_HANGUL and VK_KANA are defined as the same constant, therefore
// we use appropriate conditions to differentiate between them
@ -881,7 +861,7 @@ fn vkey_to_non_char_key(
VK_NUMLOCK => Key::Named(NamedKey::NumLock),
VK_SCROLL => Key::Named(NamedKey::ScrollLock),
VK_OEM_NEC_EQUAL => Key::Unidentified(native_code),
//VK_OEM_FJ_JISHO => Key::Unidentified(native_code), // Conflicts with `VK_OEM_NEC_EQUAL`
// VK_OEM_FJ_JISHO => Key::Unidentified(native_code), // Conflicts with `VK_OEM_NEC_EQUAL`
VK_OEM_FJ_MASSHOU => Key::Unidentified(native_code),
VK_OEM_FJ_TOUROKU => Key::Unidentified(native_code),
VK_OEM_FJ_LOYA => Key::Unidentified(native_code),
@ -897,7 +877,7 @@ fn vkey_to_non_char_key(
} else {
Key::Named(NamedKey::Alt)
}
}
},
VK_BROWSER_BACK => Key::Named(NamedKey::BrowserBack),
VK_BROWSER_FORWARD => Key::Named(NamedKey::BrowserForward),
VK_BROWSER_REFRESH => Key::Named(NamedKey::BrowserRefresh),
@ -987,7 +967,7 @@ fn vkey_to_non_char_key(
// Also see: https://github.com/pyfisch/keyboard-types/issues/9
Key::Unidentified(native_code)
}
}
},
VK_OEM_COPY => Key::Named(NamedKey::Copy),
VK_OEM_AUTO => Key::Named(NamedKey::Hankaku),
VK_OEM_ENLW => Key::Named(NamedKey::Zenkaku),

View file

@ -1,21 +1,17 @@
#![cfg(windows_platform)]
use smol_str::SmolStr;
use windows_sys::Win32::{
Foundation::{HANDLE, HWND},
UI::WindowsAndMessaging::{HMENU, WINDOW_LONG_PTR_INDEX},
};
use windows_sys::Win32::Foundation::{HANDLE, HWND};
use windows_sys::Win32::UI::WindowsAndMessaging::{HMENU, WINDOW_LONG_PTR_INDEX};
pub(crate) use self::{
event_loop::{
ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle,
PlatformSpecificEventLoopAttributes,
},
icon::{SelectedCursor, WinIcon},
keyboard::{physicalkey_to_scancode, scancode_to_physicalkey},
monitor::{MonitorHandle, VideoModeHandle},
window::Window,
pub(crate) use self::event_loop::{
ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle,
PlatformSpecificEventLoopAttributes,
};
pub(crate) use self::icon::{SelectedCursor, WinIcon};
pub(crate) use self::keyboard::{physicalkey_to_scancode, scancode_to_physicalkey};
pub(crate) use self::monitor::{MonitorHandle, VideoModeHandle};
pub(crate) use self::window::Window;
pub(crate) use self::icon::WinCursor as PlatformCustomCursor;
pub use self::icon::WinIcon as PlatformIcon;
@ -149,17 +145,17 @@ const fn get_y_lparam(x: u32) -> i16 {
#[inline(always)]
pub(crate) const fn primarylangid(lgid: u16) -> u16 {
lgid & 0x3FF
lgid & 0x3ff
}
#[inline(always)]
pub(crate) const fn loword(x: u32) -> u16 {
(x & 0xFFFF) as u16
(x & 0xffff) as u16
}
#[inline(always)]
const fn hiword(x: u32) -> u16 {
((x >> 16) & 0xFFFF) as u16
((x >> 16) & 0xffff) as u16
}
#[inline(always)]

View file

@ -1,29 +1,21 @@
use std::{
collections::{BTreeSet, VecDeque},
hash::Hash,
io, mem, ptr,
};
use std::collections::{BTreeSet, VecDeque};
use std::hash::Hash;
use std::{io, mem, ptr};
use windows_sys::Win32::{
Foundation::{BOOL, HWND, LPARAM, POINT, RECT},
Graphics::Gdi::{
EnumDisplayMonitors, EnumDisplaySettingsExW, GetMonitorInfoW, MonitorFromPoint,
MonitorFromWindow, DEVMODEW, DM_BITSPERPEL, DM_DISPLAYFREQUENCY, DM_PELSHEIGHT,
DM_PELSWIDTH, ENUM_CURRENT_SETTINGS, HDC, HMONITOR, MONITORINFO, MONITORINFOEXW,
MONITOR_DEFAULTTONEAREST, MONITOR_DEFAULTTOPRIMARY,
},
use windows_sys::Win32::Foundation::{BOOL, HWND, LPARAM, POINT, RECT};
use windows_sys::Win32::Graphics::Gdi::{
EnumDisplayMonitors, EnumDisplaySettingsExW, GetMonitorInfoW, MonitorFromPoint,
MonitorFromWindow, DEVMODEW, DM_BITSPERPEL, DM_DISPLAYFREQUENCY, DM_PELSHEIGHT, DM_PELSWIDTH,
ENUM_CURRENT_SETTINGS, HDC, HMONITOR, MONITORINFO, MONITORINFOEXW, MONITOR_DEFAULTTONEAREST,
MONITOR_DEFAULTTOPRIMARY,
};
use super::util::decode_wide;
use crate::{
dpi::{PhysicalPosition, PhysicalSize},
monitor::VideoModeHandle as RootVideoModeHandle,
platform_impl::platform::{
dpi::{dpi_to_scale_factor, get_monitor_dpi},
util::has_flag,
window::Window,
},
};
use crate::dpi::{PhysicalPosition, PhysicalSize};
use crate::monitor::VideoModeHandle as RootVideoModeHandle;
use crate::platform_impl::platform::dpi::{dpi_to_scale_factor, get_monitor_dpi};
use crate::platform_impl::platform::util::has_flag;
use crate::platform_impl::platform::window::Window;
#[derive(Clone)]
pub struct VideoModeHandle {
@ -144,10 +136,7 @@ pub(crate) fn get_monitor_info(hmonitor: HMONITOR) -> Result<MONITORINFOEXW, io:
let mut monitor_info: MONITORINFOEXW = unsafe { mem::zeroed() };
monitor_info.monitorInfo.cbSize = mem::size_of::<MONITORINFOEXW>() as u32;
let status = unsafe {
GetMonitorInfoW(
hmonitor,
&mut monitor_info as *mut MONITORINFOEXW as *mut MONITORINFO,
)
GetMonitorInfoW(hmonitor, &mut monitor_info as *mut MONITORINFOEXW as *mut MONITORINFO)
};
if status == false.into() {
Err(io::Error::last_os_error())
@ -164,11 +153,7 @@ impl MonitorHandle {
#[inline]
pub fn name(&self) -> Option<String> {
let monitor_info = get_monitor_info(self.0).unwrap();
Some(
decode_wide(&monitor_info.szDevice)
.to_string_lossy()
.to_string(),
)
Some(decode_wide(&monitor_info.szDevice).to_string_lossy().to_string())
}
#[inline]
@ -212,10 +197,7 @@ impl MonitorHandle {
get_monitor_info(self.0)
.map(|info| {
let rc_monitor = info.monitorInfo.rcMonitor;
PhysicalPosition {
x: rc_monitor.left,
y: rc_monitor.top,
}
PhysicalPosition { x: rc_monitor.left, y: rc_monitor.top }
})
.unwrap_or(PhysicalPosition { x: 0, y: 0 })
}
@ -238,7 +220,7 @@ impl MonitorHandle {
Err(error) => {
tracing::warn!("Error from get_monitor_info: {error}");
return modes.into_iter().map(mod_map);
}
},
};
let device_name = monitor_info.szDevice.as_ptr();

View file

@ -1,39 +1,31 @@
use std::{
mem::{self, size_of},
ptr,
};
use std::mem::{self, size_of};
use std::ptr;
use windows_sys::Win32::{
Devices::HumanInterfaceDevice::{
HID_USAGE_GENERIC_KEYBOARD, HID_USAGE_GENERIC_MOUSE, HID_USAGE_PAGE_GENERIC,
},
Foundation::{HANDLE, HWND},
UI::{
Input::{
GetRawInputData, GetRawInputDeviceInfoW, GetRawInputDeviceList,
KeyboardAndMouse::{MapVirtualKeyW, MAPVK_VK_TO_VSC_EX, VK_NUMLOCK, VK_SHIFT},
RegisterRawInputDevices, HRAWINPUT, RAWINPUT, RAWINPUTDEVICE, RAWINPUTDEVICELIST,
RAWINPUTHEADER, RAWKEYBOARD, RIDEV_DEVNOTIFY, RIDEV_INPUTSINK, RIDEV_REMOVE,
RIDI_DEVICEINFO, RIDI_DEVICENAME, RID_DEVICE_INFO, RID_DEVICE_INFO_HID,
RID_DEVICE_INFO_KEYBOARD, RID_DEVICE_INFO_MOUSE, RID_INPUT, RIM_TYPEHID,
RIM_TYPEKEYBOARD, RIM_TYPEMOUSE,
},
WindowsAndMessaging::{
RI_KEY_E0, RI_KEY_E1, RI_MOUSE_BUTTON_1_DOWN, RI_MOUSE_BUTTON_1_UP,
RI_MOUSE_BUTTON_2_DOWN, RI_MOUSE_BUTTON_2_UP, RI_MOUSE_BUTTON_3_DOWN,
RI_MOUSE_BUTTON_3_UP, RI_MOUSE_BUTTON_4_DOWN, RI_MOUSE_BUTTON_4_UP,
RI_MOUSE_BUTTON_5_DOWN, RI_MOUSE_BUTTON_5_UP,
},
},
use windows_sys::Win32::Devices::HumanInterfaceDevice::{
HID_USAGE_GENERIC_KEYBOARD, HID_USAGE_GENERIC_MOUSE, HID_USAGE_PAGE_GENERIC,
};
use windows_sys::Win32::Foundation::{HANDLE, HWND};
use windows_sys::Win32::UI::Input::KeyboardAndMouse::{
MapVirtualKeyW, MAPVK_VK_TO_VSC_EX, VK_NUMLOCK, VK_SHIFT,
};
use windows_sys::Win32::UI::Input::{
GetRawInputData, GetRawInputDeviceInfoW, GetRawInputDeviceList, RegisterRawInputDevices,
HRAWINPUT, RAWINPUT, RAWINPUTDEVICE, RAWINPUTDEVICELIST, RAWINPUTHEADER, RAWKEYBOARD,
RIDEV_DEVNOTIFY, RIDEV_INPUTSINK, RIDEV_REMOVE, RIDI_DEVICEINFO, RIDI_DEVICENAME,
RID_DEVICE_INFO, RID_DEVICE_INFO_HID, RID_DEVICE_INFO_KEYBOARD, RID_DEVICE_INFO_MOUSE,
RID_INPUT, RIM_TYPEHID, RIM_TYPEKEYBOARD, RIM_TYPEMOUSE,
};
use windows_sys::Win32::UI::WindowsAndMessaging::{
RI_KEY_E0, RI_KEY_E1, RI_MOUSE_BUTTON_1_DOWN, RI_MOUSE_BUTTON_1_UP, RI_MOUSE_BUTTON_2_DOWN,
RI_MOUSE_BUTTON_2_UP, RI_MOUSE_BUTTON_3_DOWN, RI_MOUSE_BUTTON_3_UP, RI_MOUSE_BUTTON_4_DOWN,
RI_MOUSE_BUTTON_4_UP, RI_MOUSE_BUTTON_5_DOWN, RI_MOUSE_BUTTON_5_UP,
};
use super::scancode_to_physicalkey;
use crate::{
event::ElementState,
event_loop::DeviceEvents,
keyboard::{KeyCode, PhysicalKey},
platform_impl::platform::util,
};
use crate::event::ElementState;
use crate::event_loop::DeviceEvents;
use crate::keyboard::{KeyCode, PhysicalKey};
use crate::platform_impl::platform::util;
#[allow(dead_code)]
pub fn get_raw_input_device_list() -> Option<Vec<RAWINPUTDEVICELIST>> {
@ -91,12 +83,7 @@ pub fn get_raw_input_device_info(handle: HANDLE) -> Option<RawDeviceInfo> {
let mut minimum_size = 0;
let status = unsafe {
GetRawInputDeviceInfoW(
handle,
RIDI_DEVICEINFO,
&mut info as *mut _ as _,
&mut minimum_size,
)
GetRawInputDeviceInfoW(handle, RIDI_DEVICEINFO, &mut info as *mut _ as _, &mut minimum_size)
};
if status == u32::MAX || status == 0 {
@ -121,12 +108,7 @@ pub fn get_raw_input_device_name(handle: HANDLE) -> Option<String> {
let mut name: Vec<u16> = Vec::with_capacity(minimum_size as _);
let status = unsafe {
GetRawInputDeviceInfoW(
handle,
RIDI_DEVICENAME,
name.as_ptr() as _,
&mut minimum_size,
)
GetRawInputDeviceInfoW(handle, RIDI_DEVICENAME, name.as_ptr() as _, &mut minimum_size)
};
if status == u32::MAX || status == 0 {
@ -159,7 +141,7 @@ pub fn register_all_mice_and_keyboards_for_raw_input(
DeviceEvents::Never => {
window_handle = 0;
RIDEV_REMOVE
}
},
DeviceEvents::WhenFocused => RIDEV_DEVNOTIFY,
DeviceEvents::Always => RIDEV_DEVNOTIFY | RIDEV_INPUTSINK,
};
@ -188,13 +170,7 @@ pub fn get_raw_input_data(handle: HRAWINPUT) -> Option<RAWINPUT> {
let header_size = size_of::<RAWINPUTHEADER>() as u32;
let status = unsafe {
GetRawInputData(
handle,
RID_INPUT,
&mut data as *mut _ as _,
&mut data_size,
header_size,
)
GetRawInputData(handle, RID_INPUT, &mut data as *mut _ as _, &mut data_size, header_size)
};
if status == u32::MAX || status == 0 {
@ -232,9 +208,9 @@ pub fn get_raw_mouse_button_state(button_flags: u32) -> [Option<ElementState>; 5
pub fn get_keyboard_physical_key(keyboard: RAWKEYBOARD) -> Option<PhysicalKey> {
let extension = {
if util::has_flag(keyboard.Flags, RI_KEY_E0 as _) {
0xE000
0xe000
} else if util::has_flag(keyboard.Flags, RI_KEY_E1 as _) {
0xE100
0xe100
} else {
0x0000
}
@ -246,7 +222,7 @@ pub fn get_keyboard_physical_key(keyboard: RAWKEYBOARD) -> Option<PhysicalKey> {
} else {
keyboard.MakeCode | extension
};
if scancode == 0xE11D || scancode == 0xE02A {
if scancode == 0xe11d || scancode == 0xe02a {
// At the hardware (or driver?) level, pressing the Pause key is equivalent to pressing
// Ctrl+NumLock.
// This equvalence means that if the user presses Pause, the keyboard will emit two
@ -307,16 +283,17 @@ pub fn get_keyboard_physical_key(keyboard: RAWKEYBOARD) -> Option<PhysicalKey> {
// as well.
//
// The issue is that in the raw device event (here), the fake shift release
// event reports the numpad key as the scancode. Unfortunately, the event doesn't
// have any information to tell whether it's the left shift or the right shift
// that needs to get the fake release (or press) event so we don't forward this
// event reports the numpad key as the scancode. Unfortunately, the event
// doesn't have any information to tell whether it's the
// left shift or the right shift that needs to get the fake
// release (or press) event so we don't forward this
// event to the application at all.
//
// For more on this, read the article by Raymond Chen, titled:
// "The shift key overrides NumLock"
// https://devblogs.microsoft.com/oldnewthing/20040906-00/?p=37953
return None;
}
},
_ => (),
}
}

View file

@ -1,39 +1,27 @@
use std::{
ffi::{c_void, OsStr, OsString},
io,
iter::once,
mem,
ops::BitAnd,
os::windows::prelude::{OsStrExt, OsStringExt},
ptr,
sync::atomic::{AtomicBool, Ordering},
};
use std::ffi::{c_void, OsStr, OsString};
use std::iter::once;
use std::ops::BitAnd;
use std::os::windows::prelude::{OsStrExt, OsStringExt};
use std::sync::atomic::{AtomicBool, Ordering};
use std::{io, mem, ptr};
use crate::utils::Lazy;
use windows_sys::{
core::{HRESULT, PCWSTR},
Win32::{
Foundation::{BOOL, HANDLE, HMODULE, HWND, RECT},
Graphics::Gdi::{ClientToScreen, HMONITOR},
System::{
LibraryLoader::{GetProcAddress, LoadLibraryA},
SystemServices::IMAGE_DOS_HEADER,
},
UI::{
HiDpi::{DPI_AWARENESS_CONTEXT, MONITOR_DPI_TYPE, PROCESS_DPI_AWARENESS},
Input::{
KeyboardAndMouse::GetActiveWindow,
Pointer::{POINTER_INFO, POINTER_PEN_INFO, POINTER_TOUCH_INFO},
},
WindowsAndMessaging::{
ClipCursor, GetClientRect, GetClipCursor, GetSystemMetrics, GetWindowPlacement,
GetWindowRect, IsIconic, ShowCursor, IDC_APPSTARTING, IDC_ARROW, IDC_CROSS,
IDC_HAND, IDC_HELP, IDC_IBEAM, IDC_NO, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS,
IDC_SIZENWSE, IDC_SIZEWE, IDC_WAIT, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN,
SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN, SW_MAXIMIZE, WINDOWPLACEMENT,
},
},
},
use windows_sys::core::{HRESULT, PCWSTR};
use windows_sys::Win32::Foundation::{BOOL, HANDLE, HMODULE, HWND, RECT};
use windows_sys::Win32::Graphics::Gdi::{ClientToScreen, HMONITOR};
use windows_sys::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryA};
use windows_sys::Win32::System::SystemServices::IMAGE_DOS_HEADER;
use windows_sys::Win32::UI::HiDpi::{
DPI_AWARENESS_CONTEXT, MONITOR_DPI_TYPE, PROCESS_DPI_AWARENESS,
};
use windows_sys::Win32::UI::Input::KeyboardAndMouse::GetActiveWindow;
use windows_sys::Win32::UI::Input::Pointer::{POINTER_INFO, POINTER_PEN_INFO, POINTER_TOUCH_INFO};
use windows_sys::Win32::UI::WindowsAndMessaging::{
ClipCursor, GetClientRect, GetClipCursor, GetSystemMetrics, GetWindowPlacement, GetWindowRect,
IsIconic, ShowCursor, IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_HELP, IDC_IBEAM,
IDC_NO, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE, IDC_SIZEWE, IDC_WAIT,
SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN, SW_MAXIMIZE,
WINDOWPLACEMENT,
};
use crate::window::CursorIcon;
@ -77,7 +65,7 @@ impl WindowArea {
match self {
WindowArea::Outer => {
win_to_err(unsafe { GetWindowRect(hwnd, &mut rect) })?;
}
},
WindowArea::Inner => unsafe {
let mut top_left = mem::zeroed();
@ -123,10 +111,7 @@ pub fn get_cursor_clip() -> Result<RECT, io::Error> {
/// Note that calling this will automatically dispatch a `WM_MOUSEMOVE` event.
pub fn set_cursor_clip(rect: Option<RECT>) -> Result<(), io::Error> {
unsafe {
let rect_ptr = rect
.as_ref()
.map(|r| r as *const RECT)
.unwrap_or(ptr::null());
let rect_ptr = rect.as_ref().map(|r| r as *const RECT).unwrap_or(ptr::null());
win_to_err(ClipCursor(rect_ptr))
}
}
@ -176,7 +161,7 @@ pub(crate) fn to_windows_cursor(cursor: CursorIcon) -> PCWSTR {
CursorIcon::NotAllowed | CursorIcon::NoDrop => IDC_NO,
CursorIcon::Grab | CursorIcon::Grabbing | CursorIcon::Move | CursorIcon::AllScroll => {
IDC_SIZEALL
}
},
CursorIcon::EResize
| CursorIcon::WResize
| CursorIcon::EwResize

View file

@ -1,92 +1,76 @@
#![cfg(windows_platform)]
use std::{
cell::Cell,
ffi::c_void,
io,
mem::{self, MaybeUninit},
panic, ptr,
sync::{mpsc::channel, Arc, Mutex, MutexGuard},
};
use std::cell::Cell;
use std::ffi::c_void;
use std::mem::{self, MaybeUninit};
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex, MutexGuard};
use std::{io, panic, ptr};
use windows_sys::Win32::{
Foundation::{
HWND, LPARAM, OLE_E_WRONGCOMPOBJ, POINT, POINTS, RECT, RPC_E_CHANGED_MODE, S_OK, WPARAM,
},
Graphics::{
Dwm::{
DwmEnableBlurBehindWindow, DwmSetWindowAttribute, DWMWA_BORDER_COLOR,
DWMWA_CAPTION_COLOR, DWMWA_SYSTEMBACKDROP_TYPE, DWMWA_TEXT_COLOR,
DWMWA_WINDOW_CORNER_PREFERENCE, DWM_BB_BLURREGION, DWM_BB_ENABLE, DWM_BLURBEHIND,
DWM_SYSTEMBACKDROP_TYPE, DWM_WINDOW_CORNER_PREFERENCE,
},
Gdi::{
ChangeDisplaySettingsExW, ClientToScreen, CreateRectRgn, DeleteObject, InvalidateRgn,
RedrawWindow, CDS_FULLSCREEN, DISP_CHANGE_BADFLAGS, DISP_CHANGE_BADMODE,
DISP_CHANGE_BADPARAM, DISP_CHANGE_FAILED, DISP_CHANGE_SUCCESSFUL, RDW_INTERNALPAINT,
},
},
System::{
Com::{
CoCreateInstance, CoInitializeEx, CoUninitialize, CLSCTX_ALL, COINIT_APARTMENTTHREADED,
},
Ole::{OleInitialize, RegisterDragDrop},
},
UI::{
Input::{
KeyboardAndMouse::{
EnableWindow, GetActiveWindow, MapVirtualKeyW, ReleaseCapture, SendInput,
ToUnicode, INPUT, INPUT_0, INPUT_KEYBOARD, KEYBDINPUT, KEYEVENTF_EXTENDEDKEY,
KEYEVENTF_KEYUP, MAPVK_VK_TO_VSC, VIRTUAL_KEY, VK_LMENU, VK_MENU, VK_SPACE,
},
Touch::{RegisterTouchWindow, TWF_WANTPALM},
},
WindowsAndMessaging::{
CreateWindowExW, EnableMenuItem, FlashWindowEx, GetClientRect, GetCursorPos,
GetForegroundWindow, GetSystemMenu, GetSystemMetrics, GetWindowPlacement,
GetWindowTextLengthW, GetWindowTextW, IsWindowVisible, LoadCursorW, PeekMessageW,
PostMessageW, RegisterClassExW, SetCursor, SetCursorPos, SetForegroundWindow,
SetMenuDefaultItem, SetWindowDisplayAffinity, SetWindowPlacement, SetWindowPos,
SetWindowTextW, TrackPopupMenu, CS_HREDRAW, CS_VREDRAW, CW_USEDEFAULT, FLASHWINFO,
FLASHW_ALL, FLASHW_STOP, FLASHW_TIMERNOFG, FLASHW_TRAY, GWLP_HINSTANCE, HTBOTTOM,
HTBOTTOMLEFT, HTBOTTOMRIGHT, HTCAPTION, HTLEFT, HTRIGHT, HTTOP, HTTOPLEFT, HTTOPRIGHT,
MENU_ITEM_STATE, MFS_DISABLED, MFS_ENABLED, MF_BYCOMMAND, NID_READY, PM_NOREMOVE,
SC_CLOSE, SC_MAXIMIZE, SC_MINIMIZE, SC_MOVE, SC_RESTORE, SC_SIZE, SM_DIGITIZER,
SWP_ASYNCWINDOWPOS, SWP_NOACTIVATE, SWP_NOSIZE, SWP_NOZORDER, TPM_LEFTALIGN,
TPM_RETURNCMD, WDA_EXCLUDEFROMCAPTURE, WDA_NONE, WM_NCLBUTTONDOWN, WM_SYSCOMMAND,
WNDCLASSEXW,
},
},
use windows_sys::Win32::Foundation::{
HWND, LPARAM, OLE_E_WRONGCOMPOBJ, POINT, POINTS, RECT, RPC_E_CHANGED_MODE, S_OK, WPARAM,
};
use windows_sys::Win32::Graphics::Dwm::{
DwmEnableBlurBehindWindow, DwmSetWindowAttribute, DWMWA_BORDER_COLOR, DWMWA_CAPTION_COLOR,
DWMWA_SYSTEMBACKDROP_TYPE, DWMWA_TEXT_COLOR, DWMWA_WINDOW_CORNER_PREFERENCE, DWM_BB_BLURREGION,
DWM_BB_ENABLE, DWM_BLURBEHIND, DWM_SYSTEMBACKDROP_TYPE, DWM_WINDOW_CORNER_PREFERENCE,
};
use windows_sys::Win32::Graphics::Gdi::{
ChangeDisplaySettingsExW, ClientToScreen, CreateRectRgn, DeleteObject, InvalidateRgn,
RedrawWindow, CDS_FULLSCREEN, DISP_CHANGE_BADFLAGS, DISP_CHANGE_BADMODE, DISP_CHANGE_BADPARAM,
DISP_CHANGE_FAILED, DISP_CHANGE_SUCCESSFUL, RDW_INTERNALPAINT,
};
use windows_sys::Win32::System::Com::{
CoCreateInstance, CoInitializeEx, CoUninitialize, CLSCTX_ALL, COINIT_APARTMENTTHREADED,
};
use windows_sys::Win32::System::Ole::{OleInitialize, RegisterDragDrop};
use windows_sys::Win32::UI::Input::KeyboardAndMouse::{
EnableWindow, GetActiveWindow, MapVirtualKeyW, ReleaseCapture, SendInput, ToUnicode, INPUT,
INPUT_0, INPUT_KEYBOARD, KEYBDINPUT, KEYEVENTF_EXTENDEDKEY, KEYEVENTF_KEYUP, MAPVK_VK_TO_VSC,
VIRTUAL_KEY, VK_LMENU, VK_MENU, VK_SPACE,
};
use windows_sys::Win32::UI::Input::Touch::{RegisterTouchWindow, TWF_WANTPALM};
use windows_sys::Win32::UI::WindowsAndMessaging::{
CreateWindowExW, EnableMenuItem, FlashWindowEx, GetClientRect, GetCursorPos,
GetForegroundWindow, GetSystemMenu, GetSystemMetrics, GetWindowPlacement, GetWindowTextLengthW,
GetWindowTextW, IsWindowVisible, LoadCursorW, PeekMessageW, PostMessageW, RegisterClassExW,
SetCursor, SetCursorPos, SetForegroundWindow, SetMenuDefaultItem, SetWindowDisplayAffinity,
SetWindowPlacement, SetWindowPos, SetWindowTextW, TrackPopupMenu, CS_HREDRAW, CS_VREDRAW,
CW_USEDEFAULT, FLASHWINFO, FLASHW_ALL, FLASHW_STOP, FLASHW_TIMERNOFG, FLASHW_TRAY,
GWLP_HINSTANCE, HTBOTTOM, HTBOTTOMLEFT, HTBOTTOMRIGHT, HTCAPTION, HTLEFT, HTRIGHT, HTTOP,
HTTOPLEFT, HTTOPRIGHT, MENU_ITEM_STATE, MFS_DISABLED, MFS_ENABLED, MF_BYCOMMAND, NID_READY,
PM_NOREMOVE, SC_CLOSE, SC_MAXIMIZE, SC_MINIMIZE, SC_MOVE, SC_RESTORE, SC_SIZE, SM_DIGITIZER,
SWP_ASYNCWINDOWPOS, SWP_NOACTIVATE, SWP_NOSIZE, SWP_NOZORDER, TPM_LEFTALIGN, TPM_RETURNCMD,
WDA_EXCLUDEFROMCAPTURE, WDA_NONE, WM_NCLBUTTONDOWN, WM_SYSCOMMAND, WNDCLASSEXW,
};
use tracing::warn;
use crate::{
cursor::Cursor,
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
error::{ExternalError, NotSupportedError, OsError as RootOsError},
icon::Icon,
platform::windows::{BackdropType, Color, CornerPreference},
platform_impl::platform::{
dark_mode::try_theme,
definitions::{
CLSID_TaskbarList, IID_ITaskbarList, IID_ITaskbarList2, ITaskbarList, ITaskbarList2,
},
dpi::{dpi_to_scale_factor, enable_non_client_dpi_scaling, hwnd_dpi},
drop_handler::FileDropHandler,
event_loop::{self, ActiveEventLoop, DESTROY_MSG_ID},
icon::{self, IconType, WinCursor},
ime::ImeContext,
keyboard::KeyEventBuilder,
monitor::{self, MonitorHandle},
util,
window_state::{CursorFlags, SavedWindow, WindowFlags, WindowState},
Fullscreen, SelectedCursor, WindowId,
},
window::{
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes,
WindowButtons, WindowLevel,
},
use crate::cursor::Cursor;
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
use crate::icon::Icon;
use crate::platform::windows::{BackdropType, Color, CornerPreference};
use crate::platform_impl::platform::dark_mode::try_theme;
use crate::platform_impl::platform::definitions::{
CLSID_TaskbarList, IID_ITaskbarList, IID_ITaskbarList2, ITaskbarList, ITaskbarList2,
};
use crate::platform_impl::platform::dpi::{
dpi_to_scale_factor, enable_non_client_dpi_scaling, hwnd_dpi,
};
use crate::platform_impl::platform::drop_handler::FileDropHandler;
use crate::platform_impl::platform::event_loop::{self, ActiveEventLoop, DESTROY_MSG_ID};
use crate::platform_impl::platform::icon::{self, IconType, WinCursor};
use crate::platform_impl::platform::ime::ImeContext;
use crate::platform_impl::platform::keyboard::KeyEventBuilder;
use crate::platform_impl::platform::monitor::{self, MonitorHandle};
use crate::platform_impl::platform::window_state::{
CursorFlags, SavedWindow, WindowFlags, WindowState,
};
use crate::platform_impl::platform::{util, Fullscreen, SelectedCursor, WindowId};
use crate::window::{
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes,
WindowButtons, WindowLevel,
};
/// The Win32 implementation of the main `Window` object.
@ -178,16 +162,23 @@ impl Window {
#[inline]
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
util::WindowArea::Outer.get_rect(self.hwnd())
util::WindowArea::Outer
.get_rect(self.hwnd())
.map(|rect| Ok(PhysicalPosition::new(rect.left, rect.top)))
.expect("Unexpected GetWindowRect failure; please report this error to rust-windowing/winit")
.expect(
"Unexpected GetWindowRect failure; please report this error to \
rust-windowing/winit",
)
}
#[inline]
pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
let mut position: POINT = unsafe { mem::zeroed() };
if unsafe { ClientToScreen(self.hwnd(), &mut position) } == false.into() {
panic!("Unexpected ClientToScreen failure: please report this error to rust-windowing/winit")
panic!(
"Unexpected ClientToScreen failure: please report this error to \
rust-windowing/winit"
)
}
Ok(PhysicalPosition::new(position.x, position.y))
}
@ -223,12 +214,12 @@ impl Window {
pub fn inner_size(&self) -> PhysicalSize<u32> {
let mut rect: RECT = unsafe { mem::zeroed() };
if unsafe { GetClientRect(self.hwnd(), &mut rect) } == false.into() {
panic!("Unexpected GetClientRect failure: please report this error to rust-windowing/winit")
panic!(
"Unexpected GetClientRect failure: please report this error to \
rust-windowing/winit"
)
}
PhysicalSize::new(
(rect.right - rect.left) as u32,
(rect.bottom - rect.top) as u32,
)
PhysicalSize::new((rect.right - rect.left) as u32, (rect.bottom - rect.top) as u32)
}
#[inline]
@ -236,10 +227,7 @@ impl Window {
util::WindowArea::Outer
.get_rect(self.hwnd())
.map(|rect| {
PhysicalSize::new(
(rect.right - rect.left) as u32,
(rect.bottom - rect.top) as u32,
)
PhysicalSize::new((rect.right - rect.left) as u32, (rect.bottom - rect.top) as u32)
})
.unwrap()
}
@ -286,8 +274,7 @@ impl Window {
pub fn resize_increments(&self) -> Option<PhysicalSize<u32>> {
let w = self.window_state_lock();
let scale_factor = w.scale_factor;
w.resize_increments
.map(|size| size.to_physical(scale_factor))
w.resize_increments.map(|size| size.to_physical(scale_factor))
}
#[inline]
@ -322,18 +309,9 @@ impl Window {
self.thread_executor.execute_in_thread(move || {
let _ = &window;
WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
f.set(
WindowFlags::MINIMIZABLE,
buttons.contains(WindowButtons::MINIMIZE),
);
f.set(
WindowFlags::MAXIMIZABLE,
buttons.contains(WindowButtons::MAXIMIZE),
);
f.set(
WindowFlags::CLOSABLE,
buttons.contains(WindowButtons::CLOSE),
)
f.set(WindowFlags::MINIMIZABLE, buttons.contains(WindowButtons::MINIMIZE));
f.set(WindowFlags::MAXIMIZABLE, buttons.contains(WindowButtons::MAXIMIZE));
f.set(WindowFlags::CLOSABLE, buttons.contains(WindowButtons::CLOSE))
});
});
}
@ -352,6 +330,7 @@ impl Window {
}
buttons
}
/// Returns the `hwnd` of this window.
#[inline]
pub fn hwnd(&self) -> HWND {
@ -401,9 +380,7 @@ impl Window {
pub fn raw_display_handle_rwh_06(
&self,
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
Ok(rwh_06::RawDisplayHandle::Windows(
rwh_06::WindowsDisplayHandle::new(),
))
Ok(rwh_06::RawDisplayHandle::Windows(rwh_06::WindowsDisplayHandle::new()))
}
#[inline]
@ -415,21 +392,21 @@ impl Window {
let cursor = LoadCursorW(0, util::to_windows_cursor(icon));
SetCursor(cursor);
});
}
},
Cursor::Custom(cursor) => {
let new_cursor = match cursor.inner {
WinCursor::Cursor(cursor) => cursor,
WinCursor::Failed => {
warn!("Requested to apply failed cursor");
return;
}
},
};
self.window_state_lock().mouse.selected_cursor =
SelectedCursor::Custom(new_cursor.clone());
self.thread_executor.execute_in_thread(move || unsafe {
SetCursor(new_cursor.as_raw_handle());
});
}
},
}
}
@ -440,7 +417,7 @@ impl Window {
CursorGrabMode::Confined => true,
CursorGrabMode::Locked => {
return Err(ExternalError::NotSupported(NotSupportedError::new()))
}
},
};
let window = self.window;
@ -520,21 +497,13 @@ impl Window {
unsafe { GetCursorPos(&mut pos) };
pos
};
let points = POINTS {
x: points.x as i16,
y: points.y as i16,
};
let points = POINTS { x: points.x as i16, y: points.y as i16 };
// ReleaseCapture needs to execute on the main thread
unsafe { ReleaseCapture() };
unsafe {
PostMessageW(
window,
WM_NCLBUTTONDOWN,
wparam,
&points as *const _ as LPARAM,
)
PostMessageW(window, WM_NCLBUTTONDOWN, wparam, &points as *const _ as LPARAM)
};
});
}
@ -575,7 +544,10 @@ impl Window {
point.x = x;
point.y = y;
if ClientToScreen(self.hwnd(), &mut point) == false.into() {
warn!("Can't convert client-area coordinates to screen coordinates when showing window menu.");
warn!(
"Can't convert client-area coordinates to screen coordinates when showing \
window menu."
);
return;
}
point
@ -585,7 +557,8 @@ impl Window {
let h_menu = GetSystemMenu(self.hwnd(), 0);
if h_menu == 0 {
warn!("The corresponding window doesn't have a system menu");
// This situation should not be treated as an error so just return without showing menu.
// This situation should not be treated as an error so just return without showing
// menu.
return;
}
@ -616,7 +589,8 @@ impl Window {
// Popup the system menu at the position.
let result = TrackPopupMenu(
h_menu,
TPM_RETURNCMD | TPM_LEFTALIGN, // for now im using LTR, but we have to use user layout direction
TPM_RETURNCMD | TPM_LEFTALIGN, /* for now im using LTR, but we have to use user
* layout direction */
point.x,
point.y,
0,
@ -720,13 +694,14 @@ impl Window {
match (&old_fullscreen, &fullscreen) {
// Return if we already are in the same fullscreen mode
_ if old_fullscreen == fullscreen => return,
// Return if saved Borderless(monitor) is the same as current monitor when requested fullscreen is Borderless(None)
// Return if saved Borderless(monitor) is the same as current monitor when requested
// fullscreen is Borderless(None)
(Some(Fullscreen::Borderless(Some(monitor))), Some(Fullscreen::Borderless(None)))
if *monitor == monitor::current_monitor(window) =>
{
return
}
_ => {}
},
_ => {},
}
window_state_lock.fullscreen.clone_from(&fullscreen);
@ -756,7 +731,7 @@ impl Window {
debug_assert!(res != DISP_CHANGE_BADPARAM);
debug_assert!(res != DISP_CHANGE_FAILED);
assert_eq!(res, DISP_CHANGE_SUCCESSFUL);
}
},
(Some(Fullscreen::Exclusive(_)), _) => {
let res = unsafe {
ChangeDisplaySettingsExW(
@ -773,7 +748,7 @@ impl Window {
debug_assert!(res != DISP_CHANGE_BADPARAM);
debug_assert!(res != DISP_CHANGE_FAILED);
assert_eq!(res, DISP_CHANGE_SUCCESSFUL);
}
},
_ => (),
}
@ -805,7 +780,8 @@ impl Window {
// Mark as fullscreen window wrt to z-order
//
// this needs to be called before the below fullscreen SetWindowPos as this itself
// will generate WM_SIZE messages of the old window size that can race with what we set below
// will generate WM_SIZE messages of the old window size that can race with what we set
// below
unsafe {
taskbar_mark_fullscreen(window, fullscreen.is_some());
}
@ -843,7 +819,7 @@ impl Window {
);
InvalidateRgn(window, 0, false.into());
}
}
},
None => {
let mut window_state_lock = window_state.lock().unwrap();
if let Some(SavedWindow { placement }) = window_state_lock.saved_window.take() {
@ -853,7 +829,7 @@ impl Window {
InvalidateRgn(window, 0, false.into());
}
}
}
},
}
});
}
@ -874,9 +850,7 @@ impl Window {
#[inline]
pub fn is_decorated(&self) -> bool {
let window_state = self.window_state_lock();
window_state
.window_flags
.contains(WindowFlags::MARKER_DECORATIONS)
window_state.window_flags.contains(WindowFlags::MARKER_DECORATIONS)
}
#[inline]
@ -887,14 +861,8 @@ impl Window {
self.thread_executor.execute_in_thread(move || {
let _ = &window;
WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
f.set(
WindowFlags::ALWAYS_ON_TOP,
level == WindowLevel::AlwaysOnTop,
);
f.set(
WindowFlags::ALWAYS_ON_BOTTOM,
level == WindowLevel::AlwaysOnBottom,
);
f.set(WindowFlags::ALWAYS_ON_TOP, level == WindowLevel::AlwaysOnTop);
f.set(WindowFlags::ALWAYS_ON_BOTTOM, level == WindowLevel::AlwaysOnBottom);
});
});
}
@ -907,9 +875,7 @@ impl Window {
#[inline]
pub fn set_window_icon(&self, window_icon: Option<Icon>) {
if let Some(ref window_icon) = window_icon {
window_icon
.inner
.set_for_window(self.hwnd(), IconType::Small);
window_icon.inner.set_for_window(self.hwnd(), IconType::Small);
} else {
icon::unset_for_window(self.hwnd(), IconType::Small);
}
@ -924,9 +890,7 @@ impl Window {
#[inline]
pub fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>) {
if let Some(ref taskbar_icon) = taskbar_icon {
taskbar_icon
.inner
.set_for_window(self.hwnd(), IconType::Big);
taskbar_icon.inner.set_for_window(self.hwnd(), IconType::Big);
} else {
icon::unset_for_window(self.hwnd(), IconType::Big);
}
@ -1055,11 +1019,7 @@ impl Window {
unsafe {
SetWindowDisplayAffinity(
self.hwnd(),
if protected {
WDA_EXCLUDEFROMCAPTURE
} else {
WDA_NONE
},
if protected { WDA_EXCLUDEFROMCAPTURE } else { WDA_NONE },
)
};
}
@ -1189,11 +1149,7 @@ impl<'a> InitData<'a> {
unsafe { ImeContext::set_ime_allowed(window, false) };
Window {
window,
window_state,
thread_executor: self.event_loop.create_thread_executor(),
}
Window { window, window_state, thread_executor: self.event_loop.create_thread_executor() }
}
unsafe fn create_window_data(&self, win: &Window) -> event_loop::WindowData {
@ -1205,9 +1161,9 @@ impl<'a> InitData<'a> {
panic!("OleInitialize failed! Result was: `OLE_E_WRONGCOMPOBJ`");
} else if ole_init_result == RPC_E_CHANGED_MODE {
panic!(
"OleInitialize failed! Result was: `RPC_E_CHANGED_MODE`. \
Make sure other crates are not using multithreaded COM library \
on the same thread or disable drag and drop support."
"OleInitialize failed! Result was: `RPC_E_CHANGED_MODE`. Make sure other \
crates are not using multithreaded COM library on the same thread or disable \
drag and drop support."
);
}
@ -1224,10 +1180,7 @@ impl<'a> InitData<'a> {
let handler_interface_ptr =
unsafe { &mut (*file_drop_handler.data).interface as *mut _ as *mut c_void };
assert_eq!(
unsafe { RegisterDragDrop(win.window, handler_interface_ptr) },
S_OK
);
assert_eq!(unsafe { RegisterDragDrop(win.window, handler_interface_ptr) }, S_OK);
Some(file_drop_handler)
} else {
None
@ -1244,7 +1197,8 @@ impl<'a> InitData<'a> {
}
// Returns a pointer to window user data on success.
// The user data will be registered for the window and can be accessed within the window event callback.
// The user data will be registered for the window and can be accessed within the window event
// callback.
pub unsafe fn on_nccreate(&mut self, window: HWND) -> Option<isize> {
let runner = self.event_loop.runner_shared.clone();
let result = runner.catch_unwind(|| {
@ -1276,10 +1230,7 @@ impl<'a> InitData<'a> {
};
let hr = unsafe { DwmEnableBlurBehindWindow(win.hwnd(), &bb) };
if hr < 0 {
warn!(
"Setting transparent window is failed. HRESULT Code: 0x{:X}",
hr
);
warn!("Setting transparent window is failed. HRESULT Code: 0x{:X}", hr);
}
unsafe { DeleteObject(region) };
}
@ -1302,15 +1253,11 @@ impl<'a> InitData<'a> {
win.set_enabled_buttons(attributes.enabled_buttons);
let size = attributes
.inner_size
.unwrap_or_else(|| PhysicalSize::new(800, 600).into());
let size = attributes.inner_size.unwrap_or_else(|| PhysicalSize::new(800, 600).into());
let max_size = attributes
.max_inner_size
.unwrap_or_else(|| PhysicalSize::new(f64::MAX, f64::MAX).into());
let min_size = attributes
.min_inner_size
.unwrap_or_else(|| PhysicalSize::new(0, 0).into());
let min_size = attributes.min_inner_size.unwrap_or_else(|| PhysicalSize::new(0, 0).into());
let clamped_size = Size::clamp(size, min_size, max_size, win.scale_factor());
win.request_inner_size(clamped_size);
@ -1357,18 +1304,12 @@ unsafe fn init(
WindowFlags::MARKER_UNDECORATED_SHADOW,
attributes.platform_specific.decoration_shadow,
);
window_flags.set(
WindowFlags::ALWAYS_ON_TOP,
attributes.window_level == WindowLevel::AlwaysOnTop,
);
window_flags.set(
WindowFlags::ALWAYS_ON_BOTTOM,
attributes.window_level == WindowLevel::AlwaysOnBottom,
);
window_flags.set(
WindowFlags::NO_BACK_BUFFER,
attributes.platform_specific.no_redirection_bitmap,
);
window_flags
.set(WindowFlags::ALWAYS_ON_TOP, attributes.window_level == WindowLevel::AlwaysOnTop);
window_flags
.set(WindowFlags::ALWAYS_ON_BOTTOM, attributes.window_level == WindowLevel::AlwaysOnBottom);
window_flags
.set(WindowFlags::NO_BACK_BUFFER, attributes.platform_specific.no_redirection_bitmap);
window_flags.set(WindowFlags::MARKER_ACTIVATE, attributes.active);
window_flags.set(WindowFlags::TRANSPARENT, attributes.transparent);
// WindowFlags::VISIBLE and MAXIMIZED are set down below after the window has been configured.
@ -1376,20 +1317,17 @@ unsafe fn init(
// Will be changed later using `window.set_enabled_buttons` but we need to set a default here
// so the diffing later can work.
window_flags.set(WindowFlags::CLOSABLE, true);
window_flags.set(
WindowFlags::CLIP_CHILDREN,
attributes.platform_specific.clip_children,
);
window_flags.set(WindowFlags::CLIP_CHILDREN, attributes.platform_specific.clip_children);
let mut fallback_parent = || match attributes.platform_specific.owner {
Some(parent) => {
window_flags.set(WindowFlags::POPUP, true);
Some(parent)
}
},
None => {
window_flags.set(WindowFlags::ON_TASKBAR, true);
None
}
},
};
#[cfg(feature = "rwh_06")]
@ -1400,7 +1338,7 @@ unsafe fn init(
warn!("Setting a menu on a child window is unsupported");
}
Some(handle.hwnd.get() as HWND)
}
},
Some(raw) => unreachable!("Invalid raw window handle {raw:?} on Windows"),
None => fallback_parent(),
};
@ -1411,12 +1349,7 @@ unsafe fn init(
let menu = attributes.platform_specific.menu;
let fullscreen = attributes.fullscreen.clone();
let maximized = attributes.maximized;
let mut initdata = InitData {
event_loop,
attributes,
window_flags,
window: None,
};
let mut initdata = InitData { event_loop, attributes, window_flags, window: None };
let (style, ex_style) = window_flags.to_window_styles();
let handle = unsafe {
@ -1450,7 +1383,8 @@ unsafe fn init(
let win = initdata.window.unwrap();
// Need to set FULLSCREEN or MAXIMIZED after CreateWindowEx
// This is because if the size is changed in WM_CREATE, the restored size will be stored in that size.
// This is because if the size is changed in WM_CREATE, the restored size will be stored in that
// size.
if fullscreen.is_some() {
win.set_fullscreen(fullscreen.map(Into::into));
unsafe { force_window_active(win.window) };
@ -1624,13 +1558,7 @@ unsafe fn force_window_active(handle: HWND) {
];
// Simulate a key press and release
unsafe {
SendInput(
inputs.len() as u32,
inputs.as_ptr(),
mem::size_of::<INPUT>() as i32,
)
};
unsafe { SendInput(inputs.len() as u32, inputs.as_ptr(), mem::size_of::<INPUT>() as i32) };
unsafe { SetForegroundWindow(handle) };
}

View file

@ -1,28 +1,23 @@
use crate::{
dpi::{PhysicalPosition, PhysicalSize, Size},
icon::Icon,
keyboard::ModifiersState,
platform_impl::platform::{event_loop, util, Fullscreen, SelectedCursor},
window::{Theme, WindowAttributes},
};
use crate::dpi::{PhysicalPosition, PhysicalSize, Size};
use crate::icon::Icon;
use crate::keyboard::ModifiersState;
use crate::platform_impl::platform::{event_loop, util, Fullscreen, SelectedCursor};
use crate::window::{Theme, WindowAttributes};
use bitflags::bitflags;
use std::io;
use std::sync::MutexGuard;
use windows_sys::Win32::{
Foundation::{HWND, RECT},
Graphics::Gdi::InvalidateRgn,
UI::WindowsAndMessaging::{
AdjustWindowRectEx, EnableMenuItem, GetMenu, GetSystemMenu, GetWindowLongW, SendMessageW,
SetWindowLongW, SetWindowPos, ShowWindow, GWL_EXSTYLE, GWL_STYLE, HWND_BOTTOM,
HWND_NOTOPMOST, HWND_TOPMOST, MF_BYCOMMAND, MF_DISABLED, MF_ENABLED, SC_CLOSE,
SWP_ASYNCWINDOWPOS, SWP_FRAMECHANGED, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOREPOSITION,
SWP_NOSIZE, SWP_NOZORDER, SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE, SW_SHOW,
SW_SHOWNOACTIVATE, WINDOWPLACEMENT, WINDOW_EX_STYLE, WINDOW_STYLE, WS_BORDER, WS_CAPTION,
WS_CHILD, WS_CLIPCHILDREN, WS_CLIPSIBLINGS, WS_EX_ACCEPTFILES, WS_EX_APPWINDOW,
WS_EX_LAYERED, WS_EX_NOREDIRECTIONBITMAP, WS_EX_TOPMOST, WS_EX_TRANSPARENT,
WS_EX_WINDOWEDGE, WS_MAXIMIZE, WS_MAXIMIZEBOX, WS_MINIMIZE, WS_MINIMIZEBOX,
WS_OVERLAPPEDWINDOW, WS_POPUP, WS_SIZEBOX, WS_SYSMENU, WS_VISIBLE,
},
use windows_sys::Win32::Foundation::{HWND, RECT};
use windows_sys::Win32::Graphics::Gdi::InvalidateRgn;
use windows_sys::Win32::UI::WindowsAndMessaging::{
AdjustWindowRectEx, EnableMenuItem, GetMenu, GetSystemMenu, GetWindowLongW, SendMessageW,
SetWindowLongW, SetWindowPos, ShowWindow, GWL_EXSTYLE, GWL_STYLE, HWND_BOTTOM, HWND_NOTOPMOST,
HWND_TOPMOST, MF_BYCOMMAND, MF_DISABLED, MF_ENABLED, SC_CLOSE, SWP_ASYNCWINDOWPOS,
SWP_FRAMECHANGED, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOREPOSITION, SWP_NOSIZE, SWP_NOZORDER,
SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE, SW_SHOW, SW_SHOWNOACTIVATE, WINDOWPLACEMENT,
WINDOW_EX_STYLE, WINDOW_STYLE, WS_BORDER, WS_CAPTION, WS_CHILD, WS_CLIPCHILDREN,
WS_CLIPSIBLINGS, WS_EX_ACCEPTFILES, WS_EX_APPWINDOW, WS_EX_LAYERED, WS_EX_NOREDIRECTIONBITMAP,
WS_EX_TOPMOST, WS_EX_TRANSPARENT, WS_EX_WINDOWEDGE, WS_MAXIMIZE, WS_MAXIMIZEBOX, WS_MINIMIZE,
WS_MINIMIZEBOX, WS_OVERLAPPEDWINDOW, WS_POPUP, WS_SIZEBOX, WS_SYSMENU, WS_VISIBLE,
};
/// Contains information about states and the window that the callback is going to use.
@ -242,7 +237,7 @@ impl MouseProperties {
Err(e) => {
self.cursor_flags = old_flags;
return Err(e);
}
},
}
Ok(())
@ -365,26 +360,20 @@ impl WindowFlags {
if diff.contains(WindowFlags::MAXIMIZED) || new.contains(WindowFlags::MAXIMIZED) {
unsafe {
ShowWindow(
window,
match new.contains(WindowFlags::MAXIMIZED) {
true => SW_MAXIMIZE,
false => SW_RESTORE,
},
);
ShowWindow(window, match new.contains(WindowFlags::MAXIMIZED) {
true => SW_MAXIMIZE,
false => SW_RESTORE,
});
}
}
// Minimize operations should execute after maximize for proper window animations
if diff.contains(WindowFlags::MINIMIZED) {
unsafe {
ShowWindow(
window,
match new.contains(WindowFlags::MINIMIZED) {
true => SW_MINIMIZE,
false => SW_RESTORE,
},
);
ShowWindow(window, match new.contains(WindowFlags::MINIMIZED) {
true => SW_MINIMIZE,
false => SW_RESTORE,
});
}
diff.remove(WindowFlags::MINIMIZED);
@ -392,11 +381,7 @@ impl WindowFlags {
if diff.contains(WindowFlags::CLOSABLE) || new.contains(WindowFlags::CLOSABLE) {
let flags = MF_BYCOMMAND
| if new.contains(WindowFlags::CLOSABLE) {
MF_ENABLED
} else {
MF_DISABLED
};
| if new.contains(WindowFlags::CLOSABLE) { MF_ENABLED } else { MF_DISABLED };
unsafe {
EnableMenuItem(GetSystemMenu(window, 0), SC_CLOSE, flags);
@ -413,12 +398,7 @@ impl WindowFlags {
let (style, style_ex) = new.to_window_styles();
unsafe {
SendMessageW(
window,
event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID.get(),
1,
0,
);
SendMessageW(window, event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID.get(), 1, 0);
// This condition is necessary to avoid having an unrestorable window
if !new.contains(WindowFlags::MINIMIZED) {
@ -439,12 +419,7 @@ impl WindowFlags {
// Refresh the window frame
SetWindowPos(window, 0, 0, 0, 0, 0, flags);
SendMessageW(
window,
event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID.get(),
0,
0,
);
SendMessageW(window, event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID.get(), 0, 0);
}
}
}
@ -454,17 +429,17 @@ impl WindowFlags {
let mut style = GetWindowLongW(hwnd, GWL_STYLE) as u32;
let style_ex = GetWindowLongW(hwnd, GWL_EXSTYLE) as u32;
// Frameless style implemented by manually overriding the non-client area in `WM_NCCALCSIZE`.
// Frameless style implemented by manually overriding the non-client area in
// `WM_NCCALCSIZE`.
if !self.contains(WindowFlags::MARKER_DECORATIONS) {
style &= !(WS_CAPTION | WS_SIZEBOX);
}
util::win_to_err({
let b_menu = GetMenu(hwnd) != 0;
if let (Some(get_dpi_for_window), Some(adjust_window_rect_ex_for_dpi)) = (
*util::GET_DPI_FOR_WINDOW,
*util::ADJUST_WINDOW_RECT_EX_FOR_DPI,
) {
if let (Some(get_dpi_for_window), Some(adjust_window_rect_ex_for_dpi)) =
(*util::GET_DPI_FOR_WINDOW, *util::ADJUST_WINDOW_RECT_EX_FOR_DPI)
{
let dpi = get_dpi_for_window(hwnd);
adjust_window_rect_ex_for_dpi(&mut rect, style, b_menu.into(), style_ex, dpi)
} else {
@ -477,12 +452,7 @@ impl WindowFlags {
pub fn adjust_size(self, hwnd: HWND, size: PhysicalSize<u32>) -> PhysicalSize<u32> {
let (width, height): (u32, u32) = size.into();
let rect = RECT {
left: 0,
right: width as i32,
top: 0,
bottom: height as i32,
};
let rect = RECT { left: 0, right: width as i32, top: 0, bottom: height as i32 };
let rect = self.adjust_rect(hwnd, rect).unwrap_or(rect);
let outer_x = (rect.right - rect.left).abs();
@ -516,20 +486,16 @@ impl CursorFlags {
let cursor_clip = match self.contains(CursorFlags::GRABBED) {
true => {
if self.contains(CursorFlags::HIDDEN) {
// Confine the cursor to the center of the window if the cursor is hidden. This avoids
// problems with the cursor activating the taskbar if the window borders or overlaps that.
// Confine the cursor to the center of the window if the cursor is hidden.
// This avoids problems with the cursor activating
// the taskbar if the window borders or overlaps that.
let cx = (client_rect.left + client_rect.right) / 2;
let cy = (client_rect.top + client_rect.bottom) / 2;
Some(RECT {
left: cx,
right: cx + 1,
top: cy,
bottom: cy + 1,
})
Some(RECT { left: cx, right: cx + 1, top: cy, bottom: cy + 1 })
} else {
Some(client_rect)
}
}
},
false => None,
};
@ -543,8 +509,9 @@ impl CursorFlags {
};
// We do this check because calling `set_cursor_clip` incessantly will flood the event
// loop with `WM_MOUSEMOVE` events, and `refresh_os_cursor` is called by `set_cursor_flags`
// which at times gets called once every iteration of the eventloop.
// loop with `WM_MOUSEMOVE` events, and `refresh_os_cursor` is called by
// `set_cursor_flags` which at times gets called once every iteration of the
// eventloop.
if active_cursor_clip != cursor_clip.map(rect_to_tuple) {
util::set_cursor_clip(cursor_clip)?;
}