wcpopup 0.9.3

Context menu for Windows and Linux
Documentation
#[cfg(feature = "accelerator")]
use super::{get_menu_data, MenuData};
#[cfg(feature = "accelerator")]
use crate::platform::platform_impl::vtoi;
#[cfg(feature = "accelerator")]
use std::collections::HashMap;
#[cfg(feature = "accelerator")]
use windows::Win32::{
    Foundation::HWND,
    UI::{
        Input::KeyboardAndMouse::{
            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,
            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,
            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,
            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,
            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,
            VK_Y, VK_Z,
        },
        WindowsAndMessaging::{CreateAcceleratorTableW, DestroyAcceleratorTable, TranslateAcceleratorW, ACCEL, FALT, FCONTROL, FSHIFT, FVIRTKEY, HACCEL, MSG},
    },
};

#[cfg(feature = "accelerator")]
const MODIFIERS: [&str; 3] = ["CTRL", "ALT", "SHIFT"];

#[cfg(feature = "accelerator")]
pub(crate) fn translate_accel(hwnd: HWND, msg: MSG) {
    let data = get_menu_data(vtoi!(hwnd.0));
    if let Some(accel) = &data.haccel {
        unsafe { TranslateAcceleratorW(hwnd, HACCEL(accel.0), &msg) };
    }
}

#[cfg(feature = "accelerator")]
pub(crate) fn destroy_haccel(data: &MenuData) {
    if let Some(haccel) = &data.haccel {
        let haccel = HACCEL(haccel.0);
        let _ = unsafe { DestroyAcceleratorTable(haccel) };
    }
}

#[cfg(feature = "accelerator")]
pub(crate) fn create_haccel(accelerators: &HashMap<u16, String>) -> Option<HACCEL> {
    let mut accels = Vec::new();

    for (cmd, accel_key) in accelerators {
        let upper_key = accel_key.to_uppercase();
        let upper_keys: Vec<&str> = upper_key.split('+').collect();

        if MODIFIERS.contains(&upper_keys[upper_keys.len() - 1]) {
            continue;
        }

        let keys: Vec<&str> = accel_key.split('+').collect();
        let key = keys[keys.len() - 1];

        let virtual_key = get_virtual_key(key);

        if virtual_key == VIRTUAL_KEY(0) {
            continue;
        }

        let mut virt = FVIRTKEY;

        if upper_keys.contains(&"CTRL") {
            virt |= FCONTROL;
        }

        if upper_keys.contains(&"ALT") {
            virt |= FALT;
        }

        if upper_keys.contains(&"SHIFT") {
            virt |= FSHIFT;
        }

        let accel = ACCEL {
            fVirt: virt,
            key: virtual_key.0,
            cmd: *cmd,
        };

        accels.push(accel);
    }

    if accels.is_empty() {
        None
    } else if let Ok(haccel) = unsafe { CreateAcceleratorTableW(&accels) } {
        Some(haccel)
    } else {
        None
    }
}

#[cfg(feature = "accelerator")]
fn get_virtual_key(key_string: &str) -> VIRTUAL_KEY {
    match key_string {
        "A" => VK_A,
        "B" => VK_B,
        "C" => VK_C,
        "D" => VK_D,
        "E" => VK_E,
        "F" => VK_F,
        "G" => VK_G,
        "H" => VK_H,
        "I" => VK_I,
        "J" => VK_J,
        "K" => VK_K,
        "L" => VK_L,
        "M" => VK_M,
        "N" => VK_N,
        "O" => VK_O,
        "P" => VK_P,
        "Q" => VK_Q,
        "R" => VK_R,
        "S" => VK_S,
        "T" => VK_T,
        "U" => VK_U,
        "V" => VK_V,
        "W" => VK_W,
        "X" => VK_X,
        "Y" => VK_Y,
        "Z" => VK_Z,
        "0" => VK_0,
        "1" => VK_1,
        "2" => VK_2,
        "3" => VK_3,
        "4" => VK_4,
        "5" => VK_5,
        "6" => VK_6,
        "7" => VK_7,
        "8" => VK_8,
        "9" => VK_9,
        "F1" => VK_F1,
        "F2" => VK_F2,
        "F3" => VK_F3,
        "F4" => VK_F4,
        "F5" => VK_F5,
        "F6" => VK_F6,
        "F7" => VK_F7,
        "F8" => VK_F8,
        "F9" => VK_F9,
        "F10" => VK_F10,
        "F11" => VK_F11,
        "F12" => VK_F12,
        "F13" => VK_F13,
        "F14" => VK_F14,
        "F15" => VK_F15,
        "F16" => VK_F16,
        "F17" => VK_F17,
        "F18" => VK_F18,
        "F19" => VK_F19,
        "F20" => VK_F20,
        "F21" => VK_F21,
        "F22" => VK_F22,
        "F23" => VK_F23,
        "F24" => VK_F24,
        "Plus" => VK_OEM_PLUS,
        "Space" => VK_SPACE,
        "Tab" => VK_TAB,
        "CapsLock" => VK_CAPITAL,
        "NumLock" => VK_NUMLOCK,
        "ScrollLock" => VK_SCROLL,
        "Backspace" => VK_BACK,
        "Delete" => VK_DELETE,
        "Insert" => VK_INSERT,
        "Enter" => VK_RETURN,
        "ArrowLeft" => VK_LEFT,
        "ArrowUp" => VK_UP,
        "ArrowRight" => VK_RIGHT,
        "ArrowDown" => VK_DOWN,
        "End" => VK_END,
        "Home" => VK_HOME,
        "PageUp" => VK_PRIOR,
        "PageDown" => VK_NEXT,
        "Escape" => VK_ESCAPE,
        "BrowserHome" => VK_BROWSER_HOME,
        "AudioVolumeMute" => VK_VOLUME_MUTE,
        "AudioVolumeDown" => VK_VOLUME_DOWN,
        "AudioVolumeUp" => VK_VOLUME_UP,
        "MediaTrackNext" => VK_MEDIA_NEXT_TRACK,
        "MediaTrackPrevious" => VK_MEDIA_PREV_TRACK,
        "MediaStop" => VK_MEDIA_STOP,
        "MediaPlayPause" => VK_MEDIA_PLAY_PAUSE,
        "PrintScreen" => VK_SNAPSHOT,
        "Comma" => VK_OEM_COMMA,
        "Minus" => VK_OEM_MINUS,
        "Period" => VK_OEM_PERIOD,
        "Semicolon" => VK_OEM_1,
        "Slash" => VK_OEM_2,
        "Backquote" => VK_OEM_3,
        "BracketLeft" => VK_OEM_4,
        "Backslash" => VK_OEM_5,
        "BracketRight" => VK_OEM_6,
        "Quote" => VK_OEM_7,
        "Pause" => VK_PAUSE,
        "KanaMode" => VK_KANA,
        "NonConvert" => VK_NONCONVERT,
        "Help" => VK_HELP,
        "ContextMenu" => VK_APPS,
        "Convert" => VK_CONVERT,
        _ => {
            println!("Invalid key:{}", key_string);
            VIRTUAL_KEY(0)
        }
    }
}