|
| 1 | +#include <signal.h> |
| 2 | +#include <chrono> |
| 3 | +#include <iostream> |
| 4 | +#include <memory> |
| 5 | +#include <thread> |
| 6 | + |
| 7 | +#include "nativeapi.h" |
| 8 | + |
| 9 | +using namespace nativeapi; |
| 10 | + |
| 11 | +// Global flag for graceful shutdown |
| 12 | +static bool g_running = true; |
| 13 | + |
| 14 | +// Signal handler for graceful shutdown |
| 15 | +void signal_handler(int sig) { |
| 16 | + std::cout << "\nReceived signal " << sig << ", shutting down...\n"; |
| 17 | + g_running = false; |
| 18 | +} |
| 19 | + |
| 20 | +int main() { |
| 21 | + std::cout << "ShortcutManager Example\n"; |
| 22 | + std::cout << "=======================\n\n"; |
| 23 | + |
| 24 | + // Set up signal handlers |
| 25 | + signal(SIGINT, signal_handler); |
| 26 | + signal(SIGTERM, signal_handler); |
| 27 | + |
| 28 | + // Get the ShortcutManager singleton instance |
| 29 | + auto& manager = ShortcutManager::GetInstance(); |
| 30 | + |
| 31 | + // Check if global shortcuts are supported |
| 32 | + if (!manager.IsSupported()) { |
| 33 | + std::cout << "⚠️ Global shortcuts are not supported on this platform or configuration.\n"; |
| 34 | + std::cout << "This may be due to:\n"; |
| 35 | + std::cout << " - Missing accessibility permissions (macOS)\n"; |
| 36 | + std::cout << " - No display server available (Linux)\n"; |
| 37 | + std::cout << " - Platform limitations\n\n"; |
| 38 | + std::cout << "The example will continue, but shortcuts won't be triggered.\n\n"; |
| 39 | + } else { |
| 40 | + std::cout << "✓ Global shortcuts are supported\n\n"; |
| 41 | + } |
| 42 | + |
| 43 | + // Add event listener for shortcut activations |
| 44 | + auto activation_listener = manager.AddListener<ShortcutActivatedEvent>( |
| 45 | + [](const ShortcutActivatedEvent& event) { |
| 46 | + std::cout << "🔔 Shortcut activated: " << event.GetAccelerator() |
| 47 | + << " (ID: " << event.GetShortcutId() << ")\n"; |
| 48 | + }); |
| 49 | + |
| 50 | + // Add event listener for registration events |
| 51 | + auto registration_listener = manager.AddListener<ShortcutRegisteredEvent>( |
| 52 | + [](const ShortcutRegisteredEvent& event) { |
| 53 | + std::cout << "✓ Shortcut registered: " << event.GetAccelerator() |
| 54 | + << " (ID: " << event.GetShortcutId() << ")\n"; |
| 55 | + }); |
| 56 | + |
| 57 | + // Add event listener for unregistration events |
| 58 | + auto unregistration_listener = manager.AddListener<ShortcutUnregisteredEvent>( |
| 59 | + [](const ShortcutUnregisteredEvent& event) { |
| 60 | + std::cout << "✗ Shortcut unregistered: " << event.GetAccelerator() |
| 61 | + << " (ID: " << event.GetShortcutId() << ")\n"; |
| 62 | + }); |
| 63 | + |
| 64 | + // Add event listener for registration failures |
| 65 | + auto failure_listener = manager.AddListener<ShortcutRegistrationFailedEvent>( |
| 66 | + [](const ShortcutRegistrationFailedEvent& event) { |
| 67 | + std::cout << "❌ Failed to register shortcut: " << event.GetAccelerator() |
| 68 | + << " - " << event.GetErrorMessage() << "\n"; |
| 69 | + }); |
| 70 | + |
| 71 | + std::cout << "Event listeners registered\n\n"; |
| 72 | + |
| 73 | + // Register shortcuts with simple callback |
| 74 | + std::cout << "Registering shortcuts...\n"; |
| 75 | + |
| 76 | + auto shortcut1 = manager.Register("Ctrl+Shift+A", []() { |
| 77 | + std::cout << " → Action A triggered!\n"; |
| 78 | + }); |
| 79 | + |
| 80 | + auto shortcut2 = manager.Register("Ctrl+Shift+B", []() { |
| 81 | + std::cout << " → Action B triggered!\n"; |
| 82 | + }); |
| 83 | + |
| 84 | + auto shortcut3 = manager.Register("Ctrl+Shift+C", []() { |
| 85 | + std::cout << " → Action C triggered!\n"; |
| 86 | + }); |
| 87 | + |
| 88 | + // Register shortcut with detailed options |
| 89 | + ShortcutOptions options; |
| 90 | + options.accelerator = "Ctrl+Shift+Q"; |
| 91 | + options.description = "Quick quit action"; |
| 92 | + options.scope = ShortcutScope::Global; |
| 93 | + options.callback = []() { |
| 94 | + std::cout << " → Quick quit triggered! (This would normally quit the app)\n"; |
| 95 | + }; |
| 96 | + |
| 97 | + auto shortcut4 = manager.Register(options); |
| 98 | + |
| 99 | + std::cout << "\n"; |
| 100 | + |
| 101 | + // Display registered shortcuts |
| 102 | + auto all_shortcuts = manager.GetAll(); |
| 103 | + std::cout << "Currently registered shortcuts (" << all_shortcuts.size() << "):\n"; |
| 104 | + for (const auto& shortcut : all_shortcuts) { |
| 105 | + std::cout << " • " << shortcut->GetAccelerator(); |
| 106 | + if (!shortcut->GetDescription().empty()) { |
| 107 | + std::cout << " - " << shortcut->GetDescription(); |
| 108 | + } |
| 109 | + std::cout << " (ID: " << shortcut->GetId() << ", Scope: " |
| 110 | + << (shortcut->GetScope() == ShortcutScope::Global ? "Global" : "Application") |
| 111 | + << ", Enabled: " << (shortcut->IsEnabled() ? "Yes" : "No") << ")\n"; |
| 112 | + } |
| 113 | + std::cout << "\n"; |
| 114 | + |
| 115 | + // Demonstrate validation |
| 116 | + std::cout << "Testing accelerator validation:\n"; |
| 117 | + std::vector<std::string> test_accelerators = { |
| 118 | + "Ctrl+A", // Valid |
| 119 | + "Ctrl+Shift+F1", // Valid |
| 120 | + "Invalid", // Invalid |
| 121 | + "Ctrl++", // Invalid |
| 122 | + "Alt+Space", // Valid |
| 123 | + }; |
| 124 | + |
| 125 | + for (const auto& acc : test_accelerators) { |
| 126 | + bool valid = manager.IsValidAccelerator(acc); |
| 127 | + bool available = manager.IsAvailable(acc); |
| 128 | + std::cout << " • \"" << acc << "\" - Valid: " << (valid ? "Yes" : "No") |
| 129 | + << ", Available: " << (available ? "Yes" : "No") << "\n"; |
| 130 | + } |
| 131 | + std::cout << "\n"; |
| 132 | + |
| 133 | + // Demonstrate enable/disable |
| 134 | + std::cout << "Demonstrating enable/disable:\n"; |
| 135 | + if (shortcut1) { |
| 136 | + std::cout << " • Disabling shortcut: " << shortcut1->GetAccelerator() << "\n"; |
| 137 | + shortcut1->SetEnabled(false); |
| 138 | + std::cout << " Shortcut is now disabled. Pressing it won't trigger the callback.\n"; |
| 139 | + |
| 140 | + std::this_thread::sleep_for(std::chrono::seconds(2)); |
| 141 | + |
| 142 | + std::cout << " • Re-enabling shortcut: " << shortcut1->GetAccelerator() << "\n"; |
| 143 | + shortcut1->SetEnabled(true); |
| 144 | + std::cout << " Shortcut is now enabled again.\n"; |
| 145 | + } |
| 146 | + std::cout << "\n"; |
| 147 | + |
| 148 | + // Demonstrate programmatic invocation |
| 149 | + std::cout << "Demonstrating programmatic invocation:\n"; |
| 150 | + if (shortcut2) { |
| 151 | + std::cout << " • Manually invoking shortcut: " << shortcut2->GetAccelerator() << "\n"; |
| 152 | + shortcut2->Invoke(); |
| 153 | + } |
| 154 | + std::cout << "\n"; |
| 155 | + |
| 156 | + // Demonstrate getting shortcuts by scope |
| 157 | + std::cout << "Shortcuts by scope:\n"; |
| 158 | + auto global_shortcuts = manager.GetByScope(ShortcutScope::Global); |
| 159 | + auto app_shortcuts = manager.GetByScope(ShortcutScope::Application); |
| 160 | + std::cout << " • Global shortcuts: " << global_shortcuts.size() << "\n"; |
| 161 | + std::cout << " • Application shortcuts: " << app_shortcuts.size() << "\n"; |
| 162 | + std::cout << "\n"; |
| 163 | + |
| 164 | + // Main loop |
| 165 | + std::cout << "📋 Available shortcuts:\n"; |
| 166 | + std::cout << " • Ctrl+Shift+A - Trigger Action A\n"; |
| 167 | + std::cout << " • Ctrl+Shift+B - Trigger Action B\n"; |
| 168 | + std::cout << " • Ctrl+Shift+C - Trigger Action C\n"; |
| 169 | + std::cout << " • Ctrl+Shift+Q - Quick quit action\n"; |
| 170 | + std::cout << "\n"; |
| 171 | + std::cout << "Press the shortcuts above to see them in action.\n"; |
| 172 | + std::cout << "Press Ctrl+C to exit.\n\n"; |
| 173 | + |
| 174 | + // Keep the main thread alive to receive shortcut events |
| 175 | + int seconds = 0; |
| 176 | + while (g_running) { |
| 177 | + std::this_thread::sleep_for(std::chrono::seconds(1)); |
| 178 | + seconds++; |
| 179 | + |
| 180 | + // After 10 seconds, demonstrate unregistering a shortcut |
| 181 | + if (seconds == 10 && shortcut3) { |
| 182 | + std::cout << "\n⏰ 10 seconds elapsed. Unregistering shortcut: " |
| 183 | + << shortcut3->GetAccelerator() << "\n\n"; |
| 184 | + manager.Unregister(shortcut3->GetId()); |
| 185 | + } |
| 186 | + |
| 187 | + // After 20 seconds, demonstrate disabling all shortcuts |
| 188 | + if (seconds == 20) { |
| 189 | + std::cout << "\n⏰ 20 seconds elapsed. Disabling all shortcut processing.\n"; |
| 190 | + std::cout << "Shortcuts will remain registered but won't trigger.\n\n"; |
| 191 | + manager.SetEnabled(false); |
| 192 | + } |
| 193 | + |
| 194 | + // After 25 seconds, re-enable |
| 195 | + if (seconds == 25) { |
| 196 | + std::cout << "\n⏰ 25 seconds elapsed. Re-enabling shortcut processing.\n\n"; |
| 197 | + manager.SetEnabled(true); |
| 198 | + } |
| 199 | + } |
| 200 | + |
| 201 | + // Cleanup |
| 202 | + std::cout << "\nCleaning up...\n"; |
| 203 | + |
| 204 | + // Remove event listeners |
| 205 | + manager.RemoveListener(activation_listener); |
| 206 | + manager.RemoveListener(registration_listener); |
| 207 | + manager.RemoveListener(unregistration_listener); |
| 208 | + manager.RemoveListener(failure_listener); |
| 209 | + |
| 210 | + // Unregister all shortcuts |
| 211 | + int count = manager.UnregisterAll(); |
| 212 | + std::cout << "Unregistered " << count << " shortcuts\n"; |
| 213 | + |
| 214 | + std::cout << "\nExample completed successfully!\n"; |
| 215 | + std::cout << "\nThis example demonstrated:\n"; |
| 216 | + std::cout << " • ShortcutManager::GetInstance() - Get singleton instance\n"; |
| 217 | + std::cout << " • ShortcutManager::IsSupported() - Check platform support\n"; |
| 218 | + std::cout << " • ShortcutManager::Register() - Register shortcuts\n"; |
| 219 | + std::cout << " • ShortcutManager::Unregister() - Unregister shortcuts\n"; |
| 220 | + std::cout << " • ShortcutManager::GetAll() - Get all shortcuts\n"; |
| 221 | + std::cout << " • ShortcutManager::GetByScope() - Filter by scope\n"; |
| 222 | + std::cout << " • ShortcutManager::IsValidAccelerator() - Validate format\n"; |
| 223 | + std::cout << " • ShortcutManager::IsAvailable() - Check availability\n"; |
| 224 | + std::cout << " • ShortcutManager::SetEnabled() - Enable/disable processing\n"; |
| 225 | + std::cout << " • Shortcut::SetEnabled() - Enable/disable individual shortcuts\n"; |
| 226 | + std::cout << " • Shortcut::Invoke() - Programmatic invocation\n"; |
| 227 | + std::cout << " • Event listeners for activation, registration, and errors\n"; |
| 228 | + |
| 229 | + return 0; |
| 230 | +} |
| 231 | + |
0 commit comments