Add context menu handling on windows
This commit is contained in:
parent
714dffe6c1
commit
8f47c6b216
|
@ -24,13 +24,14 @@ HKL currentKeyboardLayout;
|
||||||
HWND window;
|
HWND window;
|
||||||
const wchar_t* const winclass = L"Espanso";
|
const wchar_t* const winclass = L"Espanso";
|
||||||
|
|
||||||
KeypressCallback keypress_callback;
|
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
|
|
||||||
#define APPWM_ICON_CLICK (WM_APP + 1)
|
#define APPWM_ICON_CLICK (WM_APP + 1)
|
||||||
#define APPWM_NOTIFICATION_POPUP (WM_APP + 2)
|
#define APPWM_NOTIFICATION_POPUP (WM_APP + 2)
|
||||||
#define APPWM_NOTIFICATION_CLOSE (WM_APP + 3)
|
#define APPWM_NOTIFICATION_CLOSE (WM_APP + 3)
|
||||||
|
#define APPWM_SHOW_CONTEXT_MENU (WM_APP + 4)
|
||||||
|
|
||||||
const wchar_t* const notification_winclass = L"EspansoNotification";
|
const wchar_t* const notification_winclass = L"EspansoNotification";
|
||||||
HWND nw = NULL;
|
HWND nw = NULL;
|
||||||
|
@ -38,18 +39,24 @@ HWND hwnd_st_u = NULL;
|
||||||
HBITMAP g_espanso_bmp = NULL;
|
HBITMAP g_espanso_bmp = NULL;
|
||||||
HICON g_espanso_ico = NULL;
|
HICON g_espanso_ico = NULL;
|
||||||
|
|
||||||
MenuItemCallback menu_item_callback = NULL;
|
// Callbacks
|
||||||
|
|
||||||
// Callback registration
|
KeypressCallback keypress_callback = NULL;
|
||||||
|
IconClickCallback icon_click_callback = NULL;
|
||||||
void register_menu_item_callback(MenuItemCallback callback) {
|
ContextMenuClickCallback context_menu_click_callback = NULL;
|
||||||
menu_item_callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_keypress_callback(KeypressCallback callback) {
|
void register_keypress_callback(KeypressCallback callback) {
|
||||||
keypress_callback = callback;
|
keypress_callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void register_icon_click_callback(IconClickCallback callback) {
|
||||||
|
icon_click_callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_context_menu_click_callback(ContextMenuClickCallback callback) {
|
||||||
|
context_menu_click_callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Message handler procedure for the windows
|
* Message handler procedure for the windows
|
||||||
*/
|
*/
|
||||||
|
@ -65,21 +72,20 @@ LRESULT CALLBACK window_procedure(HWND window, unsigned int msg, WPARAM wp, LPAR
|
||||||
DeleteObject(g_espanso_bmp);
|
DeleteObject(g_espanso_bmp);
|
||||||
DeleteObject(g_espanso_ico);
|
DeleteObject(g_espanso_ico);
|
||||||
return 0L;
|
return 0L;
|
||||||
case WM_MENUSELECT: // Click on the tray icon context menu
|
case WM_COMMAND: // Click on the tray icon context menu
|
||||||
{
|
{
|
||||||
HMENU hmenu = (HMENU)lp;
|
|
||||||
UINT idItem = (UINT)LOWORD(wp);
|
UINT idItem = (UINT)LOWORD(wp);
|
||||||
UINT flags = (UINT)HIWORD(wp);
|
UINT flags = (UINT)HIWORD(wp);
|
||||||
|
|
||||||
if (flags & MF_CHECKED) {
|
if (flags == 0) {
|
||||||
// TODO: callback
|
context_menu_click_callback(manager_instance, (int32_t)idItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case APPWM_NOTIFICATION_POPUP: // Request to show a notification
|
case APPWM_NOTIFICATION_POPUP: // Request to show a notification
|
||||||
{
|
{
|
||||||
std::unique_ptr<wchar_t> ptr(reinterpret_cast<wchar_t*>(wp));
|
std::unique_ptr<wchar_t[]> ptr(reinterpret_cast<wchar_t*>(wp));
|
||||||
|
|
||||||
SetWindowText(hwnd_st_u, L" "); // Clear the previous text
|
SetWindowText(hwnd_st_u, L" "); // Clear the previous text
|
||||||
SetWindowText(hwnd_st_u, ptr.get());
|
SetWindowText(hwnd_st_u, ptr.get());
|
||||||
|
@ -94,32 +100,36 @@ LRESULT CALLBACK window_procedure(HWND window, unsigned int msg, WPARAM wp, LPAR
|
||||||
ShowWindow(nw, SW_HIDE);
|
ShowWindow(nw, SW_HIDE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case APPWM_SHOW_CONTEXT_MENU: // Request to show context menu
|
||||||
|
{
|
||||||
|
HMENU hPopupMenu = CreatePopupMenu();
|
||||||
|
|
||||||
|
// Create the menu
|
||||||
|
|
||||||
|
int32_t count = static_cast<int32_t>(lp);
|
||||||
|
std::unique_ptr<MenuItem[]> items(reinterpret_cast<MenuItem*>(wp));
|
||||||
|
|
||||||
|
for (int i = 0; i<count; i++) {
|
||||||
|
if (items[i].type == 1) {
|
||||||
|
InsertMenu(hPopupMenu, i, MF_BYPOSITION | MF_STRING, items[i].id, items[i].name);
|
||||||
|
}else{
|
||||||
|
InsertMenu(hPopupMenu, i, MF_BYPOSITION | MF_SEPARATOR, items[i].id, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
POINT pt;
|
||||||
|
GetCursorPos(&pt);
|
||||||
|
SetForegroundWindow(nw);
|
||||||
|
TrackPopupMenu(hPopupMenu, TPM_BOTTOMALIGN | TPM_LEFTALIGN, pt.x, pt.y, 0, nw, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case APPWM_ICON_CLICK: // Click on the tray icon
|
case APPWM_ICON_CLICK: // Click on the tray icon
|
||||||
{
|
{
|
||||||
switch (lp)
|
switch (lp)
|
||||||
{
|
{
|
||||||
case WM_LBUTTONUP:
|
case WM_LBUTTONUP:
|
||||||
case WM_RBUTTONUP:
|
case WM_RBUTTONUP:
|
||||||
HMENU hPopupMenu = CreatePopupMenu();
|
icon_click_callback(manager_instance);
|
||||||
|
|
||||||
// Create the menu
|
|
||||||
|
|
||||||
int32_t count;
|
|
||||||
MenuItem items[100];
|
|
||||||
|
|
||||||
// Load the items
|
|
||||||
menu_item_callback(manager_instance, items, &count);
|
|
||||||
|
|
||||||
for (int i = 0; i<count; i++) {
|
|
||||||
if (items[i].type == 1) {
|
|
||||||
InsertMenu(hPopupMenu, 0, MF_BYPOSITION | MF_STRING, items[i].id, items[i].name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
POINT pt;
|
|
||||||
GetCursorPos(&pt);
|
|
||||||
SetForegroundWindow(nw);
|
|
||||||
TrackPopupMenu(hPopupMenu, TPM_BOTTOMALIGN | TPM_LEFTALIGN, pt.x, pt.y, 0, nw, NULL);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -489,4 +499,16 @@ void close_notification() {
|
||||||
if (nw != NULL) {
|
if (nw != NULL) {
|
||||||
PostMessage(nw, APPWM_NOTIFICATION_CLOSE, 0, 0);
|
PostMessage(nw, APPWM_NOTIFICATION_CLOSE, 0, 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t show_context_menu(MenuItem * items, int32_t count) {
|
||||||
|
if (nw != NULL) {
|
||||||
|
MenuItem * items_buffer = new MenuItem[count];
|
||||||
|
memcpy(items_buffer, items, sizeof(MenuItem)*count);
|
||||||
|
|
||||||
|
PostMessage(nw, APPWM_SHOW_CONTEXT_MENU, reinterpret_cast<WPARAM>(items_buffer), static_cast<LPARAM>(count));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
|
@ -60,6 +60,13 @@ extern "C" int32_t get_active_window_executable(wchar_t * buffer, int32_t size);
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when the tray icon is clicked
|
||||||
|
*/
|
||||||
|
typedef void (*IconClickCallback)(void * self);
|
||||||
|
extern IconClickCallback icon_click_callback;
|
||||||
|
extern "C" void register_icon_click_callback(IconClickCallback callback);
|
||||||
|
|
||||||
// CONTEXT MENU
|
// CONTEXT MENU
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -68,13 +75,14 @@ typedef struct {
|
||||||
wchar_t name[100];
|
wchar_t name[100];
|
||||||
} MenuItem;
|
} MenuItem;
|
||||||
|
|
||||||
/*
|
extern "C" int32_t show_context_menu(MenuItem * items, int32_t count);
|
||||||
* Called when the context menu is created.
|
|
||||||
*/
|
|
||||||
typedef void (*MenuItemCallback)(void * self, MenuItem * items, int32_t * item_count);
|
|
||||||
|
|
||||||
extern MenuItemCallback menu_item_callback;
|
/*
|
||||||
extern "C" void register_menu_item_callback(MenuItemCallback callback);
|
* Called when the context menu is clicked
|
||||||
|
*/
|
||||||
|
typedef void (*ContextMenuClickCallback)(void * self, int32_t id);
|
||||||
|
extern ContextMenuClickCallback context_menu_click_callback;
|
||||||
|
extern "C" void register_context_menu_click_callback(ContextMenuClickCallback callback);
|
||||||
|
|
||||||
// NOTIFICATION
|
// NOTIFICATION
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,9 @@ extern {
|
||||||
// UI
|
// UI
|
||||||
pub fn show_notification(message: *const u16) -> i32;
|
pub fn show_notification(message: *const u16) -> i32;
|
||||||
pub fn close_notification();
|
pub fn close_notification();
|
||||||
pub fn register_menu_item_callback(cb: extern fn(_self: *mut c_void, *mut WindowsMenuItem,
|
pub fn show_context_menu(items: *const WindowsMenuItem, count: i32) -> i32;
|
||||||
*mut i32));
|
pub fn register_icon_click_callback(cb: extern fn(_self: *mut c_void));
|
||||||
|
pub fn register_context_menu_click_callback(cb: extern fn(_self: *mut c_void, id: i32));
|
||||||
|
|
||||||
// KEYBOARD
|
// KEYBOARD
|
||||||
pub fn register_keypress_callback(cb: extern fn(_self: *mut c_void, *const i32,
|
pub fn register_keypress_callback(cb: extern fn(_self: *mut c_void, *const i32,
|
||||||
|
|
|
@ -15,15 +15,6 @@ pub trait Context {
|
||||||
fn eventloop(&self);
|
fn eventloop(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum MenuItemType {
|
|
||||||
Button,
|
|
||||||
Separator
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct MenuItem {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// MAC IMPLEMENTATION
|
// MAC IMPLEMENTATION
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub fn new(send_channel: Sender<Event>) -> Box<dyn Context> { // TODO
|
pub fn new(send_channel: Sender<Event>) -> Box<dyn Context> { // TODO
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
use crate::bridge::windows::*;
|
use crate::bridge::windows::*;
|
||||||
use crate::event::{Event, KeyEvent, KeyModifier};
|
use crate::event::{Event, KeyEvent, KeyModifier, ActionEvent};
|
||||||
use crate::event::KeyModifier::*;
|
use crate::event::KeyModifier::*;
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::fs::create_dir_all;
|
use std::fs::create_dir_all;
|
||||||
|
@ -63,7 +63,8 @@ impl WindowsContext {
|
||||||
|
|
||||||
// Register callbacks
|
// Register callbacks
|
||||||
register_keypress_callback(keypress_callback);
|
register_keypress_callback(keypress_callback);
|
||||||
register_menu_item_callback(menu_item_callback);
|
register_icon_click_callback(icon_click_callback);
|
||||||
|
register_context_menu_click_callback(context_menu_click_callback);
|
||||||
|
|
||||||
let ico_file_c = U16CString::from_str(ico_icon).unwrap();
|
let ico_file_c = U16CString::from_str(ico_icon).unwrap();
|
||||||
let bmp_file_c = U16CString::from_str(bmp_icon).unwrap();
|
let bmp_file_c = U16CString::from_str(bmp_icon).unwrap();
|
||||||
|
@ -122,22 +123,21 @@ extern fn keypress_callback(_self: *mut c_void, raw_buffer: *const i32, len: i32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn menu_item_callback(_self: *mut c_void, items: *mut WindowsMenuItem, count: *mut i32) {
|
extern fn icon_click_callback(_self: *mut c_void) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _self = _self as *mut WindowsContext;
|
let _self = _self as *mut WindowsContext;
|
||||||
|
|
||||||
let str = U16CString::from_str("Test").unwrap_or_default();
|
let event = Event::Action(ActionEvent::IconClick);
|
||||||
let mut str_buff : [u16; 100] = [0; 100];
|
(*_self).send_channel.send(event).unwrap();
|
||||||
std::ptr::copy(str.as_ptr(), str_buff.as_mut_ptr(), str.len());
|
}
|
||||||
let item = WindowsMenuItem {
|
}
|
||||||
item_id: 1,
|
|
||||||
item_type: 1,
|
|
||||||
item_name: str_buff,
|
|
||||||
};
|
|
||||||
|
|
||||||
let items = unsafe { std::slice::from_raw_parts_mut(items, 100) };
|
|
||||||
|
|
||||||
items[0] = item;
|
extern fn context_menu_click_callback(_self: *mut c_void, id: i32) {
|
||||||
*count = 1;
|
unsafe {
|
||||||
|
let _self = _self as *mut WindowsContext;
|
||||||
|
|
||||||
|
let event = Event::Action(ActionEvent::ContextMenuClick(id));
|
||||||
|
(*_self).send_channel.send(event).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,8 +4,9 @@ use crate::config::ConfigManager;
|
||||||
use crate::config::BackendType;
|
use crate::config::BackendType;
|
||||||
use crate::clipboard::ClipboardManager;
|
use crate::clipboard::ClipboardManager;
|
||||||
use log::{info};
|
use log::{info};
|
||||||
use crate::ui::UIManager;
|
use crate::ui::{UIManager, MenuItem, MenuItemType};
|
||||||
use crate::event::{ActionEventReceiver, Event};
|
use crate::event::{ActionEventReceiver, Event, ActionEvent};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
pub struct Engine<'a, S: KeyboardSender, C: ClipboardManager, M: ConfigManager<'a>,
|
pub struct Engine<'a, S: KeyboardSender, C: ClipboardManager, M: ConfigManager<'a>,
|
||||||
U: UIManager> {
|
U: UIManager> {
|
||||||
|
@ -13,12 +14,44 @@ pub struct Engine<'a, S: KeyboardSender, C: ClipboardManager, M: ConfigManager<'
|
||||||
clipboard_manager: &'a C,
|
clipboard_manager: &'a C,
|
||||||
config_manager: &'a M,
|
config_manager: &'a M,
|
||||||
ui_manager: &'a U,
|
ui_manager: &'a U,
|
||||||
|
enabled: RefCell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a, S: KeyboardSender, C: ClipboardManager, M: ConfigManager<'a>, U: UIManager>
|
impl <'a, S: KeyboardSender, C: ClipboardManager, M: ConfigManager<'a>, U: UIManager>
|
||||||
Engine<'a, S, C, M, U> {
|
Engine<'a, S, C, M, U> {
|
||||||
pub fn new(sender: S, clipboard_manager: &'a C, config_manager: &'a M, ui_manager: &'a U) -> Engine<'a, S, C, M, U> {
|
pub fn new(sender: S, clipboard_manager: &'a C, config_manager: &'a M, ui_manager: &'a U) -> Engine<'a, S, C, M, U> {
|
||||||
Engine{sender, clipboard_manager, config_manager, ui_manager }
|
let enabled = RefCell::new(true);
|
||||||
|
Engine{sender, clipboard_manager, config_manager, ui_manager, enabled }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_menu(&self) -> Vec<MenuItem> {
|
||||||
|
let mut menu = Vec::new();
|
||||||
|
|
||||||
|
let enabled = self.enabled.borrow();
|
||||||
|
let toggle_text = if *enabled {
|
||||||
|
"Disable"
|
||||||
|
}else{
|
||||||
|
"Enable"
|
||||||
|
}.to_owned();
|
||||||
|
menu.push(MenuItem{
|
||||||
|
item_type: MenuItemType::Button,
|
||||||
|
item_name: toggle_text,
|
||||||
|
item_id: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
menu.push(MenuItem{
|
||||||
|
item_type: MenuItemType::Separator,
|
||||||
|
item_name: "".to_owned(),
|
||||||
|
item_id: 999,
|
||||||
|
});
|
||||||
|
|
||||||
|
menu.push(MenuItem{
|
||||||
|
item_type: MenuItemType::Button,
|
||||||
|
item_name: "Exit".to_owned(),
|
||||||
|
item_id: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
menu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +103,9 @@ impl <'a, S: KeyboardSender, C: ClipboardManager, M: ConfigManager<'a>, U: UIMan
|
||||||
|
|
||||||
info!("Toggled: {}", message);
|
info!("Toggled: {}", message);
|
||||||
|
|
||||||
|
let mut enabled_ref = self.enabled.borrow_mut();
|
||||||
|
*enabled_ref = status;
|
||||||
|
|
||||||
self.ui_manager.notify(message);
|
self.ui_manager.notify(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +113,14 @@ impl <'a, S: KeyboardSender, C: ClipboardManager, M: ConfigManager<'a>, U: UIMan
|
||||||
impl <'a, S: KeyboardSender, C: ClipboardManager,
|
impl <'a, S: KeyboardSender, C: ClipboardManager,
|
||||||
M: ConfigManager<'a>, U: UIManager> ActionEventReceiver for Engine<'a, S, C, M, U>{
|
M: ConfigManager<'a>, U: UIManager> ActionEventReceiver for Engine<'a, S, C, M, U>{
|
||||||
|
|
||||||
fn on_action_event(&self, e: Event) {
|
fn on_action_event(&self, e: ActionEvent) {
|
||||||
unimplemented!()
|
match e {
|
||||||
|
ActionEvent::IconClick => {
|
||||||
|
self.ui_manager.show_menu(self.build_menu());
|
||||||
|
},
|
||||||
|
ActionEvent::ContextMenuClick(id) => {
|
||||||
|
println!("{}", id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -31,8 +31,8 @@ impl <'a, K: KeyEventReceiver, A: ActionEventReceiver> EventManager for DefaultE
|
||||||
Event::Key(key_event) => {
|
Event::Key(key_event) => {
|
||||||
self.key_receiver.on_key_event(key_event);
|
self.key_receiver.on_key_event(key_event);
|
||||||
},
|
},
|
||||||
Event::Action => {
|
Event::Action(action_event) => {
|
||||||
self.action_receiver.on_action_event(event); // TODO: action event
|
self.action_receiver.on_action_event(action_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,10 +4,16 @@ use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
Action,
|
Action(ActionEvent),
|
||||||
Key(KeyEvent)
|
Key(KeyEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ActionEvent {
|
||||||
|
IconClick,
|
||||||
|
ContextMenuClick(i32)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum KeyEvent {
|
pub enum KeyEvent {
|
||||||
Char(char),
|
Char(char),
|
||||||
|
@ -36,5 +42,5 @@ pub trait KeyEventReceiver {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ActionEventReceiver {
|
pub trait ActionEventReceiver {
|
||||||
fn on_action_event(&self, e: Event); // TODO: Action event
|
fn on_action_event(&self, e: ActionEvent); // TODO: Action event
|
||||||
}
|
}
|
|
@ -9,15 +9,18 @@ mod macos;
|
||||||
|
|
||||||
pub trait UIManager {
|
pub trait UIManager {
|
||||||
fn notify(&self, message: &str);
|
fn notify(&self, message: &str);
|
||||||
|
fn show_menu(&self, menu: Vec<MenuItem>);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum MenuItemType {
|
pub enum MenuItemType {
|
||||||
Button,
|
Button,
|
||||||
Separator
|
Separator,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MenuItem {
|
pub struct MenuItem {
|
||||||
|
pub item_id: i32,
|
||||||
|
pub item_type: MenuItemType,
|
||||||
|
pub item_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// MAC IMPLEMENTATION
|
// MAC IMPLEMENTATION
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use crate::bridge::windows::{show_notification, close_notification, WindowsMenuItem};
|
use crate::bridge::windows::{show_notification, close_notification, WindowsMenuItem, show_context_menu};
|
||||||
use widestring::U16CString;
|
use widestring::U16CString;
|
||||||
use std::{fs, thread, time};
|
use std::{fs, thread, time};
|
||||||
use log::{info, debug};
|
use log::{info, debug};
|
||||||
|
@ -7,6 +7,7 @@ use std::sync::Mutex;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::fs::create_dir_all;
|
use std::fs::create_dir_all;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
use crate::ui::{MenuItem, MenuItemType};
|
||||||
|
|
||||||
const BMP_BINARY : &'static [u8] = include_bytes!("../res/win/espanso.bmp");
|
const BMP_BINARY : &'static [u8] = include_bytes!("../res/win/espanso.bmp");
|
||||||
const ICO_BINARY : &'static [u8] = include_bytes!("../res/win/espanso.ico");
|
const ICO_BINARY : &'static [u8] = include_bytes!("../res/win/espanso.ico");
|
||||||
|
@ -49,6 +50,33 @@ impl super::UIManager for WindowsUIManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn show_menu(&self, menu: Vec<MenuItem>) {
|
||||||
|
let mut raw_menu = Vec::new();
|
||||||
|
|
||||||
|
for item in menu.iter() {
|
||||||
|
let text = U16CString::from_str(item.item_name.clone()).unwrap_or_default();
|
||||||
|
let mut str_buff : [u16; 100] = [0; 100];
|
||||||
|
unsafe {
|
||||||
|
std::ptr::copy(text.as_ptr(), str_buff.as_mut_ptr(), text.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
let menu_type = match item.item_type {
|
||||||
|
MenuItemType::Button => {1},
|
||||||
|
MenuItemType::Separator => {2},
|
||||||
|
};
|
||||||
|
|
||||||
|
let raw_item = WindowsMenuItem {
|
||||||
|
item_id: item.item_id,
|
||||||
|
item_type: menu_type,
|
||||||
|
item_name: str_buff,
|
||||||
|
};
|
||||||
|
|
||||||
|
raw_menu.push(raw_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { show_context_menu(raw_menu.as_ptr(), raw_menu.len() as i32); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowsUIManager {
|
impl WindowsUIManager {
|
||||||
|
@ -61,26 +89,4 @@ impl WindowsUIManager {
|
||||||
|
|
||||||
manager
|
manager
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// NATIVE
|
|
||||||
|
|
||||||
extern fn menu_item_callback(_self: *mut c_void, items: *mut WindowsMenuItem, count: *mut i32) {
|
|
||||||
unsafe {
|
|
||||||
let _self = _self as *mut WindowsUIManager;
|
|
||||||
|
|
||||||
let str = U16CString::from_str("Test").unwrap_or_default();
|
|
||||||
let mut str_buff : [u16; 100] = [0; 100];
|
|
||||||
std::ptr::copy(str.as_ptr(), str_buff.as_mut_ptr(), str.len());
|
|
||||||
let item = WindowsMenuItem {
|
|
||||||
item_id: 1,
|
|
||||||
item_type: 1,
|
|
||||||
item_name: str_buff,
|
|
||||||
};
|
|
||||||
|
|
||||||
let items = unsafe { std::slice::from_raw_parts_mut(items, 100) };
|
|
||||||
|
|
||||||
items[0] = item;
|
|
||||||
*count = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user