windowpp 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/bin/windowpp.js +86 -0
  2. package/cmake/embed_assets.py +144 -0
  3. package/framework/CMakeLists.txt +176 -0
  4. package/framework/include/windowpp/windowpp.h +704 -0
  5. package/framework/src/AppData/API/AppData.ts +137 -0
  6. package/framework/src/AppData/appdata_bridge.h +138 -0
  7. package/framework/src/AppData/appdata_manager.cpp +126 -0
  8. package/framework/src/AppData/appdata_manager.h +3 -0
  9. package/framework/src/FileSystem/API/FileSystem.ts +389 -0
  10. package/framework/src/FileSystem/Linux/filesearch.cpp +148 -0
  11. package/framework/src/FileSystem/Linux/readfile.cpp +79 -0
  12. package/framework/src/FileSystem/Linux/savefile.cpp +333 -0
  13. package/framework/src/FileSystem/MacOS/filesearch.cpp +149 -0
  14. package/framework/src/FileSystem/MacOS/readfile.cpp +80 -0
  15. package/framework/src/FileSystem/MacOS/savefile.cpp +264 -0
  16. package/framework/src/FileSystem/Windows/filesearch.cpp +195 -0
  17. package/framework/src/FileSystem/Windows/readfile.cpp +122 -0
  18. package/framework/src/FileSystem/Windows/savefile.cpp +290 -0
  19. package/framework/src/FileSystem/file_index_service.cpp +262 -0
  20. package/framework/src/FileSystem/file_index_service.h +55 -0
  21. package/framework/src/FileSystem/filesystem_bridge.h +243 -0
  22. package/framework/src/FileSystem/filesystem_handler.h +93 -0
  23. package/framework/src/FileSystem/filesystem_json.h +241 -0
  24. package/framework/src/FileSystem/filesystem_search_service.cpp +414 -0
  25. package/framework/src/FileSystem/filesystem_search_service.h +94 -0
  26. package/framework/src/Input/API/Input.ts +161 -0
  27. package/framework/src/Input/Linux/linux_key_utils.h +135 -0
  28. package/framework/src/Input/MacOS/macos_key_utils.h +137 -0
  29. package/framework/src/Input/Windows/win32_key_utils.h +199 -0
  30. package/framework/src/Input/input_bridge.h +192 -0
  31. package/framework/src/Input/input_service.cpp +584 -0
  32. package/framework/src/Input/input_service.h +21 -0
  33. package/framework/src/application.cpp +29 -0
  34. package/framework/src/common/hit_test.cpp +40 -0
  35. package/framework/src/common/image_loader.cpp +24 -0
  36. package/framework/src/common/paths.cpp +75 -0
  37. package/framework/src/filedrop/filedrop.cpp +316 -0
  38. package/framework/src/filedrop/filedrop.css +421 -0
  39. package/framework/src/filedrop/filedrop.hpp +92 -0
  40. package/framework/src/filedrop/filedrop.ts +183 -0
  41. package/framework/src/platform/API/App.ts +156 -0
  42. package/framework/src/platform/API/Window.ts +249 -0
  43. package/framework/src/platform/linux/app_linux.cpp +256 -0
  44. package/framework/src/platform/linux/app_linux.h +64 -0
  45. package/framework/src/platform/linux/linux_helpers.cpp +26 -0
  46. package/framework/src/platform/linux/linux_helpers.h +19 -0
  47. package/framework/src/platform/linux/tray_linux.cpp +21 -0
  48. package/framework/src/platform/linux/tray_linux.h +26 -0
  49. package/framework/src/platform/linux/window_linux.cpp +256 -0
  50. package/framework/src/platform/linux/window_linux.h +70 -0
  51. package/framework/src/platform/macos/app_macos.h +59 -0
  52. package/framework/src/platform/macos/app_macos.mm +223 -0
  53. package/framework/src/platform/macos/macos_helpers.h +21 -0
  54. package/framework/src/platform/macos/tray_macos.h +22 -0
  55. package/framework/src/platform/macos/tray_macos.mm +53 -0
  56. package/framework/src/platform/macos/window_macos.h +74 -0
  57. package/framework/src/platform/macos/window_macos.mm +318 -0
  58. package/framework/src/platform/platform_bridge.h +514 -0
  59. package/framework/src/platform/platform_factory.cpp +33 -0
  60. package/framework/src/platform/platform_factory.h +19 -0
  61. package/framework/src/platform/win32/app_win32.cpp +572 -0
  62. package/framework/src/platform/win32/app_win32.h +83 -0
  63. package/framework/src/platform/win32/tray_win32.cpp +57 -0
  64. package/framework/src/platform/win32/tray_win32.h +30 -0
  65. package/framework/src/platform/win32/win32_helpers.h +61 -0
  66. package/framework/src/platform/win32/window_win32.cpp +267 -0
  67. package/framework/src/platform/win32/window_win32.h +79 -0
  68. package/framework/src/renderer/webgpu.h +128 -0
  69. package/framework/src/renderer/webview/include/WebView2.h +48014 -0
  70. package/framework/src/renderer/webview/include/WebView2EnvironmentOptions.h +342 -0
  71. package/framework/src/renderer/webview/webview.h +13 -0
  72. package/framework/src/renderer/webview/webview_linux.cpp +392 -0
  73. package/framework/src/renderer/webview/webview_macos.mm +388 -0
  74. package/framework/src/renderer/webview/webview_win32.cpp +688 -0
  75. package/framework/src/renderer/webview/x64/WebView2Loader.dll +0 -0
  76. package/framework/src/renderer/webview/x64/WebView2Loader.lib +0 -0
  77. package/framework/src/renderer/webview/x64/WebView2LoaderStatic.lib +0 -0
  78. package/lib/build.js +112 -0
  79. package/lib/create.js +283 -0
  80. package/lib/dev.js +155 -0
  81. package/package.json +24 -0
  82. package/scripts/publish.js +67 -0
  83. package/scripts/sync-framework.js +73 -0
  84. package/templates/solid/CMakeLists.txt +56 -0
  85. package/templates/solid/frontend/package.json +22 -0
  86. package/templates/solid/frontend/vite.config.ts +25 -0
  87. package/templates/solid/main.cpp +72 -0
  88. package/templates/solid/package.json +12 -0
@@ -0,0 +1,135 @@
1
+ #pragma once
2
+
3
+ #if defined(__linux__)
4
+
5
+ #include <X11/keysym.h>
6
+ #include <xcb/xcb.h>
7
+ #include <xcb/xcb_keysyms.h>
8
+
9
+ #include <string>
10
+
11
+ #include <windowpp/windowpp.h>
12
+
13
+ namespace wpp::input::linux {
14
+
15
+ inline Key key_from_keysym(xcb_keysym_t keysym) {
16
+ switch (keysym) {
17
+ case XK_a: case XK_A: return Key::A;
18
+ case XK_b: case XK_B: return Key::B;
19
+ case XK_c: case XK_C: return Key::C;
20
+ case XK_d: case XK_D: return Key::D;
21
+ case XK_e: case XK_E: return Key::E;
22
+ case XK_f: case XK_F: return Key::F;
23
+ case XK_g: case XK_G: return Key::G;
24
+ case XK_h: case XK_H: return Key::H;
25
+ case XK_i: case XK_I: return Key::I;
26
+ case XK_j: case XK_J: return Key::J;
27
+ case XK_k: case XK_K: return Key::K;
28
+ case XK_l: case XK_L: return Key::L;
29
+ case XK_m: case XK_M: return Key::M;
30
+ case XK_n: case XK_N: return Key::N;
31
+ case XK_o: case XK_O: return Key::O;
32
+ case XK_p: case XK_P: return Key::P;
33
+ case XK_q: case XK_Q: return Key::Q;
34
+ case XK_r: case XK_R: return Key::R;
35
+ case XK_s: case XK_S: return Key::S;
36
+ case XK_t: case XK_T: return Key::T;
37
+ case XK_u: case XK_U: return Key::U;
38
+ case XK_v: case XK_V: return Key::V;
39
+ case XK_w: case XK_W: return Key::W;
40
+ case XK_x: case XK_X: return Key::X;
41
+ case XK_y: case XK_Y: return Key::Y;
42
+ case XK_z: case XK_Z: return Key::Z;
43
+ case XK_0: return Key::Digit0;
44
+ case XK_1: return Key::Digit1;
45
+ case XK_2: return Key::Digit2;
46
+ case XK_3: return Key::Digit3;
47
+ case XK_4: return Key::Digit4;
48
+ case XK_5: return Key::Digit5;
49
+ case XK_6: return Key::Digit6;
50
+ case XK_7: return Key::Digit7;
51
+ case XK_8: return Key::Digit8;
52
+ case XK_9: return Key::Digit9;
53
+ case XK_space: return Key::Space;
54
+ case XK_Return: return Key::Enter;
55
+ case XK_Escape: return Key::Escape;
56
+ case XK_Tab: return Key::Tab;
57
+ case XK_BackSpace: return Key::Backspace;
58
+ case XK_Delete: return Key::Delete;
59
+ case XK_Insert: return Key::Insert;
60
+ case XK_Home: return Key::Home;
61
+ case XK_End: return Key::End;
62
+ case XK_Page_Up: return Key::PageUp;
63
+ case XK_Page_Down: return Key::PageDown;
64
+ case XK_Left: return Key::Left;
65
+ case XK_Right: return Key::Right;
66
+ case XK_Up: return Key::Up;
67
+ case XK_Down: return Key::Down;
68
+ case XK_Caps_Lock: return Key::CapsLock;
69
+ case XK_Shift_L: case XK_Shift_R: return Key::Shift;
70
+ case XK_Control_L: case XK_Control_R: return Key::Control;
71
+ case XK_Alt_L: case XK_Alt_R: case XK_Meta_L: case XK_Meta_R: return Key::Alt;
72
+ case XK_Super_L: case XK_Super_R: case XK_Hyper_L: case XK_Hyper_R: return Key::Meta;
73
+ case XK_F1: return Key::F1;
74
+ case XK_F2: return Key::F2;
75
+ case XK_F3: return Key::F3;
76
+ case XK_F4: return Key::F4;
77
+ case XK_F5: return Key::F5;
78
+ case XK_F6: return Key::F6;
79
+ case XK_F7: return Key::F7;
80
+ case XK_F8: return Key::F8;
81
+ case XK_F9: return Key::F9;
82
+ case XK_F10: return Key::F10;
83
+ case XK_F11: return Key::F11;
84
+ case XK_F12: return Key::F12;
85
+ default: return Key::Unknown;
86
+ }
87
+ }
88
+
89
+ inline xcb_keysym_t keysym_from_event(xcb_connection_t* connection, uint8_t detail, uint16_t state) {
90
+ xcb_key_symbols_t* symbols = xcb_key_symbols_alloc(connection);
91
+ if (!symbols) {
92
+ return 0;
93
+ }
94
+ const int column = (state & XCB_MOD_MASK_SHIFT) ? 1 : 0;
95
+ const xcb_keysym_t keysym = xcb_key_symbols_get_keysym(symbols, detail, column);
96
+ xcb_key_symbols_free(symbols);
97
+ return keysym;
98
+ }
99
+
100
+ inline std::string key_name_from_keysym(xcb_keysym_t keysym) {
101
+ const auto key = key_from_keysym(keysym);
102
+ if (key != Key::Unknown) {
103
+ return key_to_string(key);
104
+ }
105
+ if (keysym >= 32 && keysym <= 126) {
106
+ return std::string(1, static_cast<char>(keysym));
107
+ }
108
+ return "Unknown";
109
+ }
110
+
111
+ inline KeyEvent make_key_event(xcb_connection_t* connection,
112
+ const xcb_key_press_event_t* native_event,
113
+ KeyEventType type,
114
+ const std::string& window_id) {
115
+ const auto keysym = keysym_from_event(connection, native_event->detail, native_event->state);
116
+
117
+ KeyEvent event{};
118
+ event.key = key_from_keysym(keysym);
119
+ event.type = type;
120
+ event.keycode = native_event->detail;
121
+ event.scancode = native_event->detail;
122
+ event.key_name = key_name_from_keysym(keysym);
123
+ event.ctrl = (native_event->state & XCB_MOD_MASK_CONTROL) != 0;
124
+ event.shift = (native_event->state & XCB_MOD_MASK_SHIFT) != 0;
125
+ event.alt = (native_event->state & XCB_MOD_MASK_1) != 0;
126
+ event.meta = (native_event->state & XCB_MOD_MASK_4) != 0;
127
+ event.is_repeat = false;
128
+ event.is_global = false;
129
+ event.window_id = window_id;
130
+ return event;
131
+ }
132
+
133
+ } // namespace wpp::input::linux
134
+
135
+ #endif
@@ -0,0 +1,137 @@
1
+ #pragma once
2
+
3
+ #import <Cocoa/Cocoa.h>
4
+
5
+ #include <string>
6
+
7
+ #include <windowpp/windowpp.h>
8
+
9
+ namespace wpp::input::macos {
10
+
11
+ inline Key key_from_keycode(unsigned short keycode) {
12
+ switch (keycode) {
13
+ case 0: return Key::A;
14
+ case 11: return Key::B;
15
+ case 8: return Key::C;
16
+ case 2: return Key::D;
17
+ case 14: return Key::E;
18
+ case 3: return Key::F;
19
+ case 5: return Key::G;
20
+ case 4: return Key::H;
21
+ case 34: return Key::I;
22
+ case 38: return Key::J;
23
+ case 40: return Key::K;
24
+ case 37: return Key::L;
25
+ case 46: return Key::M;
26
+ case 45: return Key::N;
27
+ case 31: return Key::O;
28
+ case 35: return Key::P;
29
+ case 12: return Key::Q;
30
+ case 15: return Key::R;
31
+ case 1: return Key::S;
32
+ case 17: return Key::T;
33
+ case 32: return Key::U;
34
+ case 9: return Key::V;
35
+ case 13: return Key::W;
36
+ case 7: return Key::X;
37
+ case 16: return Key::Y;
38
+ case 6: return Key::Z;
39
+ case 29: return Key::Digit0;
40
+ case 18: return Key::Digit1;
41
+ case 19: return Key::Digit2;
42
+ case 20: return Key::Digit3;
43
+ case 21: return Key::Digit4;
44
+ case 23: return Key::Digit5;
45
+ case 22: return Key::Digit6;
46
+ case 26: return Key::Digit7;
47
+ case 28: return Key::Digit8;
48
+ case 25: return Key::Digit9;
49
+ case 49: return Key::Space;
50
+ case 36: return Key::Enter;
51
+ case 53: return Key::Escape;
52
+ case 48: return Key::Tab;
53
+ case 51: return Key::Backspace;
54
+ case 117: return Key::Delete;
55
+ case 114: return Key::Insert;
56
+ case 115: return Key::Home;
57
+ case 119: return Key::End;
58
+ case 116: return Key::PageUp;
59
+ case 121: return Key::PageDown;
60
+ case 123: return Key::Left;
61
+ case 124: return Key::Right;
62
+ case 126: return Key::Up;
63
+ case 125: return Key::Down;
64
+ case 57: return Key::CapsLock;
65
+ case 56: case 60: return Key::Shift;
66
+ case 59: case 62: return Key::Control;
67
+ case 58: case 61: return Key::Alt;
68
+ case 55: case 54: return Key::Meta;
69
+ case 122: return Key::F1;
70
+ case 120: return Key::F2;
71
+ case 99: return Key::F3;
72
+ case 118: return Key::F4;
73
+ case 96: return Key::F5;
74
+ case 97: return Key::F6;
75
+ case 98: return Key::F7;
76
+ case 100: return Key::F8;
77
+ case 101: return Key::F9;
78
+ case 109: return Key::F10;
79
+ case 103: return Key::F11;
80
+ case 111: return Key::F12;
81
+ default: return Key::Unknown;
82
+ }
83
+ }
84
+
85
+ inline std::string key_name_from_event(NSEvent* event, Key key) {
86
+ if (key != Key::Unknown) {
87
+ return key_to_string(key);
88
+ }
89
+
90
+ NSString* characters = [event charactersIgnoringModifiers];
91
+ if (characters && characters.length > 0) {
92
+ return std::string([[characters uppercaseString] UTF8String]);
93
+ }
94
+ return "Unknown";
95
+ }
96
+
97
+ inline bool modifier_active(NSEventModifierFlags flags, Key key) {
98
+ switch (key) {
99
+ case Key::Shift: return (flags & NSEventModifierFlagShift) != 0;
100
+ case Key::Control: return (flags & NSEventModifierFlagControl) != 0;
101
+ case Key::Alt: return (flags & NSEventModifierFlagOption) != 0;
102
+ case Key::Meta: return (flags & NSEventModifierFlagCommand) != 0;
103
+ default: return false;
104
+ }
105
+ }
106
+
107
+ inline KeyEvent make_key_event(NSEvent* native_event,
108
+ const std::string& window_id,
109
+ KeyEventType type) {
110
+ const auto key = key_from_keycode(native_event.keyCode);
111
+ const auto flags = native_event.modifierFlags;
112
+
113
+ KeyEvent event{};
114
+ event.key = key;
115
+ event.type = type;
116
+ event.keycode = native_event.keyCode;
117
+ event.scancode = native_event.keyCode;
118
+ event.key_name = key_name_from_event(native_event, key);
119
+ event.ctrl = (flags & NSEventModifierFlagControl) != 0;
120
+ event.shift = (flags & NSEventModifierFlagShift) != 0;
121
+ event.alt = (flags & NSEventModifierFlagOption) != 0;
122
+ event.meta = (flags & NSEventModifierFlagCommand) != 0;
123
+ event.is_repeat = native_event.isARepeat;
124
+ event.is_global = false;
125
+ event.window_id = window_id;
126
+ return event;
127
+ }
128
+
129
+ inline KeyEvent make_flags_changed_event(NSEvent* native_event,
130
+ const std::string& window_id) {
131
+ const auto key = key_from_keycode(native_event.keyCode);
132
+ const auto flags = native_event.modifierFlags;
133
+ const auto type = modifier_active(flags, key) ? KeyEventType::KeyDown : KeyEventType::KeyUp;
134
+ return make_key_event(native_event, window_id, type);
135
+ }
136
+
137
+ } // namespace wpp::input::macos
@@ -0,0 +1,199 @@
1
+ #pragma once
2
+
3
+ #include <windows.h>
4
+
5
+ #include <string>
6
+
7
+ #include <windowpp/windowpp.h>
8
+
9
+ namespace wpp::input::win32 {
10
+
11
+ inline Key key_from_virtual_key(UINT vk) {
12
+ if (vk >= 'A' && vk <= 'Z') {
13
+ return static_cast<Key>(static_cast<int>(Key::A) + static_cast<int>(vk - 'A'));
14
+ }
15
+ if (vk >= '0' && vk <= '9') {
16
+ return static_cast<Key>(static_cast<int>(Key::Digit0) + static_cast<int>(vk - '0'));
17
+ }
18
+
19
+ switch (vk) {
20
+ case VK_SPACE: return Key::Space;
21
+ case VK_RETURN: return Key::Enter;
22
+ case VK_ESCAPE: return Key::Escape;
23
+ case VK_TAB: return Key::Tab;
24
+ case VK_BACK: return Key::Backspace;
25
+ case VK_DELETE: return Key::Delete;
26
+ case VK_INSERT: return Key::Insert;
27
+ case VK_HOME: return Key::Home;
28
+ case VK_END: return Key::End;
29
+ case VK_PRIOR: return Key::PageUp;
30
+ case VK_NEXT: return Key::PageDown;
31
+ case VK_LEFT: return Key::Left;
32
+ case VK_RIGHT: return Key::Right;
33
+ case VK_UP: return Key::Up;
34
+ case VK_DOWN: return Key::Down;
35
+ case VK_CAPITAL: return Key::CapsLock;
36
+ case VK_SHIFT:
37
+ case VK_LSHIFT:
38
+ case VK_RSHIFT:
39
+ return Key::Shift;
40
+ case VK_CONTROL:
41
+ case VK_LCONTROL:
42
+ case VK_RCONTROL:
43
+ return Key::Control;
44
+ case VK_MENU:
45
+ case VK_LMENU:
46
+ case VK_RMENU:
47
+ return Key::Alt;
48
+ case VK_LWIN:
49
+ case VK_RWIN:
50
+ return Key::Meta;
51
+ case VK_F1: return Key::F1;
52
+ case VK_F2: return Key::F2;
53
+ case VK_F3: return Key::F3;
54
+ case VK_F4: return Key::F4;
55
+ case VK_F5: return Key::F5;
56
+ case VK_F6: return Key::F6;
57
+ case VK_F7: return Key::F7;
58
+ case VK_F8: return Key::F8;
59
+ case VK_F9: return Key::F9;
60
+ case VK_F10: return Key::F10;
61
+ case VK_F11: return Key::F11;
62
+ case VK_F12: return Key::F12;
63
+ default: return Key::Unknown;
64
+ }
65
+ }
66
+
67
+ inline UINT virtual_key_from_key(Key key) {
68
+ switch (key) {
69
+ case Key::A: return 'A';
70
+ case Key::B: return 'B';
71
+ case Key::C: return 'C';
72
+ case Key::D: return 'D';
73
+ case Key::E: return 'E';
74
+ case Key::F: return 'F';
75
+ case Key::G: return 'G';
76
+ case Key::H: return 'H';
77
+ case Key::I: return 'I';
78
+ case Key::J: return 'J';
79
+ case Key::K: return 'K';
80
+ case Key::L: return 'L';
81
+ case Key::M: return 'M';
82
+ case Key::N: return 'N';
83
+ case Key::O: return 'O';
84
+ case Key::P: return 'P';
85
+ case Key::Q: return 'Q';
86
+ case Key::R: return 'R';
87
+ case Key::S: return 'S';
88
+ case Key::T: return 'T';
89
+ case Key::U: return 'U';
90
+ case Key::V: return 'V';
91
+ case Key::W: return 'W';
92
+ case Key::X: return 'X';
93
+ case Key::Y: return 'Y';
94
+ case Key::Z: return 'Z';
95
+ case Key::Digit0: return '0';
96
+ case Key::Digit1: return '1';
97
+ case Key::Digit2: return '2';
98
+ case Key::Digit3: return '3';
99
+ case Key::Digit4: return '4';
100
+ case Key::Digit5: return '5';
101
+ case Key::Digit6: return '6';
102
+ case Key::Digit7: return '7';
103
+ case Key::Digit8: return '8';
104
+ case Key::Digit9: return '9';
105
+ case Key::Space: return VK_SPACE;
106
+ case Key::Enter: return VK_RETURN;
107
+ case Key::Escape: return VK_ESCAPE;
108
+ case Key::Tab: return VK_TAB;
109
+ case Key::Backspace: return VK_BACK;
110
+ case Key::Delete: return VK_DELETE;
111
+ case Key::Insert: return VK_INSERT;
112
+ case Key::Home: return VK_HOME;
113
+ case Key::End: return VK_END;
114
+ case Key::PageUp: return VK_PRIOR;
115
+ case Key::PageDown: return VK_NEXT;
116
+ case Key::Left: return VK_LEFT;
117
+ case Key::Right: return VK_RIGHT;
118
+ case Key::Up: return VK_UP;
119
+ case Key::Down: return VK_DOWN;
120
+ case Key::CapsLock: return VK_CAPITAL;
121
+ case Key::F1: return VK_F1;
122
+ case Key::F2: return VK_F2;
123
+ case Key::F3: return VK_F3;
124
+ case Key::F4: return VK_F4;
125
+ case Key::F5: return VK_F5;
126
+ case Key::F6: return VK_F6;
127
+ case Key::F7: return VK_F7;
128
+ case Key::F8: return VK_F8;
129
+ case Key::F9: return VK_F9;
130
+ case Key::F10: return VK_F10;
131
+ case Key::F11: return VK_F11;
132
+ case Key::F12: return VK_F12;
133
+ default: return 0;
134
+ }
135
+ }
136
+
137
+ inline std::string key_name_from_message(UINT vk, LPARAM lparam) {
138
+ if (const auto key = key_from_virtual_key(vk); key != Key::Unknown) {
139
+ return key_to_string(key);
140
+ }
141
+
142
+ LONG scan = static_cast<LONG>((lparam >> 16) & 0xFF);
143
+ if ((lparam & 0x01000000) != 0) {
144
+ scan |= 0x100;
145
+ }
146
+ wchar_t buffer[64] = {};
147
+ if (GetKeyNameTextW(scan << 16, buffer, static_cast<int>(std::size(buffer))) > 0) {
148
+ int needed = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, nullptr, 0, nullptr, nullptr);
149
+ if (needed > 1) {
150
+ std::string utf8(static_cast<size_t>(needed - 1), '\0');
151
+ WideCharToMultiByte(CP_UTF8, 0, buffer, -1, utf8.data(), needed, nullptr, nullptr);
152
+ return utf8;
153
+ }
154
+ }
155
+ return "Unknown";
156
+ }
157
+
158
+ inline bool is_vk_down(int vk) {
159
+ return (GetAsyncKeyState(vk) & 0x8000) != 0;
160
+ }
161
+
162
+ inline bool modifier_down_for_event(Key key, KeyEventType type, bool current_state, Key modifier) {
163
+ if (key == modifier) {
164
+ return type == KeyEventType::KeyDown;
165
+ }
166
+ return current_state;
167
+ }
168
+
169
+ inline KeyEvent make_key_event(UINT msg, WPARAM wparam, LPARAM lparam, const std::string& window_id) {
170
+ KeyEvent event{};
171
+ event.key = key_from_virtual_key(static_cast<UINT>(wparam));
172
+ event.type = (msg == WM_KEYUP || msg == WM_SYSKEYUP) ? KeyEventType::KeyUp : KeyEventType::KeyDown;
173
+ event.keycode = static_cast<int>(wparam);
174
+ event.scancode = static_cast<uint32_t>((lparam >> 16) & 0xFF);
175
+ event.key_name = key_name_from_message(static_cast<UINT>(wparam), lparam);
176
+ event.ctrl = modifier_down_for_event(event.key, event.type, is_vk_down(VK_CONTROL), Key::Control);
177
+ event.shift = modifier_down_for_event(event.key, event.type, is_vk_down(VK_SHIFT), Key::Shift);
178
+ event.alt = modifier_down_for_event(event.key, event.type, is_vk_down(VK_MENU), Key::Alt);
179
+ event.meta = modifier_down_for_event(event.key, event.type, is_vk_down(VK_LWIN) || is_vk_down(VK_RWIN), Key::Meta);
180
+ event.is_repeat = (lparam & 0x40000000) != 0 && event.type == KeyEventType::KeyDown;
181
+ event.is_global = false;
182
+ event.window_id = window_id;
183
+ return event;
184
+ }
185
+
186
+ inline UINT hotkey_modifiers_from_shortcut(const Shortcut& shortcut) {
187
+ UINT modifiers = 0;
188
+ if (shortcut.ctrl) modifiers |= MOD_CONTROL;
189
+ if (shortcut.shift) modifiers |= MOD_SHIFT;
190
+ if (shortcut.alt) modifiers |= MOD_ALT;
191
+ if (shortcut.meta) modifiers |= MOD_WIN;
192
+ return modifiers;
193
+ }
194
+
195
+ inline bool is_modifier_key(Key key) {
196
+ return key == Key::Shift || key == Key::Control || key == Key::Alt || key == Key::Meta;
197
+ }
198
+
199
+ } // namespace wpp::input::win32
@@ -0,0 +1,192 @@
1
+ #pragma once
2
+
3
+ #include <functional>
4
+ #include <string>
5
+ #include <utility>
6
+ #include <vector>
7
+
8
+ #include "input_service.h"
9
+ #include "../FileSystem/filesystem_json.h"
10
+
11
+ namespace wpp::input {
12
+
13
+ using EvalFn = std::function<void(const std::string& js)>;
14
+ using DispatchFn = std::function<void(std::function<void()>)>;
15
+
16
+ class InputBridge {
17
+ public:
18
+ InputBridge(EvalFn eval_fn, DispatchFn dispatch_fn, std::string window_id)
19
+ : eval_(std::move(eval_fn)), dispatch_(std::move(dispatch_fn)), window_id_(std::move(window_id)) {
20
+ listener_id_ = Service::instance().add_key_listener([this](const KeyEvent& event) {
21
+ if (!stream_enabled_) {
22
+ return;
23
+ }
24
+ if (!event.is_global && event.window_id != window_id_) {
25
+ return;
26
+ }
27
+ emit_event("key", key_event_to_json(event));
28
+ });
29
+ }
30
+
31
+ ~InputBridge() {
32
+ if (listener_id_ != 0) {
33
+ Service::instance().remove_key_listener(listener_id_);
34
+ }
35
+ }
36
+
37
+ void dispatch(const std::string& raw) {
38
+ std::string id;
39
+ std::string method;
40
+ std::vector<wpp::fs::JsonValue> params;
41
+
42
+ try {
43
+ auto env = wpp::fs::JsonValue::parse(raw);
44
+ id = env["id"].as_string();
45
+ method = env["method"].as_string();
46
+ params = env["params"].as_array();
47
+ } catch (...) {
48
+ return;
49
+ }
50
+
51
+ if (method.rfind("input:", 0) != 0) {
52
+ return;
53
+ }
54
+
55
+ auto reply_ok = [this, &id](const std::string& json_result) {
56
+ eval_("window.__response__(" + wpp::fs::JsonValue::to_js_argument(id) + "," + json_result + ")");
57
+ };
58
+
59
+ auto reply_err = [this, &id](const std::string& msg) {
60
+ eval_(
61
+ "window.__response__(" + wpp::fs::JsonValue::to_js_argument(id) + ",null," +
62
+ wpp::fs::JsonValue::to_js_argument(msg) + ")");
63
+ };
64
+
65
+ try {
66
+ if (method == "input:setEventStreamEnabled") {
67
+ stream_enabled_ = !params.empty() && params[0].as_bool();
68
+ reply_ok("null");
69
+
70
+ } else if (method == "input:getPressedKeys") {
71
+ const auto pressed = Service::instance().pressed_keys();
72
+ std::string json = "[";
73
+ for (size_t index = 0; index < pressed.size(); ++index) {
74
+ if (index > 0) {
75
+ json += ',';
76
+ }
77
+ json += wpp::fs::JsonValue::dump_value(key_to_string(pressed[index]));
78
+ }
79
+ json += "]";
80
+ reply_ok(json);
81
+
82
+ } else if (method == "input:isPressed") {
83
+ if (params.empty()) {
84
+ throw std::runtime_error("Missing key parameter");
85
+ }
86
+ const auto shortcut = Service::instance().parse_shortcut(params[0].as_string());
87
+ reply_ok(Service::instance().is_pressed(shortcut.key) ? "true" : "false");
88
+
89
+ } else if (method == "input:registerLocalShortcut") {
90
+ if (params.size() < 2) {
91
+ throw std::runtime_error("Expected id and shortcut");
92
+ }
93
+ const auto shortcut_id = params[0].as_string();
94
+ const auto shortcut_text = params[1].as_string();
95
+ Service::instance().register_shortcut(
96
+ shortcut_id,
97
+ shortcut_text,
98
+ [this, shortcut_id](const KeyEvent& event) {
99
+ emit_event("shortcut", shortcut_event_to_json(shortcut_id, event));
100
+ },
101
+ ShortcutOptions{false, false, false, window_id_});
102
+ reply_ok("null");
103
+
104
+ } else if (method == "input:registerGlobalHotkey") {
105
+ if (params.size() < 2) {
106
+ throw std::runtime_error("Expected id and shortcut");
107
+ }
108
+ const auto shortcut_id = params[0].as_string();
109
+ const auto shortcut_text = params[1].as_string();
110
+ Service::instance().register_shortcut(
111
+ shortcut_id,
112
+ shortcut_text,
113
+ [this, shortcut_id](const KeyEvent& event) {
114
+ emit_event("shortcut", shortcut_event_to_json(shortcut_id, event));
115
+ },
116
+ ShortcutOptions{true, false, false, {}});
117
+ reply_ok("null");
118
+
119
+ } else if (method == "input:unregisterShortcut") {
120
+ if (params.empty()) {
121
+ throw std::runtime_error("Expected id");
122
+ }
123
+ Service::instance().unregister_shortcut(params[0].as_string());
124
+ reply_ok("null");
125
+
126
+ } else if (method == "input:clearShortcuts") {
127
+ Service::instance().clear_shortcuts();
128
+ reply_ok("null");
129
+ }
130
+ } catch (const std::exception& e) {
131
+ reply_err(e.what());
132
+ } catch (...) {
133
+ reply_err("Unknown error in input bridge");
134
+ }
135
+ }
136
+
137
+ private:
138
+ std::string key_event_to_json(const KeyEvent& event) const {
139
+ std::string json = "{";
140
+ json += "\"type\":" + wpp::fs::JsonValue::dump_value(event.type == KeyEventType::KeyDown ? std::string("keydown") : std::string("keyup"));
141
+ json += ",\"key\":" + wpp::fs::JsonValue::dump_value(key_to_string(event.key));
142
+ json += ",\"keyName\":" + wpp::fs::JsonValue::dump_value(event.key_name);
143
+ json += ",\"keycode\":" + std::to_string(event.keycode);
144
+ json += ",\"scancode\":" + std::to_string(event.scancode);
145
+ json += ",\"ctrl\":" + std::string(event.ctrl ? "true" : "false");
146
+ json += ",\"shift\":" + std::string(event.shift ? "true" : "false");
147
+ json += ",\"alt\":" + std::string(event.alt ? "true" : "false");
148
+ json += ",\"meta\":" + std::string(event.meta ? "true" : "false");
149
+ json += ",\"repeat\":" + std::string(event.is_repeat ? "true" : "false");
150
+ json += ",\"global\":" + std::string(event.is_global ? "true" : "false");
151
+ json += ",\"windowId\":" + wpp::fs::JsonValue::dump_value(event.window_id);
152
+ json += ",\"pressedKeys\":[";
153
+ for (size_t index = 0; index < event.pressed_keys.size(); ++index) {
154
+ if (index > 0) {
155
+ json += ',';
156
+ }
157
+ json += wpp::fs::JsonValue::dump_value(key_to_string(event.pressed_keys[index]));
158
+ }
159
+ json += "]";
160
+ json += "}";
161
+ return json;
162
+ }
163
+
164
+ std::string shortcut_event_to_json(const std::string& id, const KeyEvent& event) const {
165
+ std::string json = "{";
166
+ json += "\"id\":" + wpp::fs::JsonValue::dump_value(id);
167
+ json += ",\"event\":" + key_event_to_json(event);
168
+ json += "}";
169
+ return json;
170
+ }
171
+
172
+ void emit_event(const std::string& event_name, const std::string& json_payload) {
173
+ std::string script = "window.__wpp_input_event__ && window.__wpp_input_event__(" +
174
+ wpp::fs::JsonValue::to_js_argument(event_name) + "," +
175
+ json_payload + ")";
176
+ if (dispatch_) {
177
+ dispatch_([eval = eval_, script = std::move(script)]() {
178
+ eval(script);
179
+ });
180
+ return;
181
+ }
182
+ eval_(script);
183
+ }
184
+
185
+ EvalFn eval_;
186
+ DispatchFn dispatch_;
187
+ std::string window_id_;
188
+ Service::ListenerId listener_id_ = 0;
189
+ bool stream_enabled_ = false;
190
+ };
191
+
192
+ } // namespace wpp::input