implement keyboard accelerators for linux

This commit is contained in:
Jinhao 2018-02-24 06:13:46 +08:00
parent 244416088f
commit 457d86aa39
2 changed files with 83 additions and 13 deletions

View File

@ -104,9 +104,40 @@ namespace detail
void window_proc_for_packet(Display *, nana::detail::msg_packet_tag&); void window_proc_for_packet(Display *, nana::detail::msg_packet_tag&);
void window_proc_for_xevent(Display*, XEvent&); void window_proc_for_xevent(Display*, XEvent&);
class accel_key_comparer
{
public:
bool operator()(const accel_key& a, const accel_key& b) const
{
auto va = a.case_sensitive ? a.key : std::tolower(a.key);
auto vb = b.case_sensitive ? b.key : std::tolower(b.key);
if(va < vb)
return true;
else if(va > vb)
return false;
if (a.case_sensitive != b.case_sensitive)
return b.case_sensitive;
if (a.alt != b.alt)
return b.alt;
if (a.ctrl != b.ctrl)
return b.ctrl;
return ((a.shift != b.shift) && b.shift);
}
};
struct accel_key_value
{
std::function<void()> command;
};
struct window_platform_assoc struct window_platform_assoc
{ {
//Wait... std::map<accel_key, accel_key_value, accel_key_comparer> accel_commands;
}; };
//class bedrock defines a static object itself to implement a static singleton //class bedrock defines a static object itself to implement a static singleton
@ -233,9 +264,16 @@ namespace detail
delete passoc; delete passoc;
} }
void bedrock::keyboard_accelerator(native_window_type, const accel_key&, const std::function<void()>& fn) void bedrock::keyboard_accelerator(native_window_type wd, const accel_key& ackey, const std::function<void()>& fn)
{ {
auto misc = wd_manager().root_runtime(wd);
if (nullptr == misc)
return;
if (!misc->wpassoc)
misc->wpassoc = new window_platform_assoc;
misc->wpassoc->accel_commands[ackey].command = fn;
} }
element_store& bedrock::get_element_store() const element_store& bedrock::get_element_store() const
@ -506,6 +544,34 @@ namespace detail
return wchar_t(keysym); return wchar_t(keysym);
} }
bool translate_keyboard_accelerator(root_misc* misc, char os_code, const arg_keyboard& modifiers)
{
if(!misc->wpassoc)
return false;
auto lower_oc = std::tolower(os_code);
std::function<void()> command;
for(auto & accel : misc->wpassoc->accel_commands)
{
if(accel.first.key != (accel.first.case_sensitive ? os_code : lower_oc))
continue;
if(accel.first.alt == modifiers.alt && accel.first.ctrl == modifiers.ctrl && accel.first.shift == modifiers.shift)
{
command = accel.second.command;
break;
}
}
if(!command)
return false;
command();
return true;
}
void window_proc_for_xevent(Display* /*display*/, XEvent& xevent) void window_proc_for_xevent(Display* /*display*/, XEvent& xevent)
{ {
typedef detail::bedrock::core_window_t core_window_t; typedef detail::bedrock::core_window_t core_window_t;
@ -865,6 +931,9 @@ namespace detail
if(msgwnd) if(msgwnd)
{ {
arg_keyboard modifiers_status;
brock.get_key_state(modifiers_status);
KeySym keysym; KeySym keysym;
Status status; Status status;
char fixbuf[33]; char fixbuf[33];
@ -899,16 +968,20 @@ namespace detail
keybuf[len] = 0; keybuf[len] = 0;
wchar_t os_code = 0; wchar_t os_code = 0;
bool accel_translated = false;
switch(status) switch(status)
{ {
case XLookupKeySym: case XLookupKeySym:
case XLookupBoth: case XLookupBoth:
os_code = os_code_from_keysym(keysym); os_code = os_code_from_keysym(keysym);
accel_translated = translate_keyboard_accelerator(root_runtime, os_code, modifiers_status);
if(accel_translated)
break;
if(os_code == keyboard::tab && (false == (msgwnd->flags.tab & detail::tab_type::eating))) //Tab if(os_code == keyboard::tab && (false == (msgwnd->flags.tab & detail::tab_type::eating))) //Tab
{ {
arg_keyboard argkey; auto tstop_wd = wd_manager.tabstop(msgwnd, !modifiers_status.shift);
brock.get_key_state(argkey);
auto tstop_wd = wd_manager.tabstop(msgwnd, !argkey.shift);
if (tstop_wd) if (tstop_wd)
{ {
root_runtime->condition.ignore_tab = true; root_runtime->condition.ignore_tab = true;
@ -923,9 +996,9 @@ namespace detail
if((nullptr == pressed_wd) && (nullptr == pressed_wd_space)) if((nullptr == pressed_wd) && (nullptr == pressed_wd_space))
{ {
arg_mouse arg; arg_mouse arg;
arg.alt = false; arg.alt = modifiers_status.alt;
arg.button = ::nana::mouse::left_button; arg.button = ::nana::mouse::left_button;
arg.ctrl = false; arg.ctrl = modifiers_status.ctrl;
arg.evt_code = event_code::mouse_down; arg.evt_code = event_code::mouse_down;
arg.left_button = true; arg.left_button = true;
arg.mid_button = false; arg.mid_button = false;
@ -971,11 +1044,10 @@ namespace detail
if(keyboard::os_ctrl == os_code) if(keyboard::os_ctrl == os_code)
context.is_ctrl_pressed = true; context.is_ctrl_pressed = true;
arg_keyboard arg; arg_keyboard arg = modifiers_status;
arg.ignore = false; arg.ignore = false;
arg.key = os_code; arg.key = os_code;
arg.evt_code = event_code::key_press; arg.evt_code = event_code::key_press;
brock.get_key_state(arg);
arg.window_handle = reinterpret_cast<window>(msgwnd); arg.window_handle = reinterpret_cast<window>(msgwnd);
brock.emit(event_code::key_press, msgwnd, arg, true, &context); brock.emit(event_code::key_press, msgwnd, arg, true, &context);
@ -1004,7 +1076,7 @@ namespace detail
for(int i = 0; i < len; ++i) for(int i = 0; i < len; ++i)
{ {
arg_keyboard arg; arg_keyboard arg = modifiers_status;
arg.ignore = false; arg.ignore = false;
arg.key = charbuf[i]; arg.key = charbuf[i];
@ -1027,7 +1099,6 @@ namespace detail
} }
arg.evt_code = event_code::key_char; arg.evt_code = event_code::key_char;
arg.window_handle = reinterpret_cast<window>(msgwnd); arg.window_handle = reinterpret_cast<window>(msgwnd);
brock.get_key_state(arg);
msgwnd->annex.events_ptr->key_char.emit(arg, reinterpret_cast<window>(msgwnd)); msgwnd->annex.events_ptr->key_char.emit(arg, reinterpret_cast<window>(msgwnd));
if(arg.ignore == false && wd_manager.available(msgwnd)) if(arg.ignore == false && wd_manager.available(msgwnd))
draw_invoker(&drawer::key_char, msgwnd, arg, &context); draw_invoker(&drawer::key_char, msgwnd, arg, &context);

View File

@ -1650,8 +1650,7 @@ namespace detail
auto misc = wd_manager().root_runtime(wd); auto misc = wd_manager().root_runtime(wd);
if (nullptr == misc) if (nullptr == misc)
return; return;
auto wpassoc = misc->wpassoc;
if (!misc->wpassoc) if (!misc->wpassoc)
misc->wpassoc = new window_platform_assoc; misc->wpassoc = new window_platform_assoc;