Skip to main content

wcpopup/platform/windows/
accelerator.rs

1#[cfg(feature = "accelerator")]
2use super::{get_menu_data, MenuData};
3#[cfg(feature = "accelerator")]
4use crate::platform::platform_impl::vtoi;
5#[cfg(feature = "accelerator")]
6use std::collections::HashMap;
7#[cfg(feature = "accelerator")]
8use windows::Win32::{
9    Foundation::HWND,
10    UI::{
11        Input::KeyboardAndMouse::{
12            VIRTUAL_KEY, VK_0, VK_1, VK_2, VK_3, VK_4, VK_5, VK_6, VK_7, VK_8, VK_9, VK_A, VK_APPS, VK_B, VK_BACK, VK_BROWSER_HOME, VK_C, VK_CAPITAL, VK_CONVERT, VK_D, VK_DELETE, VK_DOWN, VK_E,
13            VK_END, VK_ESCAPE, VK_F, VK_F1, VK_F10, VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, VK_F19, VK_F2, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, VK_F3, VK_F4, VK_F5, VK_F6,
14            VK_F7, VK_F8, VK_F9, VK_G, VK_H, VK_HELP, VK_HOME, VK_I, VK_INSERT, VK_J, VK_K, VK_KANA, VK_L, VK_LEFT, VK_M, VK_MEDIA_NEXT_TRACK, VK_MEDIA_PLAY_PAUSE, VK_MEDIA_PREV_TRACK, VK_MEDIA_STOP,
15            VK_N, VK_NEXT, VK_NONCONVERT, VK_NUMLOCK, VK_O, VK_OEM_1, VK_OEM_2, VK_OEM_3, VK_OEM_4, VK_OEM_5, VK_OEM_6, VK_OEM_7, VK_OEM_COMMA, VK_OEM_MINUS, VK_OEM_PERIOD, VK_OEM_PLUS, VK_P,
16            VK_PAUSE, VK_PRIOR, VK_Q, VK_R, VK_RETURN, VK_RIGHT, VK_S, VK_SCROLL, VK_SNAPSHOT, VK_SPACE, VK_T, VK_TAB, VK_U, VK_UP, VK_V, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, VK_W, VK_X,
17            VK_Y, VK_Z,
18        },
19        WindowsAndMessaging::{CreateAcceleratorTableW, DestroyAcceleratorTable, TranslateAcceleratorW, ACCEL, FALT, FCONTROL, FSHIFT, FVIRTKEY, HACCEL, MSG},
20    },
21};
22
23#[cfg(feature = "accelerator")]
24const MODIFIERS: [&str; 3] = ["CTRL", "ALT", "SHIFT"];
25
26#[cfg(feature = "accelerator")]
27pub(crate) fn translate_accel(hwnd: HWND, msg: MSG) {
28    let data = get_menu_data(vtoi!(hwnd.0));
29    if let Some(accel) = &data.haccel {
30        unsafe { TranslateAcceleratorW(hwnd, HACCEL(accel.0), &msg) };
31    }
32}
33
34#[cfg(feature = "accelerator")]
35pub(crate) fn destroy_haccel(data: &MenuData) {
36    if let Some(haccel) = &data.haccel {
37        let haccel = HACCEL(haccel.0);
38        let _ = unsafe { DestroyAcceleratorTable(haccel) };
39    }
40}
41
42#[cfg(feature = "accelerator")]
43pub(crate) fn create_haccel(accelerators: &HashMap<u16, String>) -> Option<HACCEL> {
44    let mut accels = Vec::new();
45
46    for (cmd, accel_key) in accelerators {
47        let upper_key = accel_key.to_uppercase();
48        let upper_keys: Vec<&str> = upper_key.split('+').collect();
49
50        if MODIFIERS.contains(&upper_keys[upper_keys.len() - 1]) {
51            continue;
52        }
53
54        let keys: Vec<&str> = accel_key.split('+').collect();
55        let key = keys[keys.len() - 1];
56
57        let virtual_key = get_virtual_key(key);
58
59        if virtual_key == VIRTUAL_KEY(0) {
60            continue;
61        }
62
63        let mut virt = FVIRTKEY;
64
65        if upper_keys.contains(&"CTRL") {
66            virt |= FCONTROL;
67        }
68
69        if upper_keys.contains(&"ALT") {
70            virt |= FALT;
71        }
72
73        if upper_keys.contains(&"SHIFT") {
74            virt |= FSHIFT;
75        }
76
77        let accel = ACCEL {
78            fVirt: virt,
79            key: virtual_key.0,
80            cmd: *cmd,
81        };
82
83        accels.push(accel);
84    }
85
86    if accels.is_empty() {
87        None
88    } else if let Ok(haccel) = unsafe { CreateAcceleratorTableW(&accels) } {
89        Some(haccel)
90    } else {
91        None
92    }
93}
94
95#[cfg(feature = "accelerator")]
96fn get_virtual_key(key_string: &str) -> VIRTUAL_KEY {
97    match key_string {
98        "A" => VK_A,
99        "B" => VK_B,
100        "C" => VK_C,
101        "D" => VK_D,
102        "E" => VK_E,
103        "F" => VK_F,
104        "G" => VK_G,
105        "H" => VK_H,
106        "I" => VK_I,
107        "J" => VK_J,
108        "K" => VK_K,
109        "L" => VK_L,
110        "M" => VK_M,
111        "N" => VK_N,
112        "O" => VK_O,
113        "P" => VK_P,
114        "Q" => VK_Q,
115        "R" => VK_R,
116        "S" => VK_S,
117        "T" => VK_T,
118        "U" => VK_U,
119        "V" => VK_V,
120        "W" => VK_W,
121        "X" => VK_X,
122        "Y" => VK_Y,
123        "Z" => VK_Z,
124        "0" => VK_0,
125        "1" => VK_1,
126        "2" => VK_2,
127        "3" => VK_3,
128        "4" => VK_4,
129        "5" => VK_5,
130        "6" => VK_6,
131        "7" => VK_7,
132        "8" => VK_8,
133        "9" => VK_9,
134        "F1" => VK_F1,
135        "F2" => VK_F2,
136        "F3" => VK_F3,
137        "F4" => VK_F4,
138        "F5" => VK_F5,
139        "F6" => VK_F6,
140        "F7" => VK_F7,
141        "F8" => VK_F8,
142        "F9" => VK_F9,
143        "F10" => VK_F10,
144        "F11" => VK_F11,
145        "F12" => VK_F12,
146        "F13" => VK_F13,
147        "F14" => VK_F14,
148        "F15" => VK_F15,
149        "F16" => VK_F16,
150        "F17" => VK_F17,
151        "F18" => VK_F18,
152        "F19" => VK_F19,
153        "F20" => VK_F20,
154        "F21" => VK_F21,
155        "F22" => VK_F22,
156        "F23" => VK_F23,
157        "F24" => VK_F24,
158        "Plus" => VK_OEM_PLUS,
159        "Space" => VK_SPACE,
160        "Tab" => VK_TAB,
161        "CapsLock" => VK_CAPITAL,
162        "NumLock" => VK_NUMLOCK,
163        "ScrollLock" => VK_SCROLL,
164        "Backspace" => VK_BACK,
165        "Delete" => VK_DELETE,
166        "Insert" => VK_INSERT,
167        "Enter" => VK_RETURN,
168        "ArrowLeft" => VK_LEFT,
169        "ArrowUp" => VK_UP,
170        "ArrowRight" => VK_RIGHT,
171        "ArrowDown" => VK_DOWN,
172        "End" => VK_END,
173        "Home" => VK_HOME,
174        "PageUp" => VK_PRIOR,
175        "PageDown" => VK_NEXT,
176        "Escape" => VK_ESCAPE,
177        "BrowserHome" => VK_BROWSER_HOME,
178        "AudioVolumeMute" => VK_VOLUME_MUTE,
179        "AudioVolumeDown" => VK_VOLUME_DOWN,
180        "AudioVolumeUp" => VK_VOLUME_UP,
181        "MediaTrackNext" => VK_MEDIA_NEXT_TRACK,
182        "MediaTrackPrevious" => VK_MEDIA_PREV_TRACK,
183        "MediaStop" => VK_MEDIA_STOP,
184        "MediaPlayPause" => VK_MEDIA_PLAY_PAUSE,
185        "PrintScreen" => VK_SNAPSHOT,
186        "Comma" => VK_OEM_COMMA,
187        "Minus" => VK_OEM_MINUS,
188        "Period" => VK_OEM_PERIOD,
189        "Semicolon" => VK_OEM_1,
190        "Slash" => VK_OEM_2,
191        "Backquote" => VK_OEM_3,
192        "BracketLeft" => VK_OEM_4,
193        "Backslash" => VK_OEM_5,
194        "BracketRight" => VK_OEM_6,
195        "Quote" => VK_OEM_7,
196        "Pause" => VK_PAUSE,
197        "KanaMode" => VK_KANA,
198        "NonConvert" => VK_NONCONVERT,
199        "Help" => VK_HELP,
200        "ContextMenu" => VK_APPS,
201        "Convert" => VK_CONVERT,
202        _ => {
203            println!("Invalid key:{}", key_string);
204            VIRTUAL_KEY(0)
205        }
206    }
207}