1use std::fmt;
2
3use keyboard_types::{Code, Modifiers};
4use windows_sys::Win32::UI::{
5 Input::KeyboardAndMouse::*,
6 WindowsAndMessaging::{ACCEL, FALT, FCONTROL, FSHIFT, FVIRTKEY},
7};
8
9use crate::accelerator::{Accelerator, AcceleratorParseError};
10
11impl Accelerator {
12 pub fn to_accel(&self, menu_id: u16) -> crate::Result<ACCEL> {
14 let mut virt_key = FVIRTKEY;
15 let key_mods: Modifiers = self.mods;
16 if key_mods.contains(Modifiers::CONTROL) {
17 virt_key |= FCONTROL;
18 }
19 if key_mods.contains(Modifiers::ALT) {
20 virt_key |= FALT;
21 }
22 if key_mods.contains(Modifiers::SHIFT) {
23 virt_key |= FSHIFT;
24 }
25
26 let vk_code = key_to_vk(&self.key)?;
27 let mod_code = vk_code >> 8;
28 if mod_code & 0x1 != 0 {
29 virt_key |= FSHIFT;
30 }
31 if mod_code & 0x02 != 0 {
32 virt_key |= FCONTROL;
33 }
34 if mod_code & 0x04 != 0 {
35 virt_key |= FALT;
36 }
37 let raw_key = vk_code & 0x00ff;
38
39 Ok(ACCEL {
40 fVirt: virt_key,
41 key: raw_key,
42 cmd: menu_id,
43 })
44 }
45}
46
47fn key_to_vk(key: &Code) -> Result<VIRTUAL_KEY, AcceleratorParseError> {
49 Ok(match key {
50 Code::KeyA => VK_A,
51 Code::KeyB => VK_B,
52 Code::KeyC => VK_C,
53 Code::KeyD => VK_D,
54 Code::KeyE => VK_E,
55 Code::KeyF => VK_F,
56 Code::KeyG => VK_G,
57 Code::KeyH => VK_H,
58 Code::KeyI => VK_I,
59 Code::KeyJ => VK_J,
60 Code::KeyK => VK_K,
61 Code::KeyL => VK_L,
62 Code::KeyM => VK_M,
63 Code::KeyN => VK_N,
64 Code::KeyO => VK_O,
65 Code::KeyP => VK_P,
66 Code::KeyQ => VK_Q,
67 Code::KeyR => VK_R,
68 Code::KeyS => VK_S,
69 Code::KeyT => VK_T,
70 Code::KeyU => VK_U,
71 Code::KeyV => VK_V,
72 Code::KeyW => VK_W,
73 Code::KeyX => VK_X,
74 Code::KeyY => VK_Y,
75 Code::KeyZ => VK_Z,
76 Code::Digit0 => VK_0,
77 Code::Digit1 => VK_1,
78 Code::Digit2 => VK_2,
79 Code::Digit3 => VK_3,
80 Code::Digit4 => VK_4,
81 Code::Digit5 => VK_5,
82 Code::Digit6 => VK_6,
83 Code::Digit7 => VK_7,
84 Code::Digit8 => VK_8,
85 Code::Digit9 => VK_9,
86 Code::Equal => VK_OEM_PLUS,
87 Code::Comma => VK_OEM_COMMA,
88 Code::Minus => VK_OEM_MINUS,
89 Code::Period => VK_OEM_PERIOD,
90 Code::Semicolon => VK_OEM_1,
91 Code::Slash => VK_OEM_2,
92 Code::Backquote => VK_OEM_3,
93 Code::BracketLeft => VK_OEM_4,
94 Code::Backslash => VK_OEM_5,
95 Code::BracketRight => VK_OEM_6,
96 Code::Quote => VK_OEM_7,
97 Code::Backspace => VK_BACK,
98 Code::Tab => VK_TAB,
99 Code::Space => VK_SPACE,
100 Code::Enter => VK_RETURN,
101 Code::Pause => VK_PAUSE,
102 Code::CapsLock => VK_CAPITAL,
103 Code::KanaMode => VK_KANA,
104 Code::Escape => VK_ESCAPE,
105 Code::NonConvert => VK_NONCONVERT,
106 Code::PageUp => VK_PRIOR,
107 Code::PageDown => VK_NEXT,
108 Code::End => VK_END,
109 Code::Home => VK_HOME,
110 Code::ArrowLeft => VK_LEFT,
111 Code::ArrowUp => VK_UP,
112 Code::ArrowRight => VK_RIGHT,
113 Code::ArrowDown => VK_DOWN,
114 Code::PrintScreen => VK_SNAPSHOT,
115 Code::Insert => VK_INSERT,
116 Code::Delete => VK_DELETE,
117 Code::Help => VK_HELP,
118 Code::ContextMenu => VK_APPS,
119 Code::F1 => VK_F1,
120 Code::F2 => VK_F2,
121 Code::F3 => VK_F3,
122 Code::F4 => VK_F4,
123 Code::F5 => VK_F5,
124 Code::F6 => VK_F6,
125 Code::F7 => VK_F7,
126 Code::F8 => VK_F8,
127 Code::F9 => VK_F9,
128 Code::F10 => VK_F10,
129 Code::F11 => VK_F11,
130 Code::F12 => VK_F12,
131 Code::F13 => VK_F13,
132 Code::F14 => VK_F14,
133 Code::F15 => VK_F15,
134 Code::F16 => VK_F16,
135 Code::F17 => VK_F17,
136 Code::F18 => VK_F18,
137 Code::F19 => VK_F19,
138 Code::F20 => VK_F20,
139 Code::F21 => VK_F21,
140 Code::F22 => VK_F22,
141 Code::F23 => VK_F23,
142 Code::F24 => VK_F24,
143 Code::NumLock => VK_NUMLOCK,
144 Code::ScrollLock => VK_SCROLL,
145 Code::BrowserBack => VK_BROWSER_BACK,
146 Code::BrowserForward => VK_BROWSER_FORWARD,
147 Code::BrowserRefresh => VK_BROWSER_REFRESH,
148 Code::BrowserStop => VK_BROWSER_STOP,
149 Code::BrowserSearch => VK_BROWSER_SEARCH,
150 Code::BrowserFavorites => VK_BROWSER_FAVORITES,
151 Code::BrowserHome => VK_BROWSER_HOME,
152 Code::AudioVolumeMute => VK_VOLUME_MUTE,
153 Code::AudioVolumeDown => VK_VOLUME_DOWN,
154 Code::AudioVolumeUp => VK_VOLUME_UP,
155 Code::MediaTrackNext => VK_MEDIA_NEXT_TRACK,
156 Code::MediaTrackPrevious => VK_MEDIA_PREV_TRACK,
157 Code::MediaStop => VK_MEDIA_STOP,
158 Code::MediaPlayPause => VK_MEDIA_PLAY_PAUSE,
159 Code::LaunchMail => VK_LAUNCH_MAIL,
160 Code::Convert => VK_CONVERT,
161 key => return Err(AcceleratorParseError::UnsupportedKey(key.to_string())),
162 })
163}
164
165impl fmt::Display for Accelerator {
166 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167 let key_mods: Modifiers = self.mods;
168 if key_mods.contains(Modifiers::CONTROL) {
169 write!(f, "Ctrl+")?;
170 }
171 if key_mods.contains(Modifiers::SHIFT) {
172 write!(f, "Shift+")?;
173 }
174 if key_mods.contains(Modifiers::ALT) {
175 write!(f, "Alt+")?;
176 }
177 if key_mods.contains(Modifiers::SUPER) {
178 write!(f, "Windows+")?;
179 }
180 match &self.key {
181 Code::KeyA => write!(f, "A"),
182 Code::KeyB => write!(f, "B"),
183 Code::KeyC => write!(f, "C"),
184 Code::KeyD => write!(f, "D"),
185 Code::KeyE => write!(f, "E"),
186 Code::KeyF => write!(f, "F"),
187 Code::KeyG => write!(f, "G"),
188 Code::KeyH => write!(f, "H"),
189 Code::KeyI => write!(f, "I"),
190 Code::KeyJ => write!(f, "J"),
191 Code::KeyK => write!(f, "K"),
192 Code::KeyL => write!(f, "L"),
193 Code::KeyM => write!(f, "M"),
194 Code::KeyN => write!(f, "N"),
195 Code::KeyO => write!(f, "O"),
196 Code::KeyP => write!(f, "P"),
197 Code::KeyQ => write!(f, "Q"),
198 Code::KeyR => write!(f, "R"),
199 Code::KeyS => write!(f, "S"),
200 Code::KeyT => write!(f, "T"),
201 Code::KeyU => write!(f, "U"),
202 Code::KeyV => write!(f, "V"),
203 Code::KeyW => write!(f, "W"),
204 Code::KeyX => write!(f, "X"),
205 Code::KeyY => write!(f, "Y"),
206 Code::KeyZ => write!(f, "Z"),
207 Code::Digit0 => write!(f, "0"),
208 Code::Digit1 => write!(f, "1"),
209 Code::Digit2 => write!(f, "2"),
210 Code::Digit3 => write!(f, "3"),
211 Code::Digit4 => write!(f, "4"),
212 Code::Digit5 => write!(f, "5"),
213 Code::Digit6 => write!(f, "6"),
214 Code::Digit7 => write!(f, "7"),
215 Code::Digit8 => write!(f, "8"),
216 Code::Digit9 => write!(f, "9"),
217 Code::Comma => write!(f, ","),
218 Code::Minus => write!(f, "-"),
219 Code::Period => write!(f, "."),
220 Code::Space => write!(f, "Space"),
221 Code::Equal => write!(f, "="),
222 Code::Semicolon => write!(f, ";"),
223 Code::Slash => write!(f, "/"),
224 Code::Backslash => write!(f, "\\"),
225 Code::Quote => write!(f, "\'"),
226 Code::Backquote => write!(f, "`"),
227 Code::BracketLeft => write!(f, "["),
228 Code::BracketRight => write!(f, "]"),
229 Code::Tab => write!(f, "Tab"),
230 Code::Escape => write!(f, "Esc"),
231 Code::Delete => write!(f, "Del"),
232 Code::Insert => write!(f, "Ins"),
233 Code::PageUp => write!(f, "PgUp"),
234 Code::PageDown => write!(f, "PgDn"),
235 Code::ArrowLeft => write!(f, "Left"),
237 Code::ArrowRight => write!(f, "Right"),
238 Code::ArrowUp => write!(f, "Up"),
239 Code::ArrowDown => write!(f, "Down"),
240 _ => write!(f, "{:?}", self.key),
241 }
242 }
243}