muda_win/platform_impl/
accelerator.rs

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    // Convert a hotkey to an accelerator.
13    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
47// used to build accelerators table from Key
48fn 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            // These names match LibreOffice.
236            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}