diff --git a/Import/GacUI.Windows.cpp b/Import/GacUI.Windows.cpp index 6a737242..09d70630 100644 --- a/Import/GacUI.Windows.cpp +++ b/Import/GacUI.Windows.cpp @@ -2086,6 +2086,11 @@ WindowsController { callbackService.InvokeClipboardUpdated(); } + + void InvokeGlobalShortcutkeyActivated(vint id) + { + callbackService.InvokeGlobalShortcutKeyActivated(id); + } }; /*********************************************************************** @@ -2119,6 +2124,12 @@ Windows Procedure case WM_CLIPBOARDUPDATE: windowsController->InvokeClipboardUpdated(); break; + case WM_HOTKEY: + if (wParam > 0) + { + windowsController->InvokeGlobalShortcutkeyActivated((vint)wParam); + } + break; } } return DefWindowProc(hwnd, uMsg, wParam, lParam); @@ -14351,6 +14362,25 @@ WindowsInputService vint index = keys.Keys().IndexOf(name); return index == -1 ? VKEY::KEY_UNKNOWN : keys.Values()[index]; } + + vint WindowsInputService::RegisterGlobalShortcutKey(bool ctrl, bool shift, bool alt, VKEY key) + { + UINT modifier = 0; + if (ctrl) modifier |= MOD_CONTROL; + if (shift) modifier |= MOD_SHIFT; + if (alt) modifier |= MOD_ALT; + + vint id = ++usedHotKeys; + BOOL result = RegisterHotKey(ownerHandle, (int)id, modifier, (UINT)key); + if (result == 0) return (vint)NativeGlobalShortcutKeyResult::Occupied; + return id; + } + + bool WindowsInputService::UnregisterGlobalShortcutKey(vint id) + { + BOOL result = UnregisterHotKey(ownerHandle, (int)id); + return result != 0; + } } } } diff --git a/Import/GacUI.Windows.h b/Import/GacUI.Windows.h index eb847ed3..fc0a87f0 100644 --- a/Import/GacUI.Windows.h +++ b/Import/GacUI.Windows.h @@ -2112,6 +2112,7 @@ namespace vl protected: HWND ownerHandle; bool isTimerEnabled; + vint usedHotKeys = (vint)NativeGlobalShortcutKeyResult::ValidIdBegins; collections::Array keyNames; collections::Dictionary keys; @@ -2129,6 +2130,8 @@ namespace vl bool IsKeyToggled(VKEY code)override; WString GetKeyName(VKEY code)override; VKEY GetKey(const WString& name)override; + vint RegisterGlobalShortcutKey(bool ctrl, bool shift, bool alt, VKEY key)override; + bool UnregisterGlobalShortcutKey(vint id)override; }; extern bool WinIsKeyPressing(VKEY code); diff --git a/Import/GacUI.cpp b/Import/GacUI.cpp index af5c2e71..53562196 100644 --- a/Import/GacUI.cpp +++ b/Import/GacUI.cpp @@ -185,6 +185,52 @@ namespace vl using namespace theme; using namespace description; +/*********************************************************************** +GuiGlobalShortcutKeyManager +***********************************************************************/ + + class GuiGlobalShortcutKeyManager : public GuiShortcutKeyManager + { + protected: + Dictionary idToItemsMap; + Dictionary itemToIdsMap; + + bool IsGlobal() override + { + return true; + } + + bool OnCreatingShortcut(GuiShortcutKeyItem* item) override + { + bool ctrl, shift, alt; + VKEY key; + item->ReadKeyConfig(ctrl, shift, alt, key); + + vint id = GetCurrentController()->InputService()->RegisterGlobalShortcutKey(ctrl, shift, alt, key); + if (id < (vint)NativeGlobalShortcutKeyResult::ValidIdBegins) return false; + + idToItemsMap.Add(id, item); + itemToIdsMap.Add(item, id); + return true; + } + + void OnDestroyingShortcut(GuiShortcutKeyItem* item) override + { + vint id = itemToIdsMap[item]; + idToItemsMap.Remove(id); + itemToIdsMap.Remove(item); + GetCurrentController()->InputService()->UnregisterGlobalShortcutKey(id); + } + + public: + + GuiShortcutKeyItem* TryGetItemFromId(vint id) + { + vint index = idToItemsMap.Keys().IndexOf(id); + return index == -1 ? nullptr : idToItemsMap.Values()[index]; + } + }; + /*********************************************************************** GuiApplication ***********************************************************************/ @@ -211,9 +257,19 @@ GuiApplication } } + void GuiApplication::GlobalShortcutKeyActivated(vint id) + { + auto manager = dynamic_cast(globalShortcutKeyManager.Obj()); + if (auto item = manager->TryGetItemFromId(id)) + { + item->Execute(); + } + } + GuiApplication::GuiApplication() :locale(Locale::UserDefault()) { + globalShortcutKeyManager = Ptr(new GuiGlobalShortcutKeyManager); GetCurrentController()->CallbackService()->InstallListener(this); } @@ -425,6 +481,11 @@ GuiApplication return sharedTooltipOwner; } + compositions::IGuiShortcutKeyManager* GuiApplication::GetGlobalShortcutKeyManager() + { + return globalShortcutKeyManager.Obj(); + } + WString GuiApplication::GetExecutablePath() { return GetCurrentController()->GetExecutablePath(); @@ -5438,8 +5499,9 @@ namespace vl GuiShortcutKeyItem ***********************************************************************/ - GuiShortcutKeyItem::GuiShortcutKeyItem(GuiShortcutKeyManager* _shortcutKeyManager, bool _ctrl, bool _shift, bool _alt, VKEY _key) + GuiShortcutKeyItem::GuiShortcutKeyItem(GuiShortcutKeyManager* _shortcutKeyManager, bool _global, bool _ctrl, bool _shift, bool _alt, VKEY _key) :shortcutKeyManager(_shortcutKeyManager) + ,global(_global) ,ctrl(_ctrl) ,shift(_shift) ,alt(_alt) @@ -5459,13 +5521,23 @@ GuiShortcutKeyItem WString GuiShortcutKeyItem::GetName() { WString name; - if(ctrl) name+=L"Ctrl+"; - if(shift) name+=L"Shift+"; - if(alt) name+=L"Alt+"; - name+=GetCurrentController()->InputService()->GetKeyName(key); + if (global) name += L"{"; + if (ctrl) name += L"Ctrl+"; + if (shift) name += L"Shift+"; + if (alt) name += L"Alt+"; + name += GetCurrentController()->InputService()->GetKeyName(key); + if (global) name += L"}"; return name; } + void GuiShortcutKeyItem::ReadKeyConfig(bool& _ctrl, bool& _shift, bool& _alt, VKEY& _key) + { + _ctrl = ctrl; + _shift = shift; + _alt = alt; + _key = key; + } + bool GuiShortcutKeyItem::CanActivate(const NativeWindowKeyInfo& info) { return @@ -5484,16 +5556,48 @@ GuiShortcutKeyItem _key==key; } + void GuiShortcutKeyItem::Execute() + { + GuiEventArgs arguments; + Executed.Execute(arguments); + } + /*********************************************************************** GuiShortcutKeyManager ***********************************************************************/ + bool GuiShortcutKeyManager::IsGlobal() + { + return false; + } + + bool GuiShortcutKeyManager::OnCreatingShortcut(GuiShortcutKeyItem* item) + { + return true; + } + + void GuiShortcutKeyManager::OnDestroyingShortcut(GuiShortcutKeyItem* item) + { + } + + IGuiShortcutKeyItem* GuiShortcutKeyManager::CreateShortcutInternal(bool ctrl, bool shift, bool alt, VKEY key) + { + auto item = Ptr(new GuiShortcutKeyItem(this, IsGlobal(), ctrl, shift, alt, key)); + if (!OnCreatingShortcut(item.Obj())) return nullptr; + shortcutKeyItems.Add(item); + return item.Obj(); + } + GuiShortcutKeyManager::GuiShortcutKeyManager() { } GuiShortcutKeyManager::~GuiShortcutKeyManager() { + for (auto item : shortcutKeyItems) + { + OnDestroyingShortcut(item.Obj()); + } } vint GuiShortcutKeyManager::GetItemCount() @@ -5513,51 +5617,55 @@ GuiShortcutKeyManager { if(item->CanActivate(info)) { - GuiEventArgs arguments; - item->Executed.Execute(arguments); + item->Execute(); executed=true; } } return executed; } - IGuiShortcutKeyItem* GuiShortcutKeyManager::CreateShortcut(bool ctrl, bool shift, bool alt, VKEY key) - { - for (auto item : shortcutKeyItems) - { - if(item->CanActivate(ctrl, shift, alt, key)) - { - return item.Obj(); - } - } - auto item=Ptr(new GuiShortcutKeyItem(this, ctrl, shift, alt, key)); - shortcutKeyItems.Add(item); - return item.Obj(); - } - - bool GuiShortcutKeyManager::DestroyShortcut(bool ctrl, bool shift, bool alt, VKEY key) - { - for (auto item : shortcutKeyItems) - { - if(item->CanActivate(ctrl, shift, alt, key)) - { - shortcutKeyItems.Remove(item.Obj()); - return true; - } - } - return false; - } - IGuiShortcutKeyItem* GuiShortcutKeyManager::TryGetShortcut(bool ctrl, bool shift, bool alt, VKEY key) { for (auto item : shortcutKeyItems) { - if(item->CanActivate(ctrl, shift, alt, key)) + if (item->CanActivate(ctrl, shift, alt, key)) { return item.Obj(); } } - return 0; + return nullptr; + } + + IGuiShortcutKeyItem* GuiShortcutKeyManager::CreateNewShortcut(bool ctrl, bool shift, bool alt, VKEY key) + { + CHECK_ERROR( + TryGetShortcut(ctrl, shift, alt, key) == nullptr, + L"vl::presentation::compositions::GuiShortcutKeyManager::CreateNewShortcut(bool, bool, bool, VKEY)#The shortcut key exists." + ); + return CreateShortcutInternal(ctrl, shift, alt, key); + } + + IGuiShortcutKeyItem* GuiShortcutKeyManager::CreateShortcutIfNotExist(bool ctrl, bool shift, bool alt, VKEY key) + { + if (TryGetShortcut(ctrl, shift, alt, key)) + { + return nullptr; + } + return CreateShortcutInternal(ctrl, shift, alt, key); + } + + bool GuiShortcutKeyManager::DestroyShortcut(IGuiShortcutKeyItem* item) + { + if (!item) return false; + if (item->GetManager() != this) return false; + + auto skItem = dynamic_cast(item); + if (!skItem) return false; + + vint index = shortcutKeyItems.IndexOf(skItem); + if (index == -1) return false; + OnDestroyingShortcut(skItem); + return shortcutKeyItems.RemoveAt(index); } } } @@ -16005,6 +16113,7 @@ GuiVirtualTreeListControl } } break; + default:; } } @@ -18089,7 +18198,7 @@ GuiDocumentCommonInterface void GuiDocumentCommonInterface::AddShortcutCommand(VKEY key, const Func& eventHandler) { - IGuiShortcutKeyItem* item=internalShortcutKeyManager->CreateShortcut(true, false, false, key); + IGuiShortcutKeyItem* item=internalShortcutKeyManager->CreateNewShortcut(true, false, false, key); item->Executed.AttachLambda([=](GuiGraphicsComposition* sender, GuiEventArgs& arguments) { eventHandler(); @@ -19712,7 +19821,7 @@ GuiTextBoxCommonInterface void GuiTextBoxCommonInterface::AddShortcutCommand(VKEY key, const Func& eventHandler) { - IGuiShortcutKeyItem* item=internalShortcutKeyManager->CreateShortcut(true, false, false, key); + IGuiShortcutKeyItem* item=internalShortcutKeyManager->CreateNewShortcut(true, false, false, key); item->Executed.AttachLambda([=](GuiGraphicsComposition* sender, GuiEventArgs& arguments) { eventHandler(); @@ -26058,25 +26167,37 @@ GuiToolstripCommand DescriptionChanged.Execute(arguments); } - void GuiToolstripCommand::ReplaceShortcut(compositions::IGuiShortcutKeyItem* value, Ptr builder) + compositions::IGuiShortcutKeyManager* GuiToolstripCommand::GetShortcutManagerFromBuilder(Ptr builder) + { + if (builder->global) + { + return GetApplication()->GetGlobalShortcutKeyManager(); + } + else + { + if (attachedControlHost) + { + if (!attachedControlHost->GetShortcutKeyManager()) + { + attachedControlHost->SetShortcutKeyManager(new GuiShortcutKeyManager()); + } + return attachedControlHost->GetShortcutKeyManager(); + } + } + return nullptr; + } + + void GuiToolstripCommand::ReplaceShortcut(compositions::IGuiShortcutKeyItem* value) { if (shortcutKeyItem != value) { if (shortcutKeyItem) { shortcutKeyItem->Executed.Detach(shortcutKeyItemExecutedHandler); - if (shortcutBuilder) - { - auto manager = dynamic_cast(shortcutOwner->GetShortcutKeyManager()); - if (manager) - { - manager->DestroyShortcut(shortcutBuilder->ctrl, shortcutBuilder->shift, shortcutBuilder->alt, shortcutBuilder->key); - } - } + shortcutKeyItem->GetManager()->DestroyShortcut(shortcutKeyItem); } shortcutKeyItem = nullptr; shortcutKeyItemExecutedHandler = nullptr; - shortcutBuilder = value ? builder : nullptr; if (value) { shortcutKeyItem = value; @@ -26091,30 +26212,15 @@ GuiToolstripCommand List errors; if (auto parser = GetParserManager()->GetParser(L"SHORTCUT")) { - if (Ptr builder = parser->ParseInternal(builderText, errors)) + if (auto builder = parser->ParseInternal(builderText, errors)) { - if (shortcutOwner) + shortcutBuilder = builder; + if (auto shortcutKeyManager = GetShortcutManagerFromBuilder(builder)) { - if (!shortcutOwner->GetShortcutKeyManager()) + if (auto item = shortcutKeyManager->CreateShortcutIfNotExist(builder->ctrl, builder->shift, builder->alt, builder->key)) { - shortcutOwner->SetShortcutKeyManager(new GuiShortcutKeyManager); + ReplaceShortcut(item); } - if (auto manager = dynamic_cast(shortcutOwner->GetShortcutKeyManager())) - { - IGuiShortcutKeyItem* item = manager->TryGetShortcut(builder->ctrl, builder->shift, builder->alt, builder->key); - if (!item) - { - item = manager->CreateShortcut(builder->ctrl, builder->shift, builder->alt, builder->key); - if (item) - { - ReplaceShortcut(item, builder); - } - } - } - } - else - { - shortcutBuilder = builder; } } } @@ -26132,16 +26238,15 @@ GuiToolstripCommand host = composition->GetRelatedControlHost(); } - if (shortcutOwner != host) + if (attachedControlHost != host) { - if (shortcutOwner) - { - ReplaceShortcut(nullptr, nullptr); - shortcutOwner = nullptr; - } - shortcutOwner = host; - if (shortcutBuilder && !shortcutKeyItem) + attachedControlHost = host; + if (shortcutBuilder && !shortcutBuilder->global) { + if (shortcutKeyItem) + { + ReplaceShortcut(nullptr); + } BuildShortcut(shortcutBuilder->text); } } @@ -26153,6 +26258,10 @@ GuiToolstripCommand GuiToolstripCommand::~GuiToolstripCommand() { + if (shortcutBuilder && shortcutKeyItem) + { + ReplaceShortcut(nullptr); + } } void GuiToolstripCommand::Attach(GuiInstanceRootObject* rootObject) @@ -26246,11 +26355,6 @@ GuiToolstripCommand return shortcutKeyItem; } - void GuiToolstripCommand::SetShortcut(compositions::IGuiShortcutKeyItem* value) - { - ReplaceShortcut(value, 0); - } - WString GuiToolstripCommand::GetShortcutBuilder() { return shortcutBuilder ? shortcutBuilder->text : L""; @@ -26298,13 +26402,15 @@ GuiToolstripCommand::ShortcutBuilder Parser typedef GuiToolstripCommand::ShortcutBuilder ShortcutBuilder; public: Regex regexShortcut; + const vint _global; const vint _ctrl; const vint _shift; const vint _alt; const vint _key; GuiToolstripCommandShortcutParser() - : regexShortcut(L"((Ctrl)/+|(Shift)/+|(Alt)/+)*(/.+)") + : regexShortcut(L"((global:))?((Ctrl)/+|(Shift)/+|(Alt)/+)*(/.+)") + , _global(regexShortcut.CaptureNames().IndexOf(L"global")) , _ctrl(regexShortcut.CaptureNames().IndexOf(L"ctrl")) , _shift(regexShortcut.CaptureNames().IndexOf(L"shift")) , _alt(regexShortcut.CaptureNames().IndexOf(L"alt")) @@ -26325,6 +26431,7 @@ GuiToolstripCommand::ShortcutBuilder Parser auto builder = Ptr(new ShortcutBuilder); builder->text = text; + builder->global = match->Groups().Contains(_global); builder->ctrl = match->Groups().Contains(_ctrl); builder->shift = match->Groups().Contains(_shift); builder->alt = match->Groups().Contains(_alt); @@ -33793,6 +33900,10 @@ INativeControllerListener { } + void INativeControllerListener::GlobalShortcutKeyActivated(vint id) + { + } + void INativeControllerListener::NativeWindowCreated(INativeWindow* window) { } @@ -34207,6 +34318,16 @@ public: { CHECK_FAIL(L"Not implemented!"); } + + vint RegisterGlobalShortcutKey(bool ctrl, bool shift, bool alt, VKEY key) override + { + CHECK_FAIL(L"Not Implemented!"); + } + + bool UnregisterGlobalShortcutKey(vint id) override + { + CHECK_FAIL(L"Not Implemented!"); + } }; extern void GuiApplicationMain(); @@ -34974,6 +35095,11 @@ GuiHostedController::INativeControllerListener callbackService.InvokeClipboardUpdated(); } + void GuiHostedController::GlobalShortcutKeyActivated(vint id) + { + callbackService.InvokeGlobalShortcutKeyActivated(id); + } + void GuiHostedController::NativeWindowDestroying(INativeWindow* window) { if (nativeWindow == window) @@ -54633,6 +54759,14 @@ SharedCallbackService } } + void SharedCallbackService::InvokeGlobalShortcutKeyActivated(vint id) + { + for (vint i = 0; i < listeners.Count(); i++) + { + listeners[i]->GlobalShortcutKeyActivated(id); + } + } + void SharedCallbackService::InvokeNativeWindowCreated(INativeWindow* window) { for(vint i=0;i /// User input service. To access this service, use [M:vl.presentation.INativeController.InputService]. /// class INativeInputService : public virtual IDescriptable, public Description { - public: + public: /// /// Start to reveive global timer message. /// - virtual void StartTimer()=0; + virtual void StartTimer()=0; /// /// Stop to receive global timer message. /// - virtual void StopTimer()=0; + virtual void StopTimer()=0; /// /// Test is the global timer message receiving enabled. /// /// Returns true if the global timer message receiving is enabled. - virtual bool IsTimerEnabled()=0; + virtual bool IsTimerEnabled()=0; /// /// Test is the specified key pressing. /// /// Returns true if the specified key is pressing. /// The key code to test. - virtual bool IsKeyPressing(VKEY code)=0; + virtual bool IsKeyPressing(VKEY code)=0; /// /// Test is the specified key toggled. /// /// Returns true if the specified key is toggled. /// The key code to test. - virtual bool IsKeyToggled(VKEY code)=0; + virtual bool IsKeyToggled(VKEY code)=0; /// /// Get the name of a key. /// /// The name of a key. /// The key code. - virtual WString GetKeyName(VKEY code)=0; + virtual WString GetKeyName(VKEY code)=0; /// /// Get the key from a name. /// /// The key, returns -1 if the key name doesn't exist. /// Key name - virtual VKEY GetKey(const WString& name)=0; + virtual VKEY GetKey(const WString& name)=0; + + /// + /// Register a system-wide shortcut key that doesn't require any window to be foreground window. + /// If the shortcut key is activated, will be called. + /// + /// Set to true if the CTRL key is required. + /// Set to true if the SHIFT key is required. + /// Set to true if the ALT key is required. + /// The non-control key. + /// + /// Returns the created id. If it fails, the id equals to one of an item in except "ValidIdBegins". + virtual vint RegisterGlobalShortcutKey(bool ctrl, bool shift, bool alt, VKEY key)=0; + + /// + /// Unregister a system-wide shortcut key. + /// + /// The created id. + /// Returns true if this operation succeeded. + virtual bool UnregisterGlobalShortcutKey(vint id)=0; }; /*********************************************************************** @@ -2927,6 +2953,10 @@ INativeCallbackService /// virtual void InvokeClipboardUpdated()=0; /// + /// Invoke of all installed listeners. + /// + virtual void InvokeGlobalShortcutKeyActivated(vint id) = 0; + /// /// Invoke of all installed listeners. /// /// The argument to the callback. @@ -3249,6 +3279,11 @@ Native Window Controller /// virtual void ClipboardUpdated(); /// + /// Called when a registered system-wide shortcut key is activated. + /// + /// + virtual void GlobalShortcutKeyActivated(vint id); + /// /// Called when a window is created. /// /// The created window. @@ -4514,6 +4549,32 @@ Shortcut Key Manager /// Returns true if at least one shortcut key item is executed. /// The key event info. virtual bool Execute(const NativeWindowKeyInfo& info)=0; + + /// Get a shortcut key item using a key combination. If the item for the key combination does not exist, this function returns null. + /// The shortcut key item. + /// Set to true if the CTRL key is required. + /// Set to true if the SHIFT key is required. + /// Set to true if the ALT key is required. + /// The non-control key. + virtual IGuiShortcutKeyItem* TryGetShortcut(bool ctrl, bool shift, bool alt, VKEY key)=0; + /// Create a shortcut key item using a key combination. If the item for the key combination exists, this function crashes. + /// The created shortcut key item. + /// Set to true if the CTRL key is required. + /// Set to true if the SHIFT key is required. + /// Set to true if the ALT key is required. + /// The non-control key. + virtual IGuiShortcutKeyItem* CreateNewShortcut(bool ctrl, bool shift, bool alt, VKEY key)=0; + /// Create a shortcut key item using a key combination. If the item for the key combination exists, this function returns the item that is created before. + /// The created shortcut key item. + /// Set to true if the CTRL key is required. + /// Set to true if the SHIFT key is required. + /// Set to true if the ALT key is required. + /// The non-control key. + virtual IGuiShortcutKeyItem* CreateShortcutIfNotExist(bool ctrl, bool shift, bool alt, VKEY key)=0; + /// Destroy a shortcut key item using a key combination + /// Returns true if the manager destroyed a existing shortcut key item. + /// The shortcut key item. + virtual bool DestroyShortcut(IGuiShortcutKeyItem* item)=0; }; /*********************************************************************** @@ -4526,21 +4587,23 @@ Shortcut Key Manager Helpers { protected: GuiShortcutKeyManager* shortcutKeyManager; + bool global; bool ctrl; bool shift; bool alt; VKEY key; - void AttachManager(GuiShortcutKeyManager* manager); - void DetachManager(GuiShortcutKeyManager* manager); public: - GuiShortcutKeyItem(GuiShortcutKeyManager* _shortcutKeyManager, bool _ctrl, bool _shift, bool _alt, VKEY _key); + GuiShortcutKeyItem(GuiShortcutKeyManager* _shortcutKeyManager, bool _global, bool _ctrl, bool _shift, bool _alt, VKEY _key); ~GuiShortcutKeyItem(); IGuiShortcutKeyManager* GetManager()override; WString GetName()override; + + void ReadKeyConfig(bool& _ctrl, bool& _shift, bool& _alt, VKEY& _key); bool CanActivate(const NativeWindowKeyInfo& info); bool CanActivate(bool _ctrl, bool _shift, bool _alt, VKEY _key); + void Execute(); }; /// A default implementation for . @@ -4549,7 +4612,11 @@ Shortcut Key Manager Helpers typedef collections::List> ShortcutKeyItemList; protected: ShortcutKeyItemList shortcutKeyItems; - + + virtual bool IsGlobal(); + virtual bool OnCreatingShortcut(GuiShortcutKeyItem* item); + virtual void OnDestroyingShortcut(GuiShortcutKeyItem* item); + IGuiShortcutKeyItem* CreateShortcutInternal(bool ctrl, bool shift, bool alt, VKEY key); public: /// Create the shortcut key manager. GuiShortcutKeyManager(); @@ -4558,28 +4625,11 @@ Shortcut Key Manager Helpers vint GetItemCount()override; IGuiShortcutKeyItem* GetItem(vint index)override; bool Execute(const NativeWindowKeyInfo& info)override; - - /// Create a shortcut key item using a key combination. If the item for the key combination exists, this function returns the item that is created before. - /// The created shortcut key item. - /// Set to true if the CTRL key is required. - /// Set to true if the SHIFT key is required. - /// Set to true if the ALT key is required. - /// The non-control key. - IGuiShortcutKeyItem* CreateShortcut(bool ctrl, bool shift, bool alt, VKEY key); - /// Destroy a shortcut key item using a key combination - /// Returns true if the manager destroyed a existing shortcut key item. - /// Set to true if the CTRL key is required. - /// Set to true if the SHIFT key is required. - /// Set to true if the ALT key is required. - /// The non-control key. - bool DestroyShortcut(bool ctrl, bool shift, bool alt, VKEY key); - /// Get a shortcut key item using a key combination. If the item for the key combination does not exist, this function returns null. - /// The shortcut key item. - /// Set to true if the CTRL key is required. - /// Set to true if the SHIFT key is required. - /// Set to true if the ALT key is required. - /// The non-control key. - IGuiShortcutKeyItem* TryGetShortcut(bool ctrl, bool shift, bool alt, VKEY key); + + IGuiShortcutKeyItem* TryGetShortcut(bool ctrl, bool shift, bool alt, VKEY key)override; + IGuiShortcutKeyItem* CreateNewShortcut(bool ctrl, bool shift, bool alt, VKEY key)override; + IGuiShortcutKeyItem* CreateShortcutIfNotExist(bool ctrl, bool shift, bool alt, VKEY key)override; + bool DestroyShortcut(IGuiShortcutKeyItem* item)override; }; } } @@ -9783,6 +9833,7 @@ Application void InvokeClipboardNotify(compositions::GuiGraphicsComposition* composition, compositions::GuiEventArgs& arguments); void ClipboardUpdated()override; + void GlobalShortcutKeyActivated(vint id)override; protected: using WindowMap = collections::Dictionary; @@ -9797,6 +9848,7 @@ Application collections::List windows; WindowMap windowMap; collections::SortedList openingPopups; + Ptr globalShortcutKeyManager; GuiApplication(); ~GuiApplication(); @@ -9853,6 +9905,9 @@ Application /// Get the tooltip owner. When the tooltip closed, it returns null. /// The tooltip owner. GuiControl* GetTooltipOwner(); + /// Get the attached with this control host. + /// The shortcut key manager. + compositions::IGuiShortcutKeyManager* GetGlobalShortcutKeyManager(); /// Get the file path of the current executable. /// The file path of the current executable. WString GetExecutablePath(); @@ -10334,6 +10389,7 @@ namespace vl namespace compositions { class IGuiShortcutKeyItem; + class IGuiShortcutKeyManager; } namespace controls @@ -10346,10 +10402,11 @@ namespace vl { public: WString text; - bool ctrl; - bool shift; - bool alt; - VKEY key; + bool global = false; + bool ctrl = false; + bool shift = false; + bool alt = false; + VKEY key = VKEY::KEY_UNKNOWN; }; protected: Ptr image; @@ -10362,13 +10419,15 @@ namespace vl Ptr shortcutBuilder; GuiInstanceRootObject* attachedRootObject = nullptr; + GuiControlHost* attachedControlHost = nullptr; Ptr renderTargetChangedHandler; - GuiControlHost* shortcutOwner = nullptr; void OnShortcutKeyItemExecuted(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments); void OnRenderTargetChanged(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments); void InvokeDescriptionChanged(); - void ReplaceShortcut(compositions::IGuiShortcutKeyItem* value, Ptr builder); + + compositions::IGuiShortcutKeyManager* GetShortcutManagerFromBuilder(Ptr builder); + void ReplaceShortcut(compositions::IGuiShortcutKeyItem* value); void BuildShortcut(const WString& builderText); void UpdateShortcutOwner(); public: @@ -10406,9 +10465,6 @@ namespace vl /// Get the shortcut key item for this command. /// The shortcut key item for this command. compositions::IGuiShortcutKeyItem* GetShortcut(); - /// Set the shortcut key item for this command. - /// The shortcut key item for this command. - void SetShortcut(compositions::IGuiShortcutKeyItem* value); /// Get the shortcut builder for this command. /// The shortcut builder for this command. WString GetShortcutBuilder(); @@ -25016,6 +25072,7 @@ namespace vl void InvokeGlobalTimer() override; void InvokeClipboardUpdated() override; + void InvokeGlobalShortcutKeyActivated(vint id) override; void InvokeNativeWindowCreated(INativeWindow* window) override; void InvokeNativeWindowDestroying(INativeWindow* window) override; }; @@ -25182,6 +25239,7 @@ GuiHostedController void GlobalTimer() override; void ClipboardUpdated() override; + void GlobalShortcutKeyActivated(vint id) override; void NativeWindowDestroying(INativeWindow* window) override; // ============================================================= diff --git a/Import/GacUIReflection.cpp b/Import/GacUIReflection.cpp index 87ffe3a6..33df9a91 100644 --- a/Import/GacUIReflection.cpp +++ b/Import/GacUIReflection.cpp @@ -581,11 +581,20 @@ Type Declaration CLASS_MEMBER_METHOD_OVERLOAD(GetScreen, {L"window"}, INativeScreen*(INativeScreenService::*)(INativeWindow*)) END_INTERFACE_MEMBER(INativeScreenService) + BEGIN_ENUM_ITEM(NativeGlobalShortcutKeyResult) + ENUM_ITEM_NAMESPACE(NativeGlobalShortcutKeyResult) + ENUM_NAMESPACE_ITEM(NotSupported) + ENUM_NAMESPACE_ITEM(Occupied) + ENUM_NAMESPACE_ITEM(ValidIdBegins) + END_ENUM_ITEM(NativeGlobalShortcutKeyResult) + BEGIN_INTERFACE_MEMBER_NOPROXY(INativeInputService) CLASS_MEMBER_METHOD(IsKeyPressing, { L"code" }) CLASS_MEMBER_METHOD(IsKeyToggled, { L"code" }) CLASS_MEMBER_METHOD(GetKeyName, { L"code" }) CLASS_MEMBER_METHOD(GetKey, { L"name" }) + CLASS_MEMBER_METHOD(RegisterGlobalShortcutKey, { L"ctrl" _ L"shift" _ L"alt" _ L"key" }) + CLASS_MEMBER_METHOD(UnregisterGlobalShortcutKey, { L"id" }) END_INTERFACE_MEMBER(INativeInputService) BEGIN_ENUM_ITEM(INativeDialogService::MessageBoxButtonsInput) @@ -1204,15 +1213,15 @@ Type Declaration (Extra) CLASS_MEMBER_PROPERTY_READONLY_FAST(ItemCount) CLASS_MEMBER_METHOD(GetItem, {L"index"}) + CLASS_MEMBER_METHOD(TryGetShortcut, { L"ctrl" _ L"shift" _ L"alt" _ L"ket" }) + CLASS_MEMBER_METHOD(CreateNewShortcut, { L"ctrl" _ L"shift" _ L"alt" _ L"ket" }) + CLASS_MEMBER_METHOD(CreateShortcutIfNotExist, { L"ctrl" _ L"shift" _ L"alt" _ L"ket" }) + CLASS_MEMBER_METHOD(DestroyShortcut, { L"ctrl" _ L"shift" _ L"alt" _ L"ket" }) END_INTERFACE_MEMBER(IGuiShortcutKeyManager) BEGIN_CLASS_MEMBER(GuiShortcutKeyManager) CLASS_MEMBER_BASE(IGuiShortcutKeyManager) CLASS_MEMBER_CONSTRUCTOR(GuiShortcutKeyManager*(), NO_PARAMETER) - - CLASS_MEMBER_METHOD(CreateShortcut, {L"ctrl" _ L"shift" _ L"alt" _ L"ket"}) - CLASS_MEMBER_METHOD(DestroyShortcut, {L"ctrl" _ L"shift" _ L"alt" _ L"ket"}) - CLASS_MEMBER_METHOD(TryGetShortcut, {L"ctrl" _ L"shift" _ L"alt" _ L"ket"}) END_CLASS_MEMBER(GuiShortcutKeyManager) BEGIN_INTERFACE_MEMBER_NOPROXY(IGuiAltAction) @@ -1650,6 +1659,7 @@ Type Declaration (Extra) CLASS_MEMBER_PROPERTY_READONLY_FAST(ExecutablePath) CLASS_MEMBER_PROPERTY_READONLY_FAST(ExecutableFolder) CLASS_MEMBER_PROPERTY_READONLY_FAST(Windows) + CLASS_MEMBER_PROPERTY_READONLY_FAST(GlobalShortcutKeyManager) CLASS_MEMBER_METHOD(Run, {L"mainWindow"}) CLASS_MEMBER_METHOD(RunOneCycle, NO_PARAMETER) @@ -2095,7 +2105,7 @@ Type Declaration (Extra) CLASS_MEMBER_PROPERTY_EVENT_FAST(LargeImage, DescriptionChanged) CLASS_MEMBER_PROPERTY_EVENT_FAST(Image, DescriptionChanged) CLASS_MEMBER_PROPERTY_EVENT_FAST(Text, DescriptionChanged) - CLASS_MEMBER_PROPERTY_EVENT_FAST(Shortcut, DescriptionChanged) + CLASS_MEMBER_PROPERTY_EVENT_READONLY_FAST(Shortcut, DescriptionChanged) CLASS_MEMBER_PROPERTY_EVENT_FAST(ShortcutBuilder, DescriptionChanged) CLASS_MEMBER_PROPERTY_EVENT_FAST(Enabled, DescriptionChanged) CLASS_MEMBER_PROPERTY_EVENT_FAST(Selected, DescriptionChanged) diff --git a/Import/GacUIReflection.h b/Import/GacUIReflection.h index cc852c17..33910604 100644 --- a/Import/GacUIReflection.h +++ b/Import/GacUIReflection.h @@ -147,6 +147,7 @@ Type List (Basic) F(presentation::INativeClipboardWriter)\ F(presentation::INativeClipboardService)\ F(presentation::INativeScreenService)\ + F(presentation::NativeGlobalShortcutKeyResult)\ F(presentation::INativeInputService)\ F(presentation::INativeDialogService::MessageBoxButtonsInput)\ F(presentation::INativeDialogService::MessageBoxButtonsOutput)\ diff --git a/Import/VlppReflection.cpp b/Import/VlppReflection.cpp index 4ace6121..a4bb87ec 100644 --- a/Import/VlppReflection.cpp +++ b/Import/VlppReflection.cpp @@ -4531,7 +4531,6 @@ Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #include -#include namespace vl { diff --git a/Import/VlppReflection.h b/Import/VlppReflection.h index 8551f83a..d2350342 100644 --- a/Import/VlppReflection.h +++ b/Import/VlppReflection.h @@ -2833,6 +2833,9 @@ Licensed under https://github.com/vczh-libraries/License #ifndef VCZH_REFLECTION_TYPES_TYPEDVALUESERIALIZERPROVIDER #define VCZH_REFLECTION_TYPES_TYPEDVALUESERIALIZERPROVIDER +#ifdef VCZH_GCC +#include +#endif namespace vl { @@ -2841,10 +2844,87 @@ namespace vl namespace description { /*********************************************************************** +Constants +***********************************************************************/ + + template + struct TypedValueSerializerMinMax; + + template<> + struct TypedValueSerializerMinMax + { + static constexpr vint8_t Min = _I8_MIN; + static constexpr vint8_t Max = _I8_MAX; + }; + + template<> + struct TypedValueSerializerMinMax + { + static constexpr vint16_t Min = _I16_MIN; + static constexpr vint16_t Max = _I16_MAX; + }; + + template<> + struct TypedValueSerializerMinMax + { + static constexpr vint32_t Min = _I32_MIN; + static constexpr vint32_t Max = _I32_MAX; + }; + + template<> + struct TypedValueSerializerMinMax + { + static constexpr vint64_t Min = _I64_MIN; + static constexpr vint64_t Max = _I64_MAX; + }; + + template<> + struct TypedValueSerializerMinMax + { + static constexpr vuint8_t Min = 0; + static constexpr vuint8_t Max = _UI8_MAX; + }; + + template<> + struct TypedValueSerializerMinMax + { + static constexpr vuint16_t Min = 0; + static constexpr vuint16_t Max = _UI16_MAX; + }; + + template<> + struct TypedValueSerializerMinMax + { + static constexpr vuint32_t Min = 0; + static constexpr vuint32_t Max = _UI32_MAX; + }; + + template<> + struct TypedValueSerializerMinMax + { + static constexpr vuint64_t Min = 0; + static constexpr vuint64_t Max = _UI64_MAX; + }; + + template<> + struct TypedValueSerializerMinMax + { + static constexpr float Min = (float)-FLT_MAX; + static constexpr float Max = (float)FLT_MAX; + }; + + template<> + struct TypedValueSerializerMinMax + { + static constexpr double Min = (double)-DBL_MAX; + static constexpr double Max = (double)DBL_MAX; + }; + +/*********************************************************************** Signed Types ***********************************************************************/ - template + template struct TypedValueSerializerProvider_Signed { static T GetDefaultValue() @@ -2860,6 +2940,8 @@ Signed Types static bool Deserialize(const WString& input, T& output) { + constexpr T MinValue = TypedValueSerializerMinMax::Min; + constexpr T MaxValue = TypedValueSerializerMinMax::Max; bool success = false; vint64_t result = wtoi64_test(input, success); if (!success) return false; @@ -2873,7 +2955,7 @@ Signed Types Unsigned Types ***********************************************************************/ - template + template struct TypedValueSerializerProvider_Unsigned { static T GetDefaultValue() @@ -2889,6 +2971,7 @@ Unsigned Types static bool Deserialize(const WString& input, T& output) { + constexpr T MaxValue = TypedValueSerializerMinMax::Max; bool success = false; vuint64_t result = wtou64_test(input, success); if (!success) return false; @@ -2902,7 +2985,7 @@ Unsigned Types Floating Point Types ***********************************************************************/ - template + template struct TypedValueSerializerProvider_FloatingPoint { static T GetDefaultValue() @@ -2919,10 +3002,12 @@ Floating Point Types static bool Deserialize(const WString& input, T& output) { + constexpr T MinValue = TypedValueSerializerMinMax::Min; + constexpr T MaxValue = TypedValueSerializerMinMax::Max; bool success = false; double result = wtof_test(input, success); if (!success) return false; - if (result < -MaxValue || result > MaxValue) return false; + if (result < MinValue || result > MaxValue) return false; output = (T)result; return true; } @@ -2932,29 +3017,29 @@ Floating Point Types Serializable Types ***********************************************************************/ -#define DEFINE_SIGNED_TVSP(TYPENAME, MINVALUE, MAXVALUE)\ - template<> struct TypedValueSerializerProvider : TypedValueSerializerProvider_Signed {};\ +#define DEFINE_SIGNED_TVSP(TYPENAME)\ + template<> struct TypedValueSerializerProvider : TypedValueSerializerProvider_Signed {};\ - DEFINE_SIGNED_TVSP(vint8_t, _I8_MIN, _I8_MAX) - DEFINE_SIGNED_TVSP(vint16_t, _I16_MIN, _I16_MAX) - DEFINE_SIGNED_TVSP(vint32_t, _I32_MIN, _I32_MAX) - DEFINE_SIGNED_TVSP(vint64_t, _I64_MIN, _I64_MAX) + DEFINE_SIGNED_TVSP(vint8_t) + DEFINE_SIGNED_TVSP(vint16_t) + DEFINE_SIGNED_TVSP(vint32_t) + DEFINE_SIGNED_TVSP(vint64_t) #undef DEFINE_SIGNED_TVSP -#define DEFINE_UNSIGNED_TVSP(TYPENAME, MAXVALUE)\ - template<> struct TypedValueSerializerProvider : TypedValueSerializerProvider_Unsigned {};\ +#define DEFINE_UNSIGNED_TVSP(TYPENAME)\ + template<> struct TypedValueSerializerProvider : TypedValueSerializerProvider_Unsigned {};\ - DEFINE_UNSIGNED_TVSP(vuint8_t, _UI8_MAX) - DEFINE_UNSIGNED_TVSP(vuint16_t, _UI16_MAX) - DEFINE_UNSIGNED_TVSP(vuint32_t, _UI32_MAX) - DEFINE_UNSIGNED_TVSP(vuint64_t, _UI64_MAX) + DEFINE_UNSIGNED_TVSP(vuint8_t) + DEFINE_UNSIGNED_TVSP(vuint16_t) + DEFINE_UNSIGNED_TVSP(vuint32_t) + DEFINE_UNSIGNED_TVSP(vuint64_t) #undef DEFINE_UNSIGNED_TVSP -#define DEFINE_FLOAT_TVSP(TYPENAME, MAXVALUE)\ - template<> struct TypedValueSerializerProvider : TypedValueSerializerProvider_FloatingPoint {};\ +#define DEFINE_FLOAT_TVSP(TYPENAME)\ + template<> struct TypedValueSerializerProvider : TypedValueSerializerProvider_FloatingPoint {};\ - DEFINE_FLOAT_TVSP(float, (float)FLT_MAX) - DEFINE_FLOAT_TVSP(double, (double)DBL_MAX) + DEFINE_FLOAT_TVSP(float) + DEFINE_FLOAT_TVSP(double) #undef DEFINE_FLOAT_TVSP #define DEFINE_TVSP(TYPENAME)\ diff --git a/Tools/Reflection32.bin b/Tools/Reflection32.bin index 9235065b..1032d10c 100644 Binary files a/Tools/Reflection32.bin and b/Tools/Reflection32.bin differ diff --git a/Tools/Reflection64.bin b/Tools/Reflection64.bin index 7958b61f..4f40d9bc 100644 Binary files a/Tools/Reflection64.bin and b/Tools/Reflection64.bin differ diff --git a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 index 8889cd89..fe03c3e4 100644 Binary files a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 and b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 differ diff --git a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 index 7b8213da..a7f87536 100644 Binary files a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 and b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 differ