diff --git a/CHANGELOG.md b/CHANGELOG.md index fddd2db716d..fb225277c31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ - Corrected `get_position` on macOS to return outer frame position, not content area position. - Corrected `set_position` on macOS to set outer frame position, not content area position. - Added `get_inner_position` method to `Window`, which gets the position of the window's client area. This is implemented on all applicable platforms (all desktop platforms other than Wayland, where this isn't possible). +- On Windows, implemented all variants of `DeviceEvent` other than `Text`. Mouse `DeviceEvent`s are now received even if the window isn't in the foreground. +- `DeviceId` on Windows is no longer a unit struct, and now contains a `u32`. For `WindowEvent`s, this will always be 0, but on `DeviceEvent`s it will be the handle to that device. `DeviceIdExt::get_persistent_identifier` can be used to acquire a unique identifier for that device that persists across replugs/reboots/etc. # Version 0.12.0 (2018-04-06) diff --git a/src/os/windows.rs b/src/os/windows.rs index d474cafa44b..1526d3b7903 100644 --- a/src/os/windows.rs +++ b/src/os/windows.rs @@ -3,6 +3,7 @@ use std::os::raw::c_void; use libc; use MonitorId; +use DeviceId; use Window; use WindowBuilder; use winapi::shared::windef::HWND; @@ -56,3 +57,18 @@ impl MonitorIdExt for MonitorId { self.inner.get_hmonitor() as *mut _ } } + +/// Additional methods on `DeviceId` that are specific to Windows. +pub trait DeviceIdExt { + /// Returns an identifier that persistently refers to this specific device. + /// + /// Will return `None` if the device is no longer available. + fn get_persistent_identifier(&self) -> Option; +} + +impl DeviceIdExt for DeviceId { + #[inline] + fn get_persistent_identifier(&self) -> Option { + self.0.get_persistent_identifier() + } +} diff --git a/src/platform/windows/event.rs b/src/platform/windows/event.rs index 5abdf309eb8..21a14cc6283 100644 --- a/src/platform/windows/event.rs +++ b/src/platform/windows/event.rs @@ -1,14 +1,13 @@ +use std::char; +use std::os::raw::c_int; + use events::VirtualKeyCode; use events::ModifiersState; -use winapi::shared::minwindef::{WPARAM, LPARAM}; +use winapi::shared::minwindef::{WPARAM, LPARAM, UINT}; use winapi::um::winuser; use ScanCode; -use std::char; - -const MAPVK_VK_TO_CHAR: u32 = 2; -const MAPVK_VSC_TO_VK_EX: u32 = 3; pub fn get_key_mods() -> ModifiersState { let mut mods = ModifiersState::default(); @@ -29,18 +28,9 @@ pub fn get_key_mods() -> ModifiersState { mods } -pub fn vkeycode_to_element(wparam: WPARAM, lparam: LPARAM) -> (ScanCode, Option) { - let scancode = ((lparam >> 16) & 0xff) as u32; - let extended = (lparam & 0x01000000) != 0; - let vk = match wparam as i32 { - winuser::VK_SHIFT => unsafe { winuser::MapVirtualKeyA(scancode, MAPVK_VSC_TO_VK_EX) as i32 }, - winuser::VK_CONTROL => if extended { winuser::VK_RCONTROL } else { winuser::VK_LCONTROL }, - winuser::VK_MENU => if extended { winuser::VK_RMENU } else { winuser::VK_LMENU }, - other => other - }; - +pub fn vkey_to_winit_vkey(vkey: c_int) -> Option { // VK_* codes are documented here https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx - (scancode, match vk { + match vkey { //winuser::VK_LBUTTON => Some(VirtualKeyCode::Lbutton), //winuser::VK_RBUTTON => Some(VirtualKeyCode::Rbutton), //winuser::VK_CANCEL => Some(VirtualKeyCode::Cancel), @@ -191,13 +181,13 @@ pub fn vkeycode_to_element(wparam: WPARAM, lparam: LPARAM) -> (ScanCode, Option< winuser::VK_OEM_COMMA => Some(VirtualKeyCode::Comma), winuser::VK_OEM_MINUS => Some(VirtualKeyCode::Minus), winuser::VK_OEM_PERIOD => Some(VirtualKeyCode::Period), - winuser::VK_OEM_1 => map_text_keys(vk), - winuser::VK_OEM_2 => map_text_keys(vk), - winuser::VK_OEM_3 => map_text_keys(vk), - winuser::VK_OEM_4 => map_text_keys(vk), - winuser::VK_OEM_5 => map_text_keys(vk), - winuser::VK_OEM_6 => map_text_keys(vk), - winuser::VK_OEM_7 => map_text_keys(vk), + winuser::VK_OEM_1 => map_text_keys(vkey), + winuser::VK_OEM_2 => map_text_keys(vkey), + winuser::VK_OEM_3 => map_text_keys(vkey), + winuser::VK_OEM_4 => map_text_keys(vkey), + winuser::VK_OEM_5 => map_text_keys(vkey), + winuser::VK_OEM_6 => map_text_keys(vkey), + winuser::VK_OEM_7 => map_text_keys(vkey), /*winuser::VK_OEM_8 => Some(VirtualKeyCode::Oem_8), */ winuser::VK_OEM_102 => Some(VirtualKeyCode::OEM102), /*winuser::VK_PROCESSKEY => Some(VirtualKeyCode::Processkey), @@ -212,13 +202,40 @@ pub fn vkeycode_to_element(wparam: WPARAM, lparam: LPARAM) -> (ScanCode, Option< winuser::VK_PA1 => Some(VirtualKeyCode::Pa1), winuser::VK_OEM_CLEAR => Some(VirtualKeyCode::Oem_clear),*/ _ => None - }) + } +} + +pub fn vkey_left_right(vkey: c_int, scancode: UINT, extended: bool) -> c_int { + match vkey { + winuser::VK_SHIFT => unsafe { winuser::MapVirtualKeyA( + scancode, + winuser::MAPVK_VSC_TO_VK_EX, + ) as _ }, + winuser::VK_CONTROL => if extended { + winuser::VK_RCONTROL + } else { + winuser::VK_LCONTROL + }, + winuser::VK_MENU => if extended { + winuser::VK_RMENU + } else { + winuser::VK_LMENU + }, + _ => vkey, + } +} + +pub fn vkeycode_to_element(wparam: WPARAM, lparam: LPARAM) -> (ScanCode, Option) { + let scancode = ((lparam >> 16) & 0xff) as UINT; + let extended = (lparam & 0x01000000) != 0; + let vkey = vkey_left_right(wparam as _, scancode, extended); + (scancode, vkey_to_winit_vkey(vkey)) } // This is needed as windows doesn't properly distinguish // some virtual key codes for different keyboard layouts fn map_text_keys(win_virtual_key: i32) -> Option { - let char_key = unsafe { winuser::MapVirtualKeyA(win_virtual_key as u32, MAPVK_VK_TO_CHAR) } & 0x7FFF; + let char_key = unsafe { winuser::MapVirtualKeyA(win_virtual_key as u32, winuser::MAPVK_VK_TO_CHAR) } & 0x7FFF; match char::from_u32(char_key) { Some(';') => Some(VirtualKeyCode::Semicolon), Some('/') => Some(VirtualKeyCode::Slash), diff --git a/src/platform/windows/events_loop.rs b/src/platform/windows/events_loop.rs index 6f1af175c0d..4dad894c4b1 100644 --- a/src/platform/windows/events_loop.rs +++ b/src/platform/windows/events_loop.rs @@ -30,13 +30,13 @@ use winapi::shared::minwindef::{LOWORD, HIWORD, DWORD, WPARAM, LPARAM, INT, UINT use winapi::shared::windef::{HWND, POINT, RECT}; use winapi::shared::windowsx; use winapi::um::{winuser, shellapi, processthreadsapi}; -use winapi::um::winnt::LONG; +use winapi::um::winnt::{LONG, SHORT}; -use platform::platform::event; +use events::DeviceEvent; +use platform::platform::{event, Cursor, WindowId, DEVICE_ID, wrap_device_id, util}; +use platform::platform::event::{vkey_to_winit_vkey, vkey_left_right}; +use platform::platform::raw_input::*; use platform::platform::window::adjust_size; -use platform::platform::Cursor; -use platform::platform::WindowId; -use platform::platform::DEVICE_ID; use ControlFlow; use CursorState; @@ -55,7 +55,7 @@ pub struct SavedWindowInfo { pub style: LONG, /// Window ex-style pub ex_style: LONG, - /// Window position and size + /// Window position and size pub rect: RECT, } @@ -396,7 +396,7 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT, context_stash.as_mut().unwrap().windows.remove(&window); }); winuser::DefWindowProcW(window, msg, wparam, lparam) - }, + }, winuser::WM_PAINT => { use events::WindowEvent::Refresh; @@ -546,7 +546,6 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT, }, winuser::WM_MOUSEWHEEL => { - use events::{DeviceEvent, WindowEvent}; use events::MouseScrollDelta::LineDelta; use events::TouchPhase; @@ -559,11 +558,6 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT, event: WindowEvent::MouseWheel { device_id: DEVICE_ID, delta: LineDelta(0.0, value), phase: TouchPhase::Moved, modifiers: event::get_key_mods() }, }); - send_event(Event::DeviceEvent { - device_id: DEVICE_ID, - event: DeviceEvent::MouseWheel { delta: LineDelta(0.0, value) }, - }); - 0 }, @@ -730,46 +724,121 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT, 0 }, + winuser::WM_INPUT_DEVICE_CHANGE => { + let event = match wparam as _ { + winuser::GIDC_ARRIVAL => DeviceEvent::Added, + winuser::GIDC_REMOVAL => DeviceEvent::Removed, + _ => unreachable!(), + }; + + send_event(Event::DeviceEvent { + device_id: wrap_device_id(lparam as _), + event, + }); + + winuser::DefWindowProcW(window, msg, wparam, lparam) + }, + winuser::WM_INPUT => { - use events::DeviceEvent::{Motion, MouseMotion}; - let mut data: winuser::RAWINPUT = mem::uninitialized(); - let mut data_size = mem::size_of::() as UINT; - winuser::GetRawInputData(mem::transmute(lparam), winuser::RID_INPUT, - mem::transmute(&mut data), &mut data_size, - mem::size_of::() as UINT); - - if data.header.dwType == winuser::RIM_TYPEMOUSE { - let mouse = data.data.mouse(); - if mouse.usFlags & winuser::MOUSE_MOVE_RELATIVE == winuser::MOUSE_MOVE_RELATIVE { - let x = mouse.lLastX as f64; - let y = mouse.lLastY as f64; - - if x != 0.0 { - send_event(Event::DeviceEvent { - device_id: DEVICE_ID, - event: Motion { axis: 0, value: x } - }); + use events::DeviceEvent::{Motion, MouseMotion, MouseWheel, Button, Key}; + use events::MouseScrollDelta::LineDelta; + use events::ElementState::{Pressed, Released}; + + if let Some(data) = get_raw_input_data(lparam as _) { + let device_id = wrap_device_id(data.header.hDevice as _); + + if data.header.dwType == winuser::RIM_TYPEMOUSE { + let mouse = data.data.mouse(); + + if util::has_flag(mouse.usFlags, winuser::MOUSE_MOVE_RELATIVE) { + let x = mouse.lLastX as f64; + let y = mouse.lLastY as f64; + + if x != 0.0 { + send_event(Event::DeviceEvent { + device_id, + event: Motion { axis: 0, value: x } + }); + } + + if y != 0.0 { + send_event(Event::DeviceEvent { + device_id, + event: Motion { axis: 1, value: y } + }); + } + + if x != 0.0 || y != 0.0 { + send_event(Event::DeviceEvent { + device_id, + event: MouseMotion { delta: (x, y) } + }); + } } - if y != 0.0 { + if util::has_flag(mouse.usButtonFlags, winuser::RI_MOUSE_WHEEL) { + let delta = mouse.usButtonData as SHORT / winuser::WHEEL_DELTA; send_event(Event::DeviceEvent { - device_id: DEVICE_ID, - event: Motion { axis: 1, value: y } + device_id, + event: MouseWheel { delta: LineDelta(0.0, delta as f32) } }); } - if x != 0.0 || y != 0.0 { + let button_state = get_raw_mouse_button_state(mouse.usButtonFlags); + // Left, middle, and right, respectively. + for (index, state) in button_state.iter().enumerate() { + if let Some(state) = *state { + // This gives us consistency with X11, since there doesn't + // seem to be anything else reasonable to do for a mouse + // button ID. + let button = (index + 1) as _; + send_event(Event::DeviceEvent { + device_id, + event: Button { + button, + state, + } + }); + } + } + } else if data.header.dwType == winuser::RIM_TYPEKEYBOARD { + let keyboard = data.data.keyboard(); + + let pressed = keyboard.Message == winuser::WM_KEYDOWN + || keyboard.Message == winuser::WM_SYSKEYDOWN; + let released = keyboard.Message == winuser::WM_KEYUP + || keyboard.Message == winuser::WM_SYSKEYUP; + + if pressed || released { + let state = if pressed { + Pressed + } else { + Released + }; + + let scancode = keyboard.MakeCode as _; + let extended = util::has_flag(keyboard.Flags, winuser::RI_KEY_E0 as _); + let vkey = vkey_left_right( + keyboard.VKey as _, + scancode, + extended, + ); + let virtual_keycode = vkey_to_winit_vkey(vkey); + send_event(Event::DeviceEvent { - device_id: DEVICE_ID, - event: MouseMotion { delta: (x, y) } + device_id, + event: Key(KeyboardInput { + scancode, + state, + virtual_keycode, + modifiers: event::get_key_mods(), + }), }); } } - - 0 - } else { - winuser::DefWindowProcW(window, msg, wparam, lparam) } + + winuser::DefWindowProcW(window, msg, wparam, lparam) }, winuser::WM_TOUCH => { diff --git a/src/platform/windows/mod.rs b/src/platform/windows/mod.rs index 19f2c021492..0ea6ab886ba 100644 --- a/src/platform/windows/mod.rs +++ b/src/platform/windows/mod.rs @@ -18,10 +18,25 @@ unsafe impl Sync for PlatformSpecificWindowBuilderAttributes {} // TODO: document what this means pub type Cursor = *const winapi::ctypes::wchar_t; -// Constant device ID, to be removed when this backend is updated to report real device IDs. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct DeviceId; -const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId); +pub struct DeviceId(u32); + +impl DeviceId { + pub fn get_persistent_identifier(&self) -> Option { + if self.0 != 0 { + raw_input::get_raw_input_device_name(self.0 as _) + } else { + None + } + } +} + +// Constant device ID, to be removed when this backend is updated to report real device IDs. +const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId(0)); + +fn wrap_device_id(id: u32) -> ::DeviceId { + ::DeviceId(DeviceId(id)) +} #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct WindowId(HWND); @@ -31,4 +46,6 @@ unsafe impl Sync for WindowId {} mod event; mod events_loop; mod monitor; +mod raw_input; +mod util; mod window; diff --git a/src/platform/windows/monitor.rs b/src/platform/windows/monitor.rs index 4f9eaadd416..92e9dd30462 100644 --- a/src/platform/windows/monitor.rs +++ b/src/platform/windows/monitor.rs @@ -6,7 +6,7 @@ use winapi::um::winuser; use std::collections::VecDeque; use std::{mem, ptr}; -use super::EventsLoop; +use super::{EventsLoop, util}; /// Win32 implementation of the main `MonitorId` object. #[derive(Clone)] @@ -44,12 +44,6 @@ struct HMonitor(HMONITOR); unsafe impl Send for HMonitor {} -fn wchar_as_string(wchar: &[wchar_t]) -> String { - String::from_utf16_lossy(wchar) - .trim_right_matches(0 as char) - .to_string() -} - unsafe extern "system" fn monitor_enum_proc(hmonitor: HMONITOR, _: HDC, place: LPRECT, data: LPARAM) -> BOOL { let monitors = data as *mut VecDeque; @@ -67,7 +61,7 @@ unsafe extern "system" fn monitor_enum_proc(hmonitor: HMONITOR, _: HDC, place: L (*monitors).push_back(MonitorId { adapter_name: monitor_info.szDevice, hmonitor: HMonitor(hmonitor), - monitor_name: wchar_as_string(&monitor_info.szDevice), + monitor_name: util::wchar_to_string(&monitor_info.szDevice), primary: monitor_info.dwFlags & winuser::MONITORINFOF_PRIMARY != 0, position, dimensions, @@ -109,7 +103,7 @@ impl EventsLoop { MonitorId { adapter_name: monitor_info.szDevice, hmonitor: super::monitor::HMonitor(hmonitor), - monitor_name: wchar_as_string(&monitor_info.szDevice), + monitor_name: util::wchar_to_string(&monitor_info.szDevice), primary: monitor_info.dwFlags & winuser::MONITORINFOF_PRIMARY != 0, position, dimensions, diff --git a/src/platform/windows/raw_input.rs b/src/platform/windows/raw_input.rs new file mode 100644 index 00000000000..2f6e90594f6 --- /dev/null +++ b/src/platform/windows/raw_input.rs @@ -0,0 +1,235 @@ +use std::mem::{self, size_of}; +use std::ptr; + +use winapi::ctypes::wchar_t; +use winapi::shared::minwindef::{UINT, USHORT, TRUE}; +use winapi::shared::hidusage::{ + HID_USAGE_PAGE_GENERIC, + HID_USAGE_GENERIC_MOUSE, + HID_USAGE_GENERIC_KEYBOARD, +}; +use winapi::shared::windef::HWND; +use winapi::um::winnt::HANDLE; +use winapi::um::winuser::{ + self, + RAWINPUTDEVICELIST, + RID_DEVICE_INFO, + RID_DEVICE_INFO_MOUSE, + RID_DEVICE_INFO_KEYBOARD, + RID_DEVICE_INFO_HID, + RIM_TYPEMOUSE, + RIM_TYPEKEYBOARD, + RIM_TYPEHID, + RIDI_DEVICEINFO, + RIDI_DEVICENAME, + RAWINPUTDEVICE, + RIDEV_DEVNOTIFY, + RIDEV_INPUTSINK, + HRAWINPUT, + RAWINPUT, + RAWINPUTHEADER, + RID_INPUT, +}; + +use platform::platform::util; +use events::ElementState; + +#[allow(dead_code)] +pub fn get_raw_input_device_list() -> Option> { + let list_size = size_of::() as UINT; + + let mut num_devices = 0; + let status = unsafe { winuser::GetRawInputDeviceList( + ptr::null_mut(), + &mut num_devices, + list_size, + ) }; + + if status == UINT::max_value() { + return None; + } + + let mut buffer = Vec::with_capacity(num_devices as _); + + let num_stored = unsafe { winuser::GetRawInputDeviceList( + buffer.as_ptr() as _, + &mut num_devices, + list_size, + ) }; + + if num_stored == UINT::max_value() { + return None; + } + + debug_assert_eq!(num_devices, num_stored); + + unsafe { buffer.set_len(num_devices as _) }; + + Some(buffer) +} + +#[allow(dead_code)] +pub enum RawDeviceInfo { + Mouse(RID_DEVICE_INFO_MOUSE), + Keyboard(RID_DEVICE_INFO_KEYBOARD), + Hid(RID_DEVICE_INFO_HID), +} + +impl From for RawDeviceInfo { + fn from(info: RID_DEVICE_INFO) -> Self { + unsafe { + match info.dwType { + RIM_TYPEMOUSE => RawDeviceInfo::Mouse(*info.u.mouse()), + RIM_TYPEKEYBOARD => RawDeviceInfo::Keyboard(*info.u.keyboard()), + RIM_TYPEHID => RawDeviceInfo::Hid(*info.u.hid()), + _ => unreachable!(), + } + } + } +} + +#[allow(dead_code)] +pub fn get_raw_input_device_info(handle: HANDLE) -> Option { + let mut info: RID_DEVICE_INFO = unsafe { mem::uninitialized() }; + let info_size = size_of::() as UINT; + + info.cbSize = info_size; + + let mut minimum_size = 0; + let status = unsafe { winuser::GetRawInputDeviceInfoW( + handle, + RIDI_DEVICEINFO, + &mut info as *mut _ as _, + &mut minimum_size, + ) }; + + if status == UINT::max_value() || status == 0 { + return None; + } + + debug_assert_eq!(info_size, status); + + Some(info.into()) +} + +pub fn get_raw_input_device_name(handle: HANDLE) -> Option { + let mut minimum_size = 0; + let status = unsafe { winuser::GetRawInputDeviceInfoW( + handle, + RIDI_DEVICENAME, + ptr::null_mut(), + &mut minimum_size, + ) }; + + if status != 0 { + return None; + } + + let mut name: Vec = Vec::with_capacity(minimum_size as _); + + let status = unsafe { winuser::GetRawInputDeviceInfoW( + handle, + RIDI_DEVICENAME, + name.as_ptr() as _, + &mut minimum_size, + ) }; + + if status == UINT::max_value() || status == 0 { + return None; + } + + debug_assert_eq!(minimum_size, status); + + unsafe { name.set_len(minimum_size as _) }; + + Some(util::wchar_to_string(&name)) +} + +pub fn register_raw_input_devices(devices: &[RAWINPUTDEVICE]) -> bool { + let device_size = size_of::() as UINT; + + let success = unsafe { winuser::RegisterRawInputDevices( + devices.as_ptr() as _, + devices.len() as _, + device_size, + ) }; + + success == TRUE +} + +pub fn register_all_mice_and_keyboards_for_raw_input(window_handle: HWND) -> bool { + // RIDEV_DEVNOTIFY: receive hotplug events + // RIDEV_INPUTSINK: receive events even if we're not in the foreground + let flags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; + + let devices: [RAWINPUTDEVICE; 2] = [ + RAWINPUTDEVICE { + usUsagePage: HID_USAGE_PAGE_GENERIC, + usUsage: HID_USAGE_GENERIC_MOUSE, + dwFlags: flags, + hwndTarget: window_handle, + }, + RAWINPUTDEVICE { + usUsagePage: HID_USAGE_PAGE_GENERIC, + usUsage: HID_USAGE_GENERIC_KEYBOARD, + dwFlags: flags, + hwndTarget: window_handle, + }, + ]; + + register_raw_input_devices(&devices) +} + +pub fn get_raw_input_data(handle: HRAWINPUT) -> Option { + let mut data: RAWINPUT = unsafe { mem::uninitialized() }; + let mut data_size = size_of::() as UINT; + let header_size = size_of::() as UINT; + + let status = unsafe { winuser::GetRawInputData( + handle, + RID_INPUT, + &mut data as *mut _ as _, + &mut data_size, + header_size, + ) }; + + if status == UINT::max_value() || status == 0 { + return None; + } + + Some(data) +} + + +fn button_flags_to_element_state(button_flags: USHORT, down_flag: USHORT, up_flag: USHORT) + -> Option +{ + // We assume the same button won't be simultaneously pressed and released. + if util::has_flag(button_flags, down_flag) { + Some(ElementState::Pressed) + } else if util::has_flag(button_flags, up_flag) { + Some(ElementState::Released) + } else { + None + } +} + +pub fn get_raw_mouse_button_state(button_flags: USHORT) -> [Option; 3] { + [ + button_flags_to_element_state( + button_flags, + winuser::RI_MOUSE_LEFT_BUTTON_DOWN, + winuser::RI_MOUSE_LEFT_BUTTON_UP, + ), + button_flags_to_element_state( + button_flags, + winuser::RI_MOUSE_MIDDLE_BUTTON_DOWN, + winuser::RI_MOUSE_MIDDLE_BUTTON_UP, + ), + button_flags_to_element_state( + button_flags, + winuser::RI_MOUSE_RIGHT_BUTTON_DOWN, + winuser::RI_MOUSE_RIGHT_BUTTON_UP, + ), + ] +} diff --git a/src/platform/windows/util.rs b/src/platform/windows/util.rs new file mode 100644 index 00000000000..3377a542921 --- /dev/null +++ b/src/platform/windows/util.rs @@ -0,0 +1,16 @@ +use std::ops::BitAnd; + +use winapi::ctypes::wchar_t; + +pub fn has_flag(bitset: T, flag: T) -> bool +where T: + Copy + PartialEq + BitAnd +{ + bitset & flag == flag +} + +pub fn wchar_to_string(wchar: &[wchar_t]) -> String { + String::from_utf16_lossy(wchar) + .trim_right_matches(0 as char) + .to_string() +} diff --git a/src/platform/windows/window.rs b/src/platform/windows/window.rs index df426df883a..212244bab61 100644 --- a/src/platform/windows/window.rs +++ b/src/platform/windows/window.rs @@ -14,6 +14,7 @@ use std::cell::Cell; use platform::platform::events_loop; use platform::platform::EventsLoop; use platform::platform::PlatformSpecificWindowBuilderAttributes; +use platform::platform::raw_input::register_all_mice_and_keyboards_for_raw_input; use platform::platform::WindowId; use CreationError; @@ -24,7 +25,6 @@ use MonitorId as RootMonitorId; use winapi::shared::minwindef::{UINT, DWORD, BOOL}; use winapi::shared::windef::{HWND, HDC, RECT, POINT}; -use winapi::shared::hidusage; use winapi::um::{winuser, dwmapi, libloaderapi, processthreadsapi}; use winapi::um::winnt::{LPCWSTR, LONG, HRESULT}; use winapi::um::combaseapi; @@ -47,14 +47,14 @@ unsafe impl Send for Window {} unsafe impl Sync for Window {} // https://blogs.msdn.microsoft.com/oldnewthing/20131017-00/?p=2903 -// The idea here is that we use the Adjust­Window­Rect­Ex function to calculate how much additional -// non-client area gets added due to the styles we passed. To make the math simple, -// we ask for a zero client rectangle, so that the resulting window is all non-client. -// And then we pass in the empty rectangle represented by the dot in the middle, -// and the Adjust­Window­Rect­Ex expands the rectangle in all dimensions. -// We see that it added ten pixels to the left, right, and bottom, +// The idea here is that we use the Adjust­Window­Rect­Ex function to calculate how much additional +// non-client area gets added due to the styles we passed. To make the math simple, +// we ask for a zero client rectangle, so that the resulting window is all non-client. +// And then we pass in the empty rectangle represented by the dot in the middle, +// and the Adjust­Window­Rect­Ex expands the rectangle in all dimensions. +// We see that it added ten pixels to the left, right, and bottom, // and it added fifty pixels to the top. -// From this we can perform the reverse calculation: Instead of expanding the rectangle, we shrink it. +// From this we can perform the reverse calculation: Instead of expanding the rectangle, we shrink it. unsafe fn unjust_window_rect(prc: &mut RECT, style: DWORD, ex_style: DWORD) -> BOOL { let mut rc: RECT = mem::zeroed(); @@ -67,7 +67,7 @@ unsafe fn unjust_window_rect(prc: &mut RECT, style: DWORD, ex_style: DWORD) -> B prc.right -= rc.right; prc.bottom -= rc.bottom; } - + frc } @@ -378,13 +378,13 @@ impl Window { pub fn set_maximized(&self, maximized: bool) { let mut window_state = self.window_state.lock().unwrap(); - window_state.attributes.maximized = maximized; + window_state.attributes.maximized = maximized; // we only maximized if we are not in fullscreen if window_state.attributes.fullscreen.is_some() { return; } - - let window = self.window.clone(); + + let window = self.window.clone(); unsafe { // And because ShowWindow will resize the window // We call it in the main thread @@ -731,16 +731,8 @@ unsafe fn init(window: WindowAttributes, pl_attribs: PlatformSpecificWindowBuild WindowWrapper(handle, hdc) }; - // Set up raw mouse input - { - let mut rid: winuser::RAWINPUTDEVICE = mem::uninitialized(); - rid.usUsagePage = hidusage::HID_USAGE_PAGE_GENERIC; - rid.usUsage = hidusage::HID_USAGE_GENERIC_MOUSE; - rid.dwFlags = 0; - rid.hwndTarget = real_window.0; - - winuser::RegisterRawInputDevices(&rid, 1, mem::size_of::() as u32); - } + // Set up raw input + register_all_mice_and_keyboards_for_raw_input(real_window.0); // Register for touch events if applicable { @@ -749,7 +741,7 @@ unsafe fn init(window: WindowAttributes, pl_attribs: PlatformSpecificWindowBuild winuser::RegisterTouchWindow( real_window.0, winuser::TWF_WANTPALM ); } } - + // Creating a mutex to track the current window state let window_state = Arc::new(Mutex::new(events_loop::WindowState { cursor: winuser::IDC_ARROW, // use arrow by default @@ -770,7 +762,7 @@ unsafe fn init(window: WindowAttributes, pl_attribs: PlatformSpecificWindowBuild dwmapi::DwmEnableBlurBehindWindow(real_window.0, &bb); } - + let win = Window { window: real_window, window_state: window_state, @@ -784,7 +776,7 @@ unsafe fn init(window: WindowAttributes, pl_attribs: PlatformSpecificWindowBuild } inserter.insert(win.window.0, win.window_state.clone()); - + Ok(win) } @@ -824,7 +816,7 @@ impl Drop for ComInitialized { } } -thread_local!{ +thread_local!{ static COM_INITIALIZED: ComInitialized = { unsafe { combaseapi::CoInitializeEx(ptr::null_mut(), COINIT_MULTITHREADED); @@ -871,7 +863,7 @@ mod taskbar { fn MarkFullscreenWindow( hwnd: HWND, fFullscreen: BOOL, - ) -> HRESULT, + ) -> HRESULT, }); }