1 namespace gui::drivers;
3 #ifdef BUILDING_ECERE_COM
8 public import static "ecere"
18 // source file line number printf (sflnprintf)
19 #define sflnprintf(format,...) printf("%s:% 5d: " format, __FILE__, __LINE__, ##__VA_ARGS__)
21 #define property _property
24 #include <emscripten.h>
31 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit;
32 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp;
33 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown;
34 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit;
35 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove;
36 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick;
37 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown;
38 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp;
39 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick;
40 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown;
41 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp;
42 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick;
43 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown;
44 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp;
48 static Point lastMouse;
50 static inline const char *emscripten_event_type_to_string(int eventType) {
51 const char *events[] = { "(invalid)", "(none)", "keypress", "keydown", "keyup", "click", "mousedown", "mouseup", "dblclick", "mousemove", "wheel", "resize",
52 "scroll", "blur", "focus", "focusin", "focusout", "deviceorientation", "devicemotion", "orientationchange", "fullscreenchange", "pointerlockchange",
53 "visibilitychange", "touchstart", "touchend", "touchmove", "touchcancel", "gamepadconnected", "gamepaddisconnected", "beforeunload",
54 "batterychargingchange", "batterylevelchange", "webglcontextlost", "webglcontextrestored", "mouseenter", "mouseleave", "mouseover", "mouseout", "(invalid)" };
56 if (eventType < 0) eventType = 0;
57 if (eventType >= sizeof(events)/sizeof(events[0])) eventType = sizeof(events)/sizeof(events[0])-1;
58 return events[eventType];
61 static int mouseButtons;
62 static int movementX, movementY;
64 static bool isFullScreen;
66 static EM_BOOL mouse_callback(int eventType, const EmscriptenMouseEvent *e, void *userData)
68 Window window = guiApp.desktop;
72 mods.alt = e->altKey ? true : false;
73 mods.shift = e->shiftKey ? true : false;
74 mods.ctrl = e->ctrlKey ? true : false;
76 mods.left = (mouseButtons & 1) ? true : false;
77 mods.right = (mouseButtons & 2) ? true : false;
78 mods.middle = (mouseButtons & 4) ? true : false;
82 case EMSCRIPTEN_EVENT_MOUSEMOVE:
83 lastMouse = { e->canvasX, e->canvasY };
84 window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove,
85 e->canvasX, e->canvasY, &mods, false, true);
86 movementX += e->movementX;
87 movementY += e->movementY;
89 case EMSCRIPTEN_EVENT_MOUSEDOWN:
90 // PrintLn("EMSCRIPTEN_EVENT_MOUSEDOWN!");
92 e->button == 0 ? __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown :
93 e->button == 2 ? __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown :
94 __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown;
95 window.MouseMessage(methodID, e->canvasX, e->canvasY, &mods, false, true);
98 else if(e->button == 2)
103 case EMSCRIPTEN_EVENT_MOUSEUP:
105 e->button == 0 ? __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp :
106 e->button == 2 ? __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp :
107 __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp;
108 window.MouseMessage(methodID, e->canvasX, e->canvasY, &mods, false, true);
111 else if(e->button == 2)
116 case EMSCRIPTEN_EVENT_DBLCLICK:
118 e->button == 0 ? __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick :
119 e->button == 2 ? __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick :
120 __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick;
121 window.MouseMessage(methodID, e->canvasX, e->canvasY, &mods, false, true);
126 printf("%s, screen: (%ld,%ld), client: (%ld,%ld),%s%s%s%s button: %hu, buttons: %hu, movement: (%ld,%ld), canvas: (%ld,%ld)\n",
127 emscripten_event_type_to_string(eventType), e->screenX, e->screenY, e->clientX, e->clientY,
128 e->ctrlKey ? " CTRL" : "", e->shiftKey ? " SHIFT" : "", e->altKey ? " ALT" : "", e->metaKey ? " META" : "",
129 e->button, e->buttons, e->movementX, e->movementY, e->canvasX, e->canvasY);
134 static EM_BOOL wheel_callback(int eventType, const EmscriptenWheelEvent *e, void *userData)
136 Window window = guiApp.desktop;
137 Key key = (e->deltaY < 0 || e->deltaX < 0) ? wheelUp : wheelDown;
139 key.alt = e->mouse.altKey ? true : false;
140 key.shift = e->mouse.shiftKey ? true : false;
141 key.ctrl = e->mouse.ctrlKey ? true : false;
144 printf("%s, screen: (%ld,%ld), client: (%ld,%ld),%s%s%s%s button: %hu, buttons: %hu, canvas: (%ld,%ld), delta:(%g,%g,%g), deltaMode:%lu\n",
145 emscripten_event_type_to_string(eventType), e->mouse.screenX, e->mouse.screenY, e->mouse.clientX, e->mouse.clientY,
146 e->mouse.ctrlKey ? " CTRL" : "", e->mouse.shiftKey ? " SHIFT" : "", e->mouse.altKey ? " ALT" : "", e->mouse.metaKey ? " META" : "",
147 e->mouse.button, e->mouse.buttons, e->mouse.canvasX, e->mouse.canvasY,
148 (float)e->deltaX, (float)e->deltaY, (float)e->deltaZ, e->deltaMode);
151 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, key, 0);
155 static bool keyStatus[KeyCode];
157 EM_BOOL pointerlockchange_callback(int eventType, const EmscriptenPointerlockChangeEvent *e, void *userData)
161 if(guiApp.acquiredWindow)
163 guiApp.acquiredWindow.acquiredInput = false;
164 guiApp.acquiredWindow = null;
169 Window w = guiApp.desktop;
170 if(w && w.children.first) w = w.children.first;
171 guiApp.acquiredWindow = w;
172 guiApp.acquiredWindow.acquiredInput = true;
175 printf("%s, isActive: %d, pointerlock element nodeName: \"%s\", id: \"%s\"\n",
176 emscripten_event_type_to_string(eventType), e->isActive, e->nodeName, e->id);
183 EM_BOOL fullscreenchange_callback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData)
186 double dw = 0, dh = 0;
187 isFullScreen = (bool)e->isFullscreen;
188 *&guiApp.fullScreen = isFullScreen;
190 emscripten_get_element_css_size(0, &dw, &dh);
191 w = (int)dw, h = (int)dh;
194 emscripten_set_canvas_size(w, h);
195 guiApp.desktop.ExternalPosition(0,0, w, h);
196 if(guiApp.desktop.display && guiApp.desktop.display.displaySystem)
197 guiApp.desktop.display.Resize(w, h);
204 // The event handler functions can return 1 to suppress the event and disable the default action. That calls event.preventDefault();
205 // Returning 0 signals that the event was not consumed by the code, and will allow the event to pass on and bubble up normally.
206 EM_BOOL key_callback(int eventType, const EmscriptenKeyboardEvent *e, void *userData)
208 Window window = guiApp.desktop;
212 case 8: key = backSpace; break;
213 case 9: key = tab; break;
214 case 13: key = enter; break;
215 case 16: key = shift; break;
216 case 17: key = control; break;
217 case 18: key = alt; break;
218 case 19: key = pause; break;
219 case 20: key = capsLock; break;
220 case 27: key = escape; break;
221 case 32: key = space; break;
222 case 33: key = pageUp; break;
223 case 34: key = pageDown; break;
224 case 35: key = end; break;
225 case 36: key = home; break;
226 case 37: key = left; break;
227 case 38: key = up; break;
228 case 39: key = right; break;
229 case 40: key = down; break;
230 case 44: key = printScreen; break;
231 case 45: key = insert; break;
232 case 46: key = del; break;
233 case 48: key = k0; break;
234 case 49: key = k1; break;
235 case 50: key = k2; break;
236 case 51: key = k3; break;
237 case 52: key = k4; break;
238 case 53: key = k5; break;
239 case 54: key = k6; break;
240 case 55: key = k7; break;
241 case 56: key = k8; break;
242 case 57: key = k9; break;
243 case 65: key = a; break;
244 case 66: key = b; break;
245 case 67: key = c; break;
246 case 68: key = d; break;
247 case 69: key = KeyCode::e; break;
248 case 70: key = f; break;
249 case 71: key = g; break;
250 case 72: key = h; break;
251 case 73: key = i; break;
252 case 74: key = j; break;
253 case 75: key = k; break;
254 case 76: key = l; break;
255 case 77: key = m; break;
256 case 78: key = n; break;
257 case 79: key = o; break;
258 case 80: key = p; break;
259 case 81: key = q; break;
260 case 82: key = r; break;
261 case 83: key = s; break;
262 case 84: key = t; break;
263 case 85: key = u; break;
264 case 86: key = v; break;
265 case 87: key = w; break;
266 case 88: key = x; break;
267 case 89: key = y; break;
268 case 90: key = z; break;
269 // case 91: key = start; break;
270 // case 93: key = context; break;
271 case 112: key = f1; break;
272 case 113: key = f2; break;
273 case 114: key = f3; break;
274 case 115: key = f4; break;
275 case 116: key = f5; break;
276 case 117: key = f6; break;
277 case 118: key = f7; break;
278 case 119: key = f8; break;
279 case 120: key = f9; break;
280 case 121: key = f10; break;
281 case 122: key = f11; break;
282 case 123: key = f12; break;
283 case 144: key = numLock; break;
284 case 125: key = scrollLock; break;
285 case 188: key = comma; break;
286 case 190: key = period; break;
287 case 191: key = slash; break;
288 case 192: key = tilde; break;
289 case 219: key = leftBracket; break; // also corresponds to the Win Key (Start) in older versions of Opera.
290 case 220: key = backSlash; break;
291 case 221: key = rightBracket; break;
292 case 222: key = quote; break;
294 /*case 173: */case 181: key = mute; break; // FF: 181
295 case 174: case 182: key = volumeDown; break; // FF: 182
296 case 175: case 183: key = volumeDown; break; // FF: 183
297 case 186: case 59: key = semicolon; break; // FF: 59
298 case 187: case 61: key = equal; break; // FF: 61
299 case 189: case 173: key = minus; break; // FF: 61
301 case 96: key = keyPad0; break;
302 //case 45: key = keyPadInsert; break;
304 case 97: key = keyPad1; break;
305 //case 35: key = keyPadEnd; break;
307 case 98: key = keyPad2; break;
308 //case 40: key = keyPadDown; break;
310 case 99: key = keyPad3; break;
311 //case 34: key = keyPadPageDown; break;
313 case 100: key = keyPad4; break;
314 //case 37: key = keyPadLeft; break;
316 case 101: key = keyPad5; break;
317 case 12: key = keyPad5; break;
319 case 102: key = keyPad6; break;
320 //case 39: key = keyPadRight; break;
322 case 103: key = keyPad7; break;
323 //case 36: key = keyPadHome; break;
325 case 104: key = keyPad8; break;
326 //case 38: key = keyPadUp; break;
328 case 105: key = keyPad9; break;
329 //case 33: key = keyPadPageUp; break;
331 case 106: key = keyPadStar; break;
332 case 107: key = keyPadPlus; break;
333 case 109: key = keyPadMinus; break;
335 case 110: key = keyPadDelete; break;
336 //case 46: key = keyPadDelete; break;
338 case 11: key = keyPadSlash; break;
341 key.alt = e->altKey ? true : false;
342 key.shift = e->shiftKey ? true : false;
343 key.ctrl = e->ctrlKey ? true : false;
346 key.modifiers.left = (mouseButtons & 1) ? true : false;
347 key.modifiers.right = (mouseButtons & 2) ? true : false;
348 key.modifiers.middle = (mouseButtons & 4) ? true : false;
353 printf("%s, key: \"%s\", code: \"%s\", location: %lu,%s%s%s%s repeat: %d, locale: \"%s\", char: \"%s\", charCode: %lu, keyCode: %lu, which: %lu\n",
354 emscripten_event_type_to_string(eventType), e->key, e->code, e->location,
355 e->ctrlKey ? " CTRL" : "", e->shiftKey ? " SHIFT" : "", e->altKey ? " ALT" : "", e->metaKey ? " META" : "",
356 e->repeat, e->locale, e->charValue, e->charCode, e->keyCode, e->which);
362 case EMSCRIPTEN_EVENT_KEYDOWN:
363 //PrintLn("Setting ", key, " to down");
364 keyStatus[key] = true;
365 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, key, (unichar)e->charCode);
367 case EMSCRIPTEN_EVENT_KEYUP:
368 //PrintLn("Setting ", key, " to false");
369 keyStatus[key] = false;
370 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, key, (unichar)e->charCode);
376 if (eventType == EMSCRIPTEN_EVENT_KEYPRESS && (!strcmp(e->key, "f") || e->which == 102)) {
377 EmscriptenFullscreenChangeEvent fsce;
378 EMSCRIPTEN_RESULT ret = emscripten_get_fullscreen_status(&fsce);
379 TEST_RESULT(emscripten_get_fullscreen_status);
380 if (!fsce.isFullscreen) {
381 printf("Requesting fullscreen..\n");
382 ret = emscripten_request_fullscreen(0, 1);
383 TEST_RESULT(emscripten_request_fullscreen);
385 printf("Exiting fullscreen..\n");
386 ret = emscripten_exit_fullscreen();
387 TEST_RESULT(emscripten_exit_fullscreen);
388 ret = emscripten_get_fullscreen_status(&fsce);
389 TEST_RESULT(emscripten_get_fullscreen_status);
390 if (fsce.isFullscreen) {
391 fprintf(stderr, "Fullscreen exit did not work!\n");
396 if (eventType == EMSCRIPTEN_EVENT_KEYPRESS && (!strcmp(e->key, "p") || e->which == 112)) {
397 EmscriptenPointerlockChangeEvent plce;
398 EMSCRIPTEN_RESULT ret = emscripten_get_pointerlock_status(&plce);
399 TEST_RESULT(emscripten_get_pointerlock_status);
400 if (!plce.isActive) {
401 printf("Requesting pointer lock..\n");
402 ret = emscripten_request_pointerlock(0, 1);
403 TEST_RESULT(emscripten_request_pointerlock);
405 printf("Exiting pointer lock..\n");
406 ret = emscripten_exit_pointerlock();
407 TEST_RESULT(emscripten_exit_pointerlock);
408 ret = emscripten_get_pointerlock_status(&plce);
409 TEST_RESULT(emscripten_get_pointerlock_status);
411 fprintf(stderr, "Pointer lock exit did not work!\n");
420 static EM_BOOL uievent_callback(int eventType, const EmscriptenUiEvent *e, void *userData)
424 case EMSCRIPTEN_EVENT_RESIZE:
425 //case EMSCRIPTEN_EVENT_SCROLL:
428 double dw = 0, dh = 0;
429 emscripten_get_element_css_size(0, &dw, &dh);
430 w = (int)dw, h = (int)dh;
433 emscripten_set_canvas_size(w, h);
434 guiApp.desktop.ExternalPosition(0,0, w, h);
435 if(guiApp.desktop.display && guiApp.desktop.display.displaySystem)
436 guiApp.desktop.display.Resize(w, h);
438 //PrintLn("EMSCRIPTEN_EVENT_RESIZE: ", w, " x ", h);
443 printf("%s, detail: %ld, document.body.client size: (%d,%d), window.inner size: (%d,%d), scrollPos: (%d, %d)\n",
444 emscripten_event_type_to_string(eventType), e->detail, e->documentBodyClientWidth, e->documentBodyClientHeight,
445 e->windowInnerWidth, e->windowInnerHeight, e->scrollTop, e->scrollLeft);
450 class EmscriptenInterface : Interface
452 class_property(name) = "Emscripten";
454 // --- User Interface System ---
458 emscripten_set_resize_callback(0, 0, 1, uievent_callback);
459 //emscripten_set_scroll_callback(0, 0, 1, uievent_callback);
460 emscripten_set_click_callback(0, 0, 1, mouse_callback);
461 emscripten_set_mousedown_callback(0, 0, 1, mouse_callback);
462 emscripten_set_mouseup_callback(0, 0, 1, mouse_callback);
463 emscripten_set_dblclick_callback(0, 0, 1, mouse_callback);
464 emscripten_set_mousemove_callback(0, 0, 1, mouse_callback);
465 emscripten_set_wheel_callback(0, 0, 1, wheel_callback);
466 emscripten_set_keypress_callback(0, 0, 1, key_callback);
467 emscripten_set_keydown_callback(0, 0, 1, key_callback);
468 emscripten_set_keyup_callback(0, 0, 1, key_callback);
469 emscripten_set_pointerlockchange_callback(0, 0, 1, pointerlockchange_callback);
470 emscripten_set_fullscreenchange_callback(0, 0, 1, fullscreenchange_callback);
471 /*emscripten_set_mouseenter_callback(0, 0, 1, mouse_callback);
472 emscripten_set_mouseleave_callback(0, 0, 1, mouse_callback);*/
481 bool ::ProcessInput(bool processAll)
492 void ::Lock(Window window)
497 void ::Unlock(Window window)
502 void ::SetTimerResolution(uint hertz)
507 const char ** ::GraphicsDrivers(int * numDrivers)
509 static const char *graphicsDrivers[] = { "OpenGL" };
510 *numDrivers = sizeof(graphicsDrivers) / sizeof(char *);
511 return (const char **)graphicsDrivers;
515 void ::EnsureFullScreen(bool * fullScreen)
520 void ::GetCurrentMode(bool * fullScreen, Resolution * resolution, PixelFormat * colorDepth, int * refreshRate)
522 *fullScreen = isFullScreen;
525 bool ::ScreenMode(bool fullScreen, Resolution resolution, PixelFormat colorDepth, int refreshRate, bool * textMode)
528 emscripten_request_fullscreen(0, 1);
530 emscripten_exit_fullscreen();
535 // --- Window Creation ---
537 void * ::CreateRootWindow(Window window)
540 return (void *)(uintptr)1;
543 void ::DestroyRootWindow(Window window)
549 // --- Window manipulation ---
551 void ::SetRootWindowCaption(Window window, const char * name)
556 void ::PositionRootWindow(Window window, int x, int y, int w, int h, bool move, bool resize)
561 void ::OffsetWindow(Window window, int * x, int * y)
566 void ::UpdateRootWindow(Window window)
571 void ::SetRootWindowState(Window window, WindowState state, bool visible)
576 void ::ActivateRootWindow(Window window)
581 void ::OrderRootWindow(Window window, bool topMost)
586 void ::SetRootWindowColor(Window window)
591 void ::FlashRootWindow(Window window)
597 // --- Mouse-based window movement ---
599 void ::StartMoving(Window window, int x, int y, bool fromKeyBoard)
604 void ::StopMoving(Window window)
610 // --- Mouse manipulation ---
612 void ::GetMousePosition(int *x, int *y)
618 void ::SetMousePosition(int x, int y)
623 void ::SetMouseRange(Window window, Box box)
628 void ::SetMouseCapture(Window window)
634 // --- Mouse cursor ---
636 void ::SetMouseCursor(Window window, SystemCursor cursor)
642 // --- Caret manipulation ---
644 void ::SetCaret(int caretX, int caretY, int size)
650 // --- Clipboard manipulation ---
652 void ::ClearClipboard()
657 bool ::AllocateClipboard(ClipBoard clipBoard, uint size)
663 bool ::SaveClipboard(ClipBoard clipBoard)
669 bool ::LoadClipboard(ClipBoard clipBoard)
675 void ::UnloadClipboard(ClipBoard clipBoard)
681 // --- State based input ---
683 bool ::AcquireInput(Window window, bool state)
686 emscripten_request_pointerlock(0, 1);
688 emscripten_exit_pointerlock();
695 bool ::GetMouseState(MouseButtons * buttons, int * x, int * y)
697 if(buttons) *buttons = { left = mouseButtons & 1, right = (mouseButtons & 2) ? true : false, middle = (mouseButtons & 4) ? true : false };
698 if(x) { *x = movementX; movementX = 0; }
699 if(y) { *y = movementY; movementY = 0; }
704 bool ::GetJoystickState(int device, Joystick joystick)
710 bool ::GetKeyState(Key key)
712 return keyStatus[key];
715 bool ::SetIcon(Window window, BitmapResource icon)
721 void ::GetScreenArea(Window window, Box box)