diff --git a/include/nana/gui/basis.hpp b/include/nana/gui/basis.hpp index 2cc656ca..cc31f862 100644 --- a/include/nana/gui/basis.hpp +++ b/include/nana/gui/basis.hpp @@ -4,7 +4,7 @@ * * Basis Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 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 @@ -30,6 +30,15 @@ namespace nana struct native_drawable_impl{}; } + struct accel_key + { + char key; + bool case_sensitive{ false }; + bool alt{ false }; + bool ctrl{ false }; + bool shift{ false }; + }; + enum class checkstate { unchecked, checked, partial diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp index 0db691b3..f0d3f63c 100644 --- a/include/nana/gui/detail/bedrock.hpp +++ b/include/nana/gui/detail/bedrock.hpp @@ -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 @@ -27,6 +27,7 @@ namespace detail struct basic_window; class window_manager; + struct window_platform_assoc; /// @brief fundamental core component, it provides an abstraction to the OS platform and some basic functions. class bedrock @@ -73,6 +74,11 @@ namespace detail //Closes the windows which are associated with the specified thread. If the given thread_id is 0, it closes all windows void close_thread_window(unsigned thread_id); + + public: + //Platform-dependent functions + static void delete_platform_assoc(window_platform_assoc*); + void keyboard_accelerator(native_window_type, const accel_key&, const std::function&); public: void event_expose(core_window_t *, bool exposed); void event_move(core_window_t*, int x, int y); diff --git a/include/nana/gui/widgets/form.hpp b/include/nana/gui/widgets/form.hpp index 77972a8b..6053a1d7 100644 --- a/include/nana/gui/widgets/form.hpp +++ b/include/nana/gui/widgets/form.hpp @@ -1,7 +1,7 @@ /** * A Form Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2015 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 @@ -68,6 +68,8 @@ namespace nana void modality() const; void wait_for_this(); + + void keyboard_accelerator(const accel_key&, const std::function& fn); }; class nested_form diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 5f4fa1fa..3e38d5ea 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -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 #include #include -#include #include #include #include +#include "inner_fwd_implement.hpp" #include #include @@ -222,6 +222,11 @@ namespace detail arg.shift = (xkey.state & ShiftMask); } + void bedrock::keyboard_accelerator(native_window_type, const accel_key&, const std::function& fn) + { + + } + element_store& bedrock::get_element_store() const { return impl_->estore; diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index 2d75e7d4..9618c47e 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -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 #include #include -#include #include #include #include #include +#include "inner_fwd_implement.hpp" #include //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> 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(msg.hwnd)); + + if (misc && misc->wpassoc->accel && ::TranslateAccelerator(msg.hwnd, misc->wpassoc->accel, &msg)) + return; + + auto menu_wd = brock->get_menu(reinterpret_cast(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(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(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(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 id_accel_key(const accel_key& key) + { + std::pair ret; + + //Use virt-key for non-case sensitive + if (!key.case_sensitive) + ret.second = static_cast(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& 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 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; diff --git a/include/nana/gui/detail/inner_fwd_implement.hpp b/source/gui/detail/inner_fwd_implement.hpp similarity index 86% rename from include/nana/gui/detail/inner_fwd_implement.hpp rename to source/gui/detail/inner_fwd_implement.hpp index 68937148..ed8ef73d 100644 --- a/include/nana/gui/detail/inner_fwd_implement.hpp +++ b/source/gui/detail/inner_fwd_implement.hpp @@ -1,7 +1,7 @@ /* * Implementations of Inner Forward Declaration * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 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,9 +15,9 @@ #define NANA_GUI_INNER_FWD_IMPLEMENT_HPP #include -#include "inner_fwd.hpp" -#include "basic_window.hpp" -#include "../../paint/graphics.hpp" +#include +#include +#include #include @@ -54,10 +54,13 @@ namespace nana{ 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; @@ -71,6 +74,10 @@ namespace nana{ 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 diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 4bfd1900..38add16a 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -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 #include #include -#include "window_register.hpp" #include -#include #include #include +#include "window_register.hpp" +#include "inner_fwd_implement.hpp" #include #include @@ -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 diff --git a/source/gui/widgets/form.cpp b/source/gui/widgets/form.cpp index 7f8247ff..9414a07b 100644 --- a/source/gui/widgets/form.cpp +++ b/source/gui/widgets/form.cpp @@ -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 +#include namespace nana { @@ -94,6 +95,11 @@ namespace nana { API::wait_for(handle()); } + + void form::keyboard_accelerator(const accel_key& key, const std::function& fn) + { + nana::detail::bedrock::instance().keyboard_accelerator(this->native_handle(), key, fn); + } //end class form //class nested_form