1use crate::{revertible::Revertible, util::str_to_c, AddonApi, InputBindsApi};
4use std::ffi::c_char;
5
6#[derive(Debug, Clone)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9#[repr(C)]
10pub struct Keybind {
11 pub key: u16,
13
14 pub alt: bool,
16
17 pub ctrl: bool,
19
20 pub shift: bool,
22}
23
24impl Keybind {
25 #[inline]
27 pub fn without_modifiers(key: u16) -> Self {
28 Self {
29 key,
30 alt: false,
31 ctrl: false,
32 shift: false,
33 }
34 }
35
36 #[inline]
38 pub fn has_modifiers(&self) -> bool {
39 !self.alt && !self.ctrl && !self.shift
40 }
41}
42
43pub type RawKeybindHandler = extern "C-unwind" fn(identifier: *const c_char, is_release: bool);
44
45pub type RawKeybindInvoke =
46 unsafe extern "C-unwind" fn(identifier: *const c_char, is_release: bool);
47
48pub type RawKeybindRegisterWithString = unsafe extern "C-unwind" fn(
49 identifier: *const c_char,
50 keybind_handler: RawKeybindHandler,
51 keybind: *const c_char,
52);
53
54pub type RawKeybindRegisterWithStruct = unsafe extern "C-unwind" fn(
55 identifier: *const c_char,
56 keybind_handler: RawKeybindHandler,
57 keybind: Keybind,
58);
59
60pub type RawKeybindDeregister = unsafe extern "C-unwind" fn(identifier: *const c_char);
61
62pub type RawKeybindHandlerOld = extern "C-unwind" fn(identifier: *const c_char);
63
64pub type RawKeybindRegisterWithStringOld = unsafe extern "C-unwind" fn(
65 identifier: *const c_char,
66 keybind_handler: RawKeybindHandlerOld,
67 keybind: *const c_char,
68);
69
70pub type RawKeybindRegisterWithStructOld = unsafe extern "C-unwind" fn(
71 identifier: *const c_char,
72 keybind_handler: RawKeybindHandlerOld,
73 keybind: Keybind,
74);
75
76pub fn invoke_keybind(identifier: impl AsRef<str>, is_release: bool) {
78 let InputBindsApi { invoke, .. } = AddonApi::get().input_binds;
79 let identifier = str_to_c(identifier, "failed to convert keybind identifier");
80 unsafe { invoke(identifier.as_ptr(), is_release) }
81}
82
83pub fn register_keybind_with_string(
101 identifier: impl AsRef<str>,
102 handler: RawKeybindHandler,
103 keybind: impl AsRef<str>,
104) -> Revertible<impl Fn() + Send + Sync + Clone + 'static> {
105 let InputBindsApi {
106 register_with_string,
107 deregister,
108 ..
109 } = AddonApi::get().input_binds;
110 let identifier = str_to_c(identifier, "failed to convert keybind identifier");
111 let keybind = str_to_c(keybind, "failed to convert keybind string");
112 unsafe { register_with_string(identifier.as_ptr(), handler, keybind.as_ptr()) };
113 let revert = move || unsafe { deregister(identifier.as_ptr()) };
114 revert.into()
115}
116
117pub fn register_keybind_with_struct(
141 identifier: impl AsRef<str>,
142 handler: RawKeybindHandler,
143 keybind: Keybind,
144) -> Revertible<impl Fn() + Send + Sync + Clone + 'static> {
145 let InputBindsApi {
146 register_with_struct,
147 deregister,
148 ..
149 } = AddonApi::get().input_binds;
150 let identifier = str_to_c(identifier, "failed to convert keybind identifier");
151 unsafe { register_with_struct(identifier.as_ptr(), handler, keybind) };
152 let revert = move || unsafe { deregister(identifier.as_ptr()) };
153 revert.into()
154}
155
156pub fn unregister_keybind(identifier: impl AsRef<str>) {
158 let InputBindsApi { deregister, .. } = AddonApi::get().input_binds;
159 let identifier = str_to_c(identifier, "failed to convert keybind identifier");
160 unsafe { deregister(identifier.as_ptr()) }
161}
162
163#[macro_export]
179macro_rules! keybind_handler {
180 ( $callback:expr $(,)? ) => {{
181 const __CALLBACK: fn(&::std::primitive::str, ::std::primitive::bool) = $callback;
182
183 extern "C-unwind" fn __keybind_callback_wrapper(
184 identifier: *const ::std::ffi::c_char,
185 is_release: ::std::primitive::bool,
186 ) {
187 let identifier = unsafe { $crate::__macro::str_from_c(identifier) }
188 .expect("invalid identifier in keybind callback");
189 __CALLBACK(identifier, is_release)
190 }
191
192 __keybind_callback_wrapper
193 }};
194}
195
196pub use keybind_handler;