Add hotkey detection implementation to Windows
This commit is contained in:
		
							parent
							
								
									89805a0248
								
							
						
					
					
						commit
						474eae69d5
					
				| 
						 | 
				
			
			@ -16,6 +16,7 @@ lazycell = "1.3.0"
 | 
			
		|||
anyhow = "1.0.38"
 | 
			
		||||
thiserror = "1.0.23"
 | 
			
		||||
regex = "1.4.3"
 | 
			
		||||
lazy_static = "1.4.0"
 | 
			
		||||
 | 
			
		||||
[target.'cfg(windows)'.dependencies]
 | 
			
		||||
widestring = "0.4.3"
 | 
			
		||||
| 
						 | 
				
			
			@ -24,9 +25,6 @@ widestring = "0.4.3"
 | 
			
		|||
libc = "0.2.85"
 | 
			
		||||
scopeguard = "1.1.0"
 | 
			
		||||
 | 
			
		||||
[target.'cfg(target_os="macos")'.dependencies]
 | 
			
		||||
lazy_static = "1.4.0"
 | 
			
		||||
 | 
			
		||||
[build-dependencies]
 | 
			
		||||
cc = "1.0.66"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -415,94 +415,89 @@ impl ShortcutKey {
 | 
			
		|||
  #[cfg(target_os = "windows")]
 | 
			
		||||
  pub fn to_code(&self) -> Option<u32> {
 | 
			
		||||
    let vkey = match self {
 | 
			
		||||
      Key::Alt => 0x12,
 | 
			
		||||
      Key::CapsLock => 0x14,
 | 
			
		||||
      Key::Control => 0x11,
 | 
			
		||||
      Key::Meta => 0x5B,
 | 
			
		||||
      Key::NumLock => 0x90,
 | 
			
		||||
      Key::Shift => 0xA0,
 | 
			
		||||
      Key::Enter => 0x0D,
 | 
			
		||||
      Key::Tab => 0x09,
 | 
			
		||||
      Key::Space => 0x20,
 | 
			
		||||
      Key::ArrowDown => 0x28,
 | 
			
		||||
      Key::ArrowLeft => 0x25,
 | 
			
		||||
      Key::ArrowRight => 0x27,
 | 
			
		||||
      Key::ArrowUp => 0x26,
 | 
			
		||||
      Key::End => 0x23,
 | 
			
		||||
      Key::Home => 0x24,
 | 
			
		||||
      Key::PageDown => 0x22,
 | 
			
		||||
      Key::PageUp => 0x21,
 | 
			
		||||
      Key::Escape => 0x1B,
 | 
			
		||||
      Key::Backspace => 0x08,
 | 
			
		||||
      Key::Insert => 0x2D,
 | 
			
		||||
      Key::Delete => 0x2E,
 | 
			
		||||
      Key::F1 => 0x70,
 | 
			
		||||
      Key::F2 => 0x71,
 | 
			
		||||
      Key::F3 => 0x72,
 | 
			
		||||
      Key::F4 => 0x73,
 | 
			
		||||
      Key::F5 => 0x74,
 | 
			
		||||
      Key::F6 => 0x75,
 | 
			
		||||
      Key::F7 => 0x76,
 | 
			
		||||
      Key::F8 => 0x77,
 | 
			
		||||
      Key::F9 => 0x78,
 | 
			
		||||
      Key::F10 => 0x79,
 | 
			
		||||
      Key::F11 => 0x7A,
 | 
			
		||||
      Key::F12 => 0x7B,
 | 
			
		||||
      Key::F13 => 0x7C,
 | 
			
		||||
      Key::F14 => 0x7D,
 | 
			
		||||
      Key::F15 => 0x7E,
 | 
			
		||||
      Key::F16 => 0x7F,
 | 
			
		||||
      Key::F17 => 0x80,
 | 
			
		||||
      Key::F18 => 0x81,
 | 
			
		||||
      Key::F19 => 0x82,
 | 
			
		||||
      Key::F20 => 0x83,
 | 
			
		||||
      Key::A => 0x41,
 | 
			
		||||
      Key::B => 0x42,
 | 
			
		||||
      Key::C => 0x43,
 | 
			
		||||
      Key::D => 0x44,
 | 
			
		||||
      Key::E => 0x45,
 | 
			
		||||
      Key::F => 0x46,
 | 
			
		||||
      Key::G => 0x47,
 | 
			
		||||
      Key::H => 0x48,
 | 
			
		||||
      Key::I => 0x49,
 | 
			
		||||
      Key::J => 0x4A,
 | 
			
		||||
      Key::K => 0x4B,
 | 
			
		||||
      Key::L => 0x4C,
 | 
			
		||||
      Key::M => 0x4D,
 | 
			
		||||
      Key::N => 0x4E,
 | 
			
		||||
      Key::O => 0x4F,
 | 
			
		||||
      Key::P => 0x50,
 | 
			
		||||
      Key::Q => 0x51,
 | 
			
		||||
      Key::R => 0x52,
 | 
			
		||||
      Key::S => 0x53,
 | 
			
		||||
      Key::T => 0x54,
 | 
			
		||||
      Key::U => 0x55,
 | 
			
		||||
      Key::V => 0x56,
 | 
			
		||||
      Key::W => 0x57,
 | 
			
		||||
      Key::X => 0x58,
 | 
			
		||||
      Key::Y => 0x59,
 | 
			
		||||
      Key::Z => 0x5A,
 | 
			
		||||
      Key::N0 => 0x30,
 | 
			
		||||
      Key::N1 => 0x31,
 | 
			
		||||
      Key::N2 => 0x32,
 | 
			
		||||
      Key::N3 => 0x33,
 | 
			
		||||
      Key::N4 => 0x34,
 | 
			
		||||
      Key::N5 => 0x35,
 | 
			
		||||
      Key::N6 => 0x36,
 | 
			
		||||
      Key::N7 => 0x37,
 | 
			
		||||
      Key::N8 => 0x38,
 | 
			
		||||
      Key::N9 => 0x39,
 | 
			
		||||
      Key::Numpad0 => 0x60,
 | 
			
		||||
      Key::Numpad1 => 0x61,
 | 
			
		||||
      Key::Numpad2 => 0x62,
 | 
			
		||||
      Key::Numpad3 => 0x63,
 | 
			
		||||
      Key::Numpad4 => 0x64,
 | 
			
		||||
      Key::Numpad5 => 0x65,
 | 
			
		||||
      Key::Numpad6 => 0x66,
 | 
			
		||||
      Key::Numpad7 => 0x67,
 | 
			
		||||
      Key::Numpad8 => 0x68,
 | 
			
		||||
      Key::Numpad9 => 0x69,
 | 
			
		||||
      Key::Raw(code) => *code,
 | 
			
		||||
      ShortcutKey::Alt => 0x12,
 | 
			
		||||
      ShortcutKey::Control => 0x11,
 | 
			
		||||
      ShortcutKey::Meta => 0x5B,
 | 
			
		||||
      ShortcutKey::Shift => 0xA0,
 | 
			
		||||
      ShortcutKey::Enter => 0x0D,
 | 
			
		||||
      ShortcutKey::Tab => 0x09,
 | 
			
		||||
      ShortcutKey::Space => 0x20,
 | 
			
		||||
      ShortcutKey::ArrowDown => 0x28,
 | 
			
		||||
      ShortcutKey::ArrowLeft => 0x25,
 | 
			
		||||
      ShortcutKey::ArrowRight => 0x27,
 | 
			
		||||
      ShortcutKey::ArrowUp => 0x26,
 | 
			
		||||
      ShortcutKey::End => 0x23,
 | 
			
		||||
      ShortcutKey::Home => 0x24,
 | 
			
		||||
      ShortcutKey::PageDown => 0x22,
 | 
			
		||||
      ShortcutKey::PageUp => 0x21,
 | 
			
		||||
      ShortcutKey::Insert => 0x2D,
 | 
			
		||||
      ShortcutKey::F1 => 0x70,
 | 
			
		||||
      ShortcutKey::F2 => 0x71,
 | 
			
		||||
      ShortcutKey::F3 => 0x72,
 | 
			
		||||
      ShortcutKey::F4 => 0x73,
 | 
			
		||||
      ShortcutKey::F5 => 0x74,
 | 
			
		||||
      ShortcutKey::F6 => 0x75,
 | 
			
		||||
      ShortcutKey::F7 => 0x76,
 | 
			
		||||
      ShortcutKey::F8 => 0x77,
 | 
			
		||||
      ShortcutKey::F9 => 0x78,
 | 
			
		||||
      ShortcutKey::F10 => 0x79,
 | 
			
		||||
      ShortcutKey::F11 => 0x7A,
 | 
			
		||||
      ShortcutKey::F12 => 0x7B,
 | 
			
		||||
      ShortcutKey::F13 => 0x7C,
 | 
			
		||||
      ShortcutKey::F14 => 0x7D,
 | 
			
		||||
      ShortcutKey::F15 => 0x7E,
 | 
			
		||||
      ShortcutKey::F16 => 0x7F,
 | 
			
		||||
      ShortcutKey::F17 => 0x80,
 | 
			
		||||
      ShortcutKey::F18 => 0x81,
 | 
			
		||||
      ShortcutKey::F19 => 0x82,
 | 
			
		||||
      ShortcutKey::F20 => 0x83,
 | 
			
		||||
      ShortcutKey::A => 0x41,
 | 
			
		||||
      ShortcutKey::B => 0x42,
 | 
			
		||||
      ShortcutKey::C => 0x43,
 | 
			
		||||
      ShortcutKey::D => 0x44,
 | 
			
		||||
      ShortcutKey::E => 0x45,
 | 
			
		||||
      ShortcutKey::F => 0x46,
 | 
			
		||||
      ShortcutKey::G => 0x47,
 | 
			
		||||
      ShortcutKey::H => 0x48,
 | 
			
		||||
      ShortcutKey::I => 0x49,
 | 
			
		||||
      ShortcutKey::J => 0x4A,
 | 
			
		||||
      ShortcutKey::K => 0x4B,
 | 
			
		||||
      ShortcutKey::L => 0x4C,
 | 
			
		||||
      ShortcutKey::M => 0x4D,
 | 
			
		||||
      ShortcutKey::N => 0x4E,
 | 
			
		||||
      ShortcutKey::O => 0x4F,
 | 
			
		||||
      ShortcutKey::P => 0x50,
 | 
			
		||||
      ShortcutKey::Q => 0x51,
 | 
			
		||||
      ShortcutKey::R => 0x52,
 | 
			
		||||
      ShortcutKey::S => 0x53,
 | 
			
		||||
      ShortcutKey::T => 0x54,
 | 
			
		||||
      ShortcutKey::U => 0x55,
 | 
			
		||||
      ShortcutKey::V => 0x56,
 | 
			
		||||
      ShortcutKey::W => 0x57,
 | 
			
		||||
      ShortcutKey::X => 0x58,
 | 
			
		||||
      ShortcutKey::Y => 0x59,
 | 
			
		||||
      ShortcutKey::Z => 0x5A,
 | 
			
		||||
      ShortcutKey::N0 => 0x30,
 | 
			
		||||
      ShortcutKey::N1 => 0x31,
 | 
			
		||||
      ShortcutKey::N2 => 0x32,
 | 
			
		||||
      ShortcutKey::N3 => 0x33,
 | 
			
		||||
      ShortcutKey::N4 => 0x34,
 | 
			
		||||
      ShortcutKey::N5 => 0x35,
 | 
			
		||||
      ShortcutKey::N6 => 0x36,
 | 
			
		||||
      ShortcutKey::N7 => 0x37,
 | 
			
		||||
      ShortcutKey::N8 => 0x38,
 | 
			
		||||
      ShortcutKey::N9 => 0x39,
 | 
			
		||||
      ShortcutKey::Numpad0 => 0x60,
 | 
			
		||||
      ShortcutKey::Numpad1 => 0x61,
 | 
			
		||||
      ShortcutKey::Numpad2 => 0x62,
 | 
			
		||||
      ShortcutKey::Numpad3 => 0x63,
 | 
			
		||||
      ShortcutKey::Numpad4 => 0x64,
 | 
			
		||||
      ShortcutKey::Numpad5 => 0x65,
 | 
			
		||||
      ShortcutKey::Numpad6 => 0x66,
 | 
			
		||||
      ShortcutKey::Numpad7 => 0x67,
 | 
			
		||||
      ShortcutKey::Numpad8 => 0x68,
 | 
			
		||||
      ShortcutKey::Numpad9 => 0x69,
 | 
			
		||||
      ShortcutKey::Raw(code) => *code,
 | 
			
		||||
    };
 | 
			
		||||
    Some(vkey)
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,12 +19,18 @@
 | 
			
		|||
 | 
			
		||||
pub mod keys;
 | 
			
		||||
 | 
			
		||||
use std::fmt::Display;
 | 
			
		||||
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use keys::ShortcutKey;
 | 
			
		||||
use thiserror::Error;
 | 
			
		||||
 | 
			
		||||
static MODIFIERS: &[ShortcutKey; 4] = &[ShortcutKey::Control, ShortcutKey::Alt, ShortcutKey::Shift, ShortcutKey::Meta];
 | 
			
		||||
static MODIFIERS: &[ShortcutKey; 4] = &[
 | 
			
		||||
  ShortcutKey::Control,
 | 
			
		||||
  ShortcutKey::Alt,
 | 
			
		||||
  ShortcutKey::Shift,
 | 
			
		||||
  ShortcutKey::Meta,
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, PartialEq, Clone)]
 | 
			
		||||
pub struct HotKey {
 | 
			
		||||
| 
						 | 
				
			
			@ -33,7 +39,6 @@ pub struct HotKey {
 | 
			
		|||
  pub modifiers: Vec<ShortcutKey>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: test all methods
 | 
			
		||||
impl HotKey {
 | 
			
		||||
  pub fn new(id: i32, shortcut: &str) -> Result<Self> {
 | 
			
		||||
    let tokens: Vec<String> = shortcut
 | 
			
		||||
| 
						 | 
				
			
			@ -85,6 +90,19 @@ impl HotKey {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Display for HotKey {
 | 
			
		||||
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
			
		||||
    let str_modifiers: Vec<String> = self.modifiers.iter().map(|m| m.to_string()).collect();
 | 
			
		||||
    let modifiers = str_modifiers.join("+");
 | 
			
		||||
    write!(
 | 
			
		||||
      f,
 | 
			
		||||
      "{}+{}",
 | 
			
		||||
      &modifiers,
 | 
			
		||||
      &self.key
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Error, Debug)]
 | 
			
		||||
pub enum HotKeyError {
 | 
			
		||||
  #[error("invalid hotkey shortcut, `{0}` is not a valid key")]
 | 
			
		||||
| 
						 | 
				
			
			@ -100,16 +118,22 @@ mod tests {
 | 
			
		|||
 | 
			
		||||
  #[test]
 | 
			
		||||
  fn parse_correctly() {
 | 
			
		||||
    assert_eq!(HotKey::new(1, "CTRL+V").unwrap(), HotKey {
 | 
			
		||||
      id: 1,
 | 
			
		||||
      key: ShortcutKey::V,
 | 
			
		||||
      modifiers: vec![ShortcutKey::Control],
 | 
			
		||||
    });
 | 
			
		||||
    assert_eq!(HotKey::new(2, "SHIFT + Ctrl + v").unwrap(), HotKey {
 | 
			
		||||
      id: 2,
 | 
			
		||||
      key: ShortcutKey::V,
 | 
			
		||||
      modifiers: vec![ShortcutKey::Shift, ShortcutKey::Control],
 | 
			
		||||
    });
 | 
			
		||||
    assert_eq!(
 | 
			
		||||
      HotKey::new(1, "CTRL+V").unwrap(),
 | 
			
		||||
      HotKey {
 | 
			
		||||
        id: 1,
 | 
			
		||||
        key: ShortcutKey::V,
 | 
			
		||||
        modifiers: vec![ShortcutKey::Control],
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
    assert_eq!(
 | 
			
		||||
      HotKey::new(2, "SHIFT + Ctrl + v").unwrap(),
 | 
			
		||||
      HotKey {
 | 
			
		||||
        id: 2,
 | 
			
		||||
        key: ShortcutKey::V,
 | 
			
		||||
        modifiers: vec![ShortcutKey::Shift, ShortcutKey::Control],
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
    assert!(HotKey::new(3, "invalid").is_err());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -124,4 +148,4 @@ mod tests {
 | 
			
		|||
    assert!(!HotKey::new(1, "SHIFT+ V").unwrap().has_alt());
 | 
			
		||||
    assert!(!HotKey::new(1, "SHIFT+ V").unwrap().has_meta());
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,7 +37,6 @@ pub mod evdev;
 | 
			
		|||
#[cfg(target_os = "macos")]
 | 
			
		||||
pub mod mac;
 | 
			
		||||
 | 
			
		||||
#[cfg(target_os = "macos")]
 | 
			
		||||
#[macro_use]
 | 
			
		||||
extern crate lazy_static;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -85,9 +84,9 @@ impl Default for SourceCreationOptions {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(target_os = "windows")]
 | 
			
		||||
pub fn get_source(_options: SourceCreationOptions) -> Result<Box<dyn Source>> {
 | 
			
		||||
pub fn get_source(options: SourceCreationOptions) -> Result<Box<dyn Source>> {
 | 
			
		||||
  info!("using Win32Source");
 | 
			
		||||
  Ok(Box::new(win32::Win32Source::new()))
 | 
			
		||||
  Ok(Box::new(win32::Win32Source::new(&options.hotkeys)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(target_os = "macos")]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,16 +17,16 @@
 | 
			
		|||
 * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
use std::ffi::c_void;
 | 
			
		||||
use std::{convert::TryInto, ffi::c_void};
 | 
			
		||||
 | 
			
		||||
use lazycell::LazyCell;
 | 
			
		||||
use log::{error, trace, warn};
 | 
			
		||||
use log::{debug, error, trace, warn};
 | 
			
		||||
use widestring::U16CStr;
 | 
			
		||||
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use thiserror::Error;
 | 
			
		||||
 | 
			
		||||
use crate::event::Variant::*;
 | 
			
		||||
use crate::{event::{HotKeyEvent, Variant::*}, hotkey::{HotKey}};
 | 
			
		||||
use crate::event::{InputEvent, Key, KeyboardEvent, Variant};
 | 
			
		||||
use crate::event::{Key::*, MouseButton, MouseEvent};
 | 
			
		||||
use crate::{event::Status::*, Source, SourceCallback};
 | 
			
		||||
| 
						 | 
				
			
			@ -36,6 +36,7 @@ const INPUT_RIGHT_VARIANT: i32 = 2;
 | 
			
		|||
 | 
			
		||||
const INPUT_EVENT_TYPE_KEYBOARD: i32 = 1;
 | 
			
		||||
const INPUT_EVENT_TYPE_MOUSE: i32 = 2;
 | 
			
		||||
const INPUT_EVENT_TYPE_HOTKEY: i32 = 3;
 | 
			
		||||
 | 
			
		||||
const INPUT_STATUS_PRESSED: i32 = 1;
 | 
			
		||||
const INPUT_STATUS_RELEASED: i32 = 2;
 | 
			
		||||
| 
						 | 
				
			
			@ -62,10 +63,18 @@ pub struct RawInputEvent {
 | 
			
		|||
  pub status: i32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
pub struct RawHotKey {
 | 
			
		||||
  pub id: i32,
 | 
			
		||||
  pub code: u32,
 | 
			
		||||
  pub flags: u32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(improper_ctypes)]
 | 
			
		||||
#[link(name = "espansodetect", kind = "static")]
 | 
			
		||||
extern "C" {
 | 
			
		||||
  pub fn detect_initialize(_self: *const Win32Source, error_code: *mut i32) -> *mut c_void;
 | 
			
		||||
  pub fn detect_register_hotkey(window: *const c_void, hotkey: RawHotKey) -> i32;
 | 
			
		||||
 | 
			
		||||
  pub fn detect_eventloop(
 | 
			
		||||
    window: *const c_void,
 | 
			
		||||
| 
						 | 
				
			
			@ -78,20 +87,24 @@ extern "C" {
 | 
			
		|||
pub struct Win32Source {
 | 
			
		||||
  handle: *mut c_void,
 | 
			
		||||
  callback: LazyCell<SourceCallback>,
 | 
			
		||||
  hotkeys: Vec<HotKey>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(clippy::new_without_default)]
 | 
			
		||||
impl Win32Source {
 | 
			
		||||
  pub fn new() -> Win32Source {
 | 
			
		||||
  pub fn new(hotkeys: &[HotKey]) -> Win32Source {
 | 
			
		||||
    Self {
 | 
			
		||||
      handle: std::ptr::null_mut(),
 | 
			
		||||
      callback: LazyCell::new(),
 | 
			
		||||
      hotkeys: hotkeys.to_vec(),
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Source for Win32Source {
 | 
			
		||||
  fn initialize(&mut self) -> Result<()> {
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    let mut error_code = 0;
 | 
			
		||||
    let handle = unsafe { detect_initialize(self as *const Win32Source, &mut error_code) };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -104,6 +117,23 @@ impl Source for Win32Source {
 | 
			
		|||
      return Err(error.into());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Register the hotkeys
 | 
			
		||||
    self
 | 
			
		||||
      .hotkeys
 | 
			
		||||
      .iter()
 | 
			
		||||
      .for_each(|hk| {
 | 
			
		||||
        let raw = convert_hotkey_to_raw(&hk);
 | 
			
		||||
        if let Some(raw_hk) = raw {
 | 
			
		||||
          if unsafe { detect_register_hotkey(handle, raw_hk) } == 0 {
 | 
			
		||||
            error!("unable to register hotkey: {}", hk);
 | 
			
		||||
          } else {
 | 
			
		||||
            debug!("registered hotkey: {}", hk);
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          error!("unable to generate raw hotkey mapping: {}", hk);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    self.handle = handle;
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
| 
						 | 
				
			
			@ -156,6 +186,35 @@ impl Drop for Win32Source {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn convert_hotkey_to_raw(hk: &HotKey) -> Option<RawHotKey> {
 | 
			
		||||
  let key_code = hk.key.to_code()?;
 | 
			
		||||
  let code: Result<u32, _> = key_code.try_into();
 | 
			
		||||
  if let Ok(code) = code {
 | 
			
		||||
    let mut flags = 0x4000;  // NOREPEAT flags
 | 
			
		||||
    if hk.has_ctrl() {
 | 
			
		||||
      flags |= 0x0002;
 | 
			
		||||
    }
 | 
			
		||||
    if hk.has_alt() {
 | 
			
		||||
      flags |= 0x0001;
 | 
			
		||||
    }
 | 
			
		||||
    if hk.has_meta() {
 | 
			
		||||
      flags |= 0x0008;
 | 
			
		||||
    }
 | 
			
		||||
    if hk.has_shift() {
 | 
			
		||||
      flags |= 0x0004;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Some(RawHotKey {
 | 
			
		||||
      id: hk.id,
 | 
			
		||||
      code,
 | 
			
		||||
      flags,
 | 
			
		||||
    })
 | 
			
		||||
  } else {
 | 
			
		||||
    error!("unable to generate raw hotkey, the key_code is overflowing");
 | 
			
		||||
    None
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Error, Debug)]
 | 
			
		||||
pub enum Win32SourceError {
 | 
			
		||||
  #[error("window registration failed")]
 | 
			
		||||
| 
						 | 
				
			
			@ -225,6 +284,12 @@ impl From<RawInputEvent> for Option<InputEvent> {
 | 
			
		|||
          return Some(InputEvent::Mouse(MouseEvent { button, status }));
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      // Hotkey events
 | 
			
		||||
      INPUT_EVENT_TYPE_HOTKEY => {
 | 
			
		||||
        return Some(InputEvent::HotKey(HotKeyEvent {
 | 
			
		||||
          hotkey_id: raw.key_code
 | 
			
		||||
        }))
 | 
			
		||||
      }
 | 
			
		||||
      _ => {}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -75,6 +75,17 @@ LRESULT CALLBACK detect_window_procedure(HWND window, unsigned int msg, WPARAM w
 | 
			
		|||
    SetWindowLongPtrW(window, GWLP_USERDATA, NULL);
 | 
			
		||||
 | 
			
		||||
    return 0L;
 | 
			
		||||
  case WM_HOTKEY: // Hotkeys
 | 
			
		||||
  {
 | 
			
		||||
    InputEvent event = {};
 | 
			
		||||
    event.event_type = INPUT_EVENT_TYPE_HOTKEY;
 | 
			
		||||
    event.key_code = (int32_t) wp;
 | 
			
		||||
    if (variables->rust_instance != NULL && variables->event_callback != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      variables->event_callback(variables->rust_instance, event);
 | 
			
		||||
    }
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
  case WM_INPUT: // Message relative to the RAW INPUT events
 | 
			
		||||
  {
 | 
			
		||||
    InputEvent event = {};
 | 
			
		||||
| 
						 | 
				
			
			@ -322,6 +333,10 @@ void * detect_initialize(void *_self, int32_t *error_code)
 | 
			
		|||
  return window;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t detect_register_hotkey(void * window, HotKey hotkey) {
 | 
			
		||||
  return RegisterHotKey((HWND)window, hotkey.hk_id, hotkey.flags, hotkey.key_code);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t detect_eventloop(void * window, EventCallback _callback)
 | 
			
		||||
{
 | 
			
		||||
  if (window)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@
 | 
			
		|||
 | 
			
		||||
#define INPUT_EVENT_TYPE_KEYBOARD 1
 | 
			
		||||
#define INPUT_EVENT_TYPE_MOUSE    2
 | 
			
		||||
#define INPUT_EVENT_TYPE_HOTKEY   3
 | 
			
		||||
 | 
			
		||||
#define INPUT_STATUS_PRESSED      1
 | 
			
		||||
#define INPUT_STATUS_RELEASED     2
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +51,8 @@ typedef struct {
 | 
			
		|||
  int32_t buffer_len;
 | 
			
		||||
  
 | 
			
		||||
  // Virtual key code of the pressed key in case of keyboard events
 | 
			
		||||
  // Mouse button code otherwise.
 | 
			
		||||
  // Mouse button code for mouse events.
 | 
			
		||||
  // Hotkey id for hotkey events
 | 
			
		||||
  int32_t key_code;
 | 
			
		||||
  
 | 
			
		||||
  // Left or Right variant
 | 
			
		||||
| 
						 | 
				
			
			@ -60,12 +62,21 @@ typedef struct {
 | 
			
		|||
  int32_t status;
 | 
			
		||||
} InputEvent;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  int32_t hk_id;
 | 
			
		||||
  uint32_t key_code;
 | 
			
		||||
  uint32_t flags;
 | 
			
		||||
} HotKey;
 | 
			
		||||
 | 
			
		||||
typedef void (*EventCallback)(void * rust_istance, InputEvent data);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Initialize the Raw Input API and the Window.
 | 
			
		||||
extern "C" void * detect_initialize(void * rust_istance, int32_t *error_code);
 | 
			
		||||
 | 
			
		||||
// Register the given hotkey, return a non-zero code if successful
 | 
			
		||||
extern "C" int32_t detect_register_hotkey(void * window, HotKey hotkey);
 | 
			
		||||
 | 
			
		||||
// Run the event loop. Blocking call.
 | 
			
		||||
extern "C" int32_t detect_eventloop(void * window, EventCallback callback);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -63,7 +63,7 @@ fn main() {
 | 
			
		|||
    let mut source = get_source(SourceCreationOptions {
 | 
			
		||||
      hotkeys: vec![
 | 
			
		||||
        HotKey::new(1, "OPTION+SPACE").unwrap(),
 | 
			
		||||
        HotKey::new(2, "CMD+OPTION+3").unwrap(),
 | 
			
		||||
        HotKey::new(2, "CTRL+OPTION+3").unwrap(),
 | 
			
		||||
      ],
 | 
			
		||||
      ..Default::default()
 | 
			
		||||
    }).unwrap();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user