add keyboard accelerator

This commit is contained in:
Jinhao
2018-02-22 07:59:27 +08:00
parent 56143087c3
commit f6548acc84
8 changed files with 150 additions and 16 deletions

View File

@@ -1,7 +1,7 @@
/*
* A Bedrock Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@@ -15,10 +15,10 @@
#include <nana/gui/detail/bedrock_pi_data.hpp>
#include <nana/gui/detail/event_code.hpp>
#include <nana/system/platform.hpp>
#include <nana/gui/detail/inner_fwd_implement.hpp>
#include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/layout_utility.hpp>
#include <nana/gui/detail/element_store.hpp>
#include "inner_fwd_implement.hpp"
#include <errno.h>
#include <algorithm>
@@ -222,6 +222,11 @@ namespace detail
arg.shift = (xkey.state & ShiftMask);
}
void bedrock::keyboard_accelerator(native_window_type, const accel_key&, const std::function<void()>& fn)
{
}
element_store& bedrock::get_element_store() const
{
return impl_->estore;

View File

@@ -1,7 +1,7 @@
/**
* A Bedrock Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@@ -20,11 +20,11 @@
#include <nana/system/platform.hpp>
#include <nana/system/timepiece.hpp>
#include <nana/gui.hpp>
#include <nana/gui/detail/inner_fwd_implement.hpp>
#include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/layout_utility.hpp>
#include <nana/gui/detail/element_store.hpp>
#include <nana/gui/detail/color_schemes.hpp>
#include "inner_fwd_implement.hpp"
#include <iostream> //use std::cerr
@@ -182,6 +182,12 @@ namespace detail
}cache;
};
struct window_platform_assoc
{
HACCEL accel{ nullptr }; ///< A handle to a Windows keyboard accelerator object.
std::map<int, std::function<void()>> accel_commands;
};
//class bedrock defines a static object itself to implement a static singleton
//here is the definition of this object
bedrock bedrock::bedrock_object;
@@ -345,6 +351,20 @@ namespace detail
}
}
void process_msg(bedrock* brock, MSG& msg)
{
auto misc = brock->wd_manager().root_runtime(reinterpret_cast<native_window_type>(msg.hwnd));
if (misc && misc->wpassoc->accel && ::TranslateAccelerator(msg.hwnd, misc->wpassoc->accel, &msg))
return;
auto menu_wd = brock->get_menu(reinterpret_cast<native_window_type>(msg.hwnd), true);
if (menu_wd) interior_helper_for_menu(msg, menu_wd);
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
void bedrock::pump_event(window condition_wd, bool is_modal)
{
const unsigned tid = ::GetCurrentThreadId();
@@ -383,11 +403,15 @@ namespace detail
if (msg.message == WM_QUIT) break;
if ((WM_KEYFIRST <= msg.message && msg.message <= WM_KEYLAST) || !::IsDialogMessage(native_handle, &msg))
{
#if 0
auto menu_wd = get_menu(reinterpret_cast<native_window_type>(msg.hwnd), true);
if (menu_wd) interior_helper_for_menu(msg, menu_wd);
::TranslateMessage(&msg);
::TranslateMessage(&msg); //deprecated
::DispatchMessage(&msg);
#else
process_msg(this, msg);
#endif
wd_manager().remove_trash_handle(tid);
}
@@ -400,11 +424,15 @@ namespace detail
{
if (-1 != ::GetMessage(&msg, 0, 0, 0))
{
#if 0
auto menu_wd = get_menu(reinterpret_cast<native_window_type>(msg.hwnd), true);
if (menu_wd) interior_helper_for_menu(msg, menu_wd);
::TranslateMessage(&msg);
::DispatchMessage(&msg);
#else
process_msg(this, msg);
#endif
}
wd_manager().call_safe_place(tid);
@@ -420,11 +448,15 @@ namespace detail
{
if(-1 != ::GetMessage(&msg, 0, 0, 0))
{
#if 0
auto menu_wd = get_menu(reinterpret_cast<native_window_type>(msg.hwnd), true);
if(menu_wd) interior_helper_for_menu(msg, menu_wd);
::TranslateMessage(&msg);
::DispatchMessage(&msg);
#else
process_msg(this, msg);
#endif
}
wd_manager().call_safe_place(tid);
@@ -635,6 +667,7 @@ namespace detail
switch(msg)
{
case WM_COMMAND:
case WM_DESTROY:
case WM_SHOWWINDOW:
case WM_SIZING:
@@ -786,6 +819,17 @@ namespace detail
switch (message)
{
case WM_COMMAND:
if ((1 == HIWORD(wParam)) && root_runtime->wpassoc)
{
auto i = root_runtime->wpassoc->accel_commands.find(LOWORD(wParam));
if (i != root_runtime->wpassoc->accel_commands.end())
{
auto fn = i->second;
fn();
}
}
break;
case WM_IME_STARTCOMPOSITION:
if (msgwnd->other.attribute.root->ime_enabled)
{
@@ -1582,6 +1626,54 @@ namespace detail
kb.shift = (0 != (::GetKeyState(VK_SHIFT) & 0x80));
}
void bedrock::delete_platform_assoc(window_platform_assoc* passoc)
{
delete passoc;
}
//Generates an identitifer for an accel key.
std::pair<int, WORD> id_accel_key(const accel_key& key)
{
std::pair<int, WORD> ret;
//Use virt-key for non-case sensitive
if (!key.case_sensitive)
ret.second = static_cast<WORD>(std::tolower(key.key) - 'a' + 0x41);
ret.first = ret.second | int(key.case_sensitive ? (1 << 8) : 0) | int(key.alt ? (1 << 9) : 0) | int(key.ctrl ? (1 << 10) : 0) | int(key.shift ? (1 << 11) : 0);
return ret;
}
void bedrock::keyboard_accelerator(native_window_type wd, const accel_key& key, const std::function<void()>& fn)
{
auto misc = wd_manager().root_runtime(wd);
if (nullptr == misc)
return;
auto wpassoc = misc->wpassoc;
if (!misc->wpassoc)
misc->wpassoc = new window_platform_assoc;
auto idkey = id_accel_key(key);
misc->wpassoc->accel_commands[idkey.first] = fn;
auto accel_size = ::CopyAcceleratorTable(misc->wpassoc->accel, nullptr, 0);
std::unique_ptr<ACCEL[]> accels(new ACCEL[accel_size + 1]);
if (accel_size)
::CopyAcceleratorTable(misc->wpassoc->accel, accels.get(), accel_size);
auto p = accels.get() + accel_size;
p->cmd = idkey.first;
p->fVirt = (key.case_sensitive ? 0 : FVIRTKEY) | (key.alt ? FALT : 0) | (key.ctrl ? FCONTROL : 0) | (key.shift ? FSHIFT : 0);
p->key = idkey.second;
::DestroyAcceleratorTable(misc->wpassoc->accel);
misc->wpassoc->accel = ::CreateAcceleratorTable(accels.get(), accel_size + 1);
}
element_store& bedrock::get_element_store() const
{
return impl_->estore;

View File

@@ -0,0 +1,112 @@
/*
* Implementations of Inner Forward Declaration
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/detail/inner_fwd_implement.hpp
*
*/
#ifndef NANA_GUI_INNER_FWD_IMPLEMENT_HPP
#define NANA_GUI_INNER_FWD_IMPLEMENT_HPP
#include <nana/push_ignore_diagnostic>
#include <nana/gui/detail/inner_fwd.hpp>
#include <nana/gui/detail/basic_window.hpp>
#include <nana/paint/graphics.hpp>
#include <map>
namespace nana{
namespace detail
{
class shortkey_container
{
struct item_type;
//Noncopyable
shortkey_container(const shortkey_container&) = delete;
shortkey_container& operator=(const shortkey_container&) = delete;
shortkey_container& operator=(shortkey_container&&) = delete;
public:
shortkey_container();
shortkey_container(shortkey_container&&);
~shortkey_container();
void clear();
bool make(window wd, unsigned long key);
void umake(window wd);
std::vector<unsigned long> keys(window wd) const;
window find(unsigned long key) const;
private:
struct implementation;
implementation * impl_;
};
struct window_platform_assoc;
struct root_misc
{
basic_window * window;
window_platform_assoc * wpassoc{ nullptr };
nana::paint::graphics root_graph;
shortkey_container shortkeys;
struct condition_rep
{
bool ignore_tab; //ignore tab when the focus is changed by TAB key.
basic_window* pressed; //The handle to a window which has been pressed by mouse left button.
basic_window* pressed_by_space; //The handle to a window which has been pressed by SPACEBAR key.
basic_window* hovered; //the latest window that mouse moved
}condition;
root_misc(root_misc&&);
root_misc(basic_window * wd, unsigned width, unsigned height);
~root_misc();
private:
root_misc(const root_misc&) = delete;
root_misc& operator=(const root_misc&) = delete;
};//end struct root_misc
class root_register
{
//Noncopyable
root_register(const root_register&) = delete;
root_register& operator=(const root_register&) = delete;
//Nonmovable
root_register(root_register&&) = delete;
root_register& operator=(root_register&&) = delete;
public:
root_register();
~root_register();
root_misc* insert(native_window_type, root_misc&&);
root_misc * find(native_window_type);
void erase(native_window_type);
private:
struct implementation;
implementation * const impl_;
};
}
}//end namespace nana
#include <nana/pop_ignore_diagnostic>
#endif //NANA_GUI_INNER_FWD_IMPLEMENT_HPP

View File

@@ -1,7 +1,7 @@
/*
* Window Manager Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@@ -16,11 +16,11 @@
#include <nana/gui/detail/events_operation.hpp>
#include <nana/gui/detail/window_manager.hpp>
#include <nana/gui/detail/window_layout.hpp>
#include "window_register.hpp"
#include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/detail/inner_fwd_implement.hpp>
#include <nana/gui/layout_utility.hpp>
#include <nana/gui/detail/effects_renderer.hpp>
#include "window_register.hpp"
#include "inner_fwd_implement.hpp"
#include <stdexcept>
#include <algorithm>
@@ -140,10 +140,12 @@ namespace nana
//struct root_misc
root_misc::root_misc(root_misc&& other):
window(other.window),
wpassoc(other.wpassoc),
root_graph(std::move(other.root_graph)),
shortkeys(std::move(other.shortkeys)),
condition(std::move(other.condition))
{
other.wpassoc = nullptr; //moved-from
}
root_misc::root_misc(basic_window * wd, unsigned width, unsigned height)
@@ -155,6 +157,11 @@ namespace nana
condition.pressed_by_space = nullptr;
condition.hovered = nullptr;
}
root_misc::~root_misc()
{
bedrock::delete_platform_assoc(wpassoc);
}
//end struct root_misc
//class root_register

View File

@@ -1,6 +1,6 @@
/*
* A Form Implementation
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@@ -10,6 +10,7 @@
*/
#include <nana/gui/widgets/form.hpp>
#include <nana/gui/detail/bedrock.hpp>
namespace nana
{
@@ -94,6 +95,11 @@ namespace nana
{
API::wait_for(handle());
}
void form::keyboard_accelerator(const accel_key& key, const std::function<void()>& fn)
{
nana::detail::bedrock::instance().keyboard_accelerator(this->native_handle(), key, fn);
}
//end class form
//class nested_form