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