1 //
2 // Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // Copyright (c) 2023 BlackBerry Limited
7 //
8
9 // QNXWindow.cpp: Implementation of OSWindow for QNX
10
11 #include "qnx/QNXWindow.h"
12
13 #include <assert.h>
14 #include <pthread.h>
15 #include <sys/keycodes.h>
16
17 #include "aemu/base/system/System.h"
18
19 namespace {
20 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
21 static screen_context_t g_screen_ctx;
22 static int FAKE_MOUSE_BUTTON_FOR_TRIGGER_TEST_EVENT = 5;
23
screen_init(void)24 static void screen_init(void) {
25 /* initialize the global screen context */
26 screen_create_context(&g_screen_ctx, SCREEN_APPLICATION_CONTEXT);
27 }
28
get_screen_context()29 static screen_context_t get_screen_context() {
30 pthread_once(&once_control, screen_init);
31 return g_screen_ctx;
32 }
33
QNXCodeToKey(unsigned keycode)34 Key QNXCodeToKey(unsigned keycode) {
35 switch (keycode) {
36 case KEYCODE_RETURN:
37 case KEYCODE_KP_ENTER:
38 return KEY_RETURN;
39 case KEYCODE_BACKSPACE:
40 return KEY_BACK;
41 case KEYCODE_DELETE:
42 return KEY_DELETE;
43 case KEYCODE_ESCAPE:
44 return KEY_ESCAPE;
45 case KEYCODE_SPACE:
46 return KEY_SPACE;
47 case KEYCODE_ZERO:
48 case KEYCODE_RIGHT_PAREN:
49 return KEY_NUM0;
50 case KEYCODE_ONE:
51 case KEYCODE_EXCLAM:
52 return KEY_NUM1;
53 case KEYCODE_TWO:
54 case KEYCODE_AT:
55 return KEY_NUM2;
56 case KEYCODE_THREE:
57 case KEYCODE_NUMBER:
58 return KEY_NUM3;
59 case KEYCODE_FOUR:
60 case KEYCODE_DOLLAR:
61 return KEY_NUM4;
62 case KEYCODE_FIVE:
63 case KEYCODE_PERCENT:
64 return KEY_NUM5;
65 case KEYCODE_SIX:
66 case KEYCODE_CIRCUMFLEX:
67 return KEY_NUM6;
68 case KEYCODE_SEVEN:
69 case KEYCODE_AMPERSAND:
70 return KEY_NUM7;
71 case KEYCODE_EIGHT:
72 case KEYCODE_ASTERISK:
73 return KEY_NUM8;
74 case KEYCODE_NINE:
75 case KEYCODE_LEFT_PAREN:
76 return KEY_NUM9;
77 case KEYCODE_A:
78 case KEYCODE_CAPITAL_A:
79 return KEY_A;
80 case KEYCODE_B:
81 case KEYCODE_CAPITAL_B:
82 return KEY_B;
83 case KEYCODE_C:
84 case KEYCODE_CAPITAL_C:
85 return KEY_C;
86 case KEYCODE_D:
87 case KEYCODE_CAPITAL_D:
88 return KEY_D;
89 case KEYCODE_E:
90 case KEYCODE_CAPITAL_E:
91 return KEY_E;
92 case KEYCODE_F:
93 case KEYCODE_CAPITAL_F:
94 return KEY_F;
95 case KEYCODE_G:
96 case KEYCODE_CAPITAL_G:
97 return KEY_G;
98 case KEYCODE_H:
99 case KEYCODE_CAPITAL_H:
100 return KEY_H;
101 case KEYCODE_I:
102 case KEYCODE_CAPITAL_I:
103 return KEY_I;
104 case KEYCODE_J:
105 case KEYCODE_CAPITAL_J:
106 return KEY_J;
107 case KEYCODE_K:
108 case KEYCODE_CAPITAL_K:
109 return KEY_K;
110 case KEYCODE_L:
111 case KEYCODE_CAPITAL_L:
112 return KEY_L;
113 case KEYCODE_M:
114 case KEYCODE_CAPITAL_M:
115 return KEY_M;
116 case KEYCODE_N:
117 case KEYCODE_CAPITAL_N:
118 return KEY_N;
119 case KEYCODE_O:
120 case KEYCODE_CAPITAL_O:
121 return KEY_O;
122 case KEYCODE_P:
123 case KEYCODE_CAPITAL_P:
124 return KEY_P;
125 case KEYCODE_Q:
126 case KEYCODE_CAPITAL_Q:
127 return KEY_Q;
128 case KEYCODE_R:
129 case KEYCODE_CAPITAL_R:
130 return KEY_R;
131 case KEYCODE_S:
132 case KEYCODE_CAPITAL_S:
133 return KEY_S;
134 case KEYCODE_T:
135 case KEYCODE_CAPITAL_T:
136 return KEY_T;
137 case KEYCODE_U:
138 case KEYCODE_CAPITAL_U:
139 return KEY_U;
140 case KEYCODE_V:
141 case KEYCODE_CAPITAL_V:
142 return KEY_V;
143 case KEYCODE_W:
144 case KEYCODE_CAPITAL_W:
145 return KEY_W;
146 case KEYCODE_X:
147 case KEYCODE_CAPITAL_X:
148 return KEY_X;
149 case KEYCODE_Y:
150 case KEYCODE_CAPITAL_Y:
151 return KEY_Y;
152 case KEYCODE_Z:
153 case KEYCODE_CAPITAL_Z:
154 return KEY_Z;
155 case KEYCODE_PLUS:
156 case KEYCODE_EQUAL:
157 return KEY_EQUAL;
158 case KEYCODE_MINUS:
159 case KEYCODE_UNDERSCORE:
160 return KEY_SUBTRACT;
161 case KEYCODE_LESS_THAN:
162 case KEYCODE_COMMA:
163 return KEY_COMMA;
164 case KEYCODE_GREATER_THAN:
165 case KEYCODE_PERIOD:
166 return KEY_PERIOD;
167 case KEYCODE_COLON:
168 case KEYCODE_SEMICOLON:
169 return KEY_SEMICOLON;
170 case KEYCODE_SLASH:
171 case KEYCODE_QUESTION:
172 return KEY_SLASH;
173 case KEYCODE_TILDE:
174 case KEYCODE_GRAVE:
175 return KEY_TILDE;
176 case KEYCODE_LEFT_BRACE:
177 case KEYCODE_LEFT_BRACKET:
178 return KEY_LBRACKET;
179 case KEYCODE_BAR:
180 case KEYCODE_BACK_SLASH:
181 return KEY_BACKSLASH;
182 case KEYCODE_RIGHT_BRACE:
183 case KEYCODE_RIGHT_BRACKET:
184 return KEY_RBRACKET;
185 case KEYCODE_QUOTE:
186 case KEYCODE_APOSTROPHE:
187 return KEY_QUOTE;
188 case KEYCODE_PAUSE:
189 return KEY_PAUSE;
190 case KEYCODE_TAB:
191 case KEYCODE_BACK_TAB:
192 return KEY_TAB;
193 case KEYCODE_LEFT:
194 return KEY_LEFT;
195 case KEYCODE_KP_LEFT:
196 return KEY_NUMPAD4;
197 case KEYCODE_KP_FIVE:
198 return KEY_NUMPAD5;
199 case KEYCODE_RIGHT:
200 return KEY_RIGHT;
201 case KEYCODE_KP_RIGHT:
202 return KEY_NUMPAD6;
203 case KEYCODE_UP:
204 return KEY_UP;
205 case KEYCODE_KP_UP:
206 return KEY_NUMPAD8;
207 case KEYCODE_DOWN:
208 return (Key)(KEY_UP + 1); // avoid name collision
209 case KEYCODE_KP_DOWN:
210 return KEY_NUMPAD2;
211 case KEYCODE_MENU:
212 case KEYCODE_LEFT_ALT:
213 case KEYCODE_RIGHT_ALT:
214 return KEY_MENU;
215 case KEYCODE_HOME:
216 return KEY_HOME;
217 case KEYCODE_END:
218 return KEY_END;
219 case KEYCODE_LEFT_SHIFT:
220 return KEY_LSHIFT;
221 case KEYCODE_RIGHT_SHIFT:
222 return KEY_RSHIFT;
223 case KEYCODE_LEFT_CTRL:
224 return KEY_LCONTROL;
225 case KEYCODE_RIGHT_CTRL:
226 return KEY_RCONTROL;
227 case KEYCODE_KP_PLUS:
228 return KEY_ADD;
229 case KEYCODE_KP_MINUS:
230 return KEY_SUBTRACT;
231 case KEYCODE_KP_MULTIPLY:
232 return KEY_MULTIPLY;
233 case KEYCODE_KP_DIVIDE:
234 return KEY_DIVIDE;
235 case KEYCODE_F1:
236 return KEY_F1;
237 case KEYCODE_F2:
238 return KEY_F2;
239 case KEYCODE_F3:
240 return KEY_F3;
241 case KEYCODE_F4:
242 return KEY_F4;
243 case KEYCODE_F5:
244 return KEY_F5;
245 case KEYCODE_F6:
246 return KEY_F6;
247 case KEYCODE_F7:
248 return KEY_F7;
249 case KEYCODE_F8:
250 return KEY_F8;
251 case KEYCODE_F9:
252 return KEY_F9;
253 case KEYCODE_F10:
254 return KEY_F10;
255 case KEYCODE_F11:
256 return KEY_F11;
257 case KEYCODE_F12:
258 return KEY_F12;
259 default:
260 return KEY_UNKNOWN;
261 }
262 return KEY_UNKNOWN;
263 }
264
QNXCodeToButton(int button)265 MouseButton QNXCodeToButton(int button) {
266 MouseButton target_button = MOUSEBUTTON_UNKNOWN;
267 switch (button) {
268 case SCREEN_LEFT_MOUSE_BUTTON:
269 target_button = MOUSEBUTTON_LEFT;
270 break;
271 case SCREEN_MIDDLE_MOUSE_BUTTON:
272 target_button = MOUSEBUTTON_MIDDLE;
273 break;
274 case SCREEN_RIGHT_MOUSE_BUTTON:
275 target_button = MOUSEBUTTON_RIGHT;
276 break;
277 default:
278 break;
279 }
280 return target_button;
281 }
282 } // namespace
283
QNXWindow()284 QNXWindow::QNXWindow() : mWindow(0), mVisible(false), mPid(getpid()) {}
285
~QNXWindow()286 QNXWindow::~QNXWindow() { destroy(); }
287
initialize(const std::string & name,size_t width,size_t height)288 bool QNXWindow::initialize(const std::string& name, size_t width, size_t height) {
289 screen_context_t screen_ctx;
290 screen_window_t screen_window;
291 int rc;
292
293 screen_ctx = get_screen_context();
294 if (screen_ctx == nullptr) {
295 perror("No screen context");
296 return false;
297 }
298
299 rc = screen_create_window_type(&screen_window, screen_ctx, SCREEN_APPLICATION_WINDOW);
300 if (rc) {
301 perror("screen_create_window");
302 return false;
303 }
304
305 int alpha_mode = SCREEN_PRE_MULTIPLIED_ALPHA;
306 screen_set_window_property_iv(screen_window, SCREEN_PROPERTY_ALPHA_MODE, &alpha_mode);
307
308 int usage = SCREEN_USAGE_NATIVE | SCREEN_USAGE_OPENGL_ES2;
309 screen_set_window_property_iv(screen_window, SCREEN_PROPERTY_USAGE, &usage);
310
311 int interval = 1;
312 screen_set_window_property_iv(screen_window, SCREEN_PROPERTY_SWAP_INTERVAL, &interval);
313
314 int format = SCREEN_FORMAT_RGBA8888;
315 screen_set_window_property_iv(screen_window, SCREEN_PROPERTY_FORMAT, &format);
316
317 int transp = SCREEN_TRANSPARENCY_NONE;
318 screen_set_window_property_iv(screen_window, SCREEN_PROPERTY_TRANSPARENCY, &transp);
319
320 int pos[2] = {0, 0};
321 screen_set_window_property_iv(screen_window, SCREEN_PROPERTY_POSITION, pos);
322
323 int size[2] = {static_cast<int>(width), static_cast<int>(height)};
324 screen_set_window_property_iv(screen_window, SCREEN_PROPERTY_SIZE, size);
325
326 size[0] = width;
327 size[1] = height;
328 screen_set_window_property_iv(screen_window, SCREEN_PROPERTY_BUFFER_SIZE, size);
329
330 rc = screen_create_window_buffers(screen_window, 2);
331 if (rc) {
332 perror("screen_create_window_buffers");
333 screen_destroy_window(screen_window);
334 return false;
335 }
336
337 char group_name[] = "gfx";
338 rc = screen_create_window_group(screen_window, group_name);
339 if (rc) {
340 perror("screen_create_window_group");
341 screen_destroy_window(screen_window);
342 return false;
343 }
344
345 mWindow = screen_window;
346
347 int sensitivity = SCREEN_SENSITIVITY_TEST;
348 screen_set_window_property_iv(screen_window, SCREEN_PROPERTY_SENSITIVITY, &sensitivity);
349
350 screen_set_window_property_cv(screen_window, SCREEN_PROPERTY_ID_STRING, name.size(),
351 name.c_str());
352
353 int visible = mVisible ? 1 : 0;
354 screen_set_window_property_iv(screen_window, SCREEN_PROPERTY_VISIBLE, &visible);
355
356 rc = screen_flush_context(screen_ctx, SCREEN_WAIT_IDLE);
357 if (rc) {
358 perror("flush");
359 }
360
361 return true;
362 }
363
destroy()364 void QNXWindow::destroy() {
365 if (mWindow) screen_destroy_window(mWindow);
366 }
367
getNativeWindow() const368 EGLNativeWindowType QNXWindow::getNativeWindow() const { return mWindow; }
369
getNativeDisplay() const370 EGLNativeDisplayType QNXWindow::getNativeDisplay() const {
371 // TODO: yodai
372 return 0;
373 }
374
getFramebufferNativeWindow() const375 void* QNXWindow::getFramebufferNativeWindow() const { return mWindow; }
376
messageLoop()377 void QNXWindow::messageLoop() {
378 screen_event_t screen_event;
379 int rc = screen_create_event(&screen_event);
380 if (rc) {
381 perror("screen_create_event");
382 return;
383 }
384
385 while (!screen_get_event(get_screen_context(), screen_event, 0)) {
386 int event_type;
387 rc = screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &event_type);
388 if (rc || event_type == SCREEN_EVENT_NONE) {
389 break;
390 }
391
392 switch (event_type) {
393 case SCREEN_EVENT_KEYBOARD:
394 processKeyEvent(screen_event);
395 break;
396 case SCREEN_EVENT_POINTER:
397 processMouseEvent(screen_event);
398 break;
399 case SCREEN_EVENT_PROPERTY:
400 processPropertyChangedEvent(screen_event);
401 break;
402 case SCREEN_EVENT_INPUT_CONTROL:
403 processInputControlEvent(screen_event);
404 break;
405 case SCREEN_EVENT_CLOSE:
406 processCloseEvent(screen_event);
407 break;
408 default:
409 break;
410 }
411 }
412 screen_destroy_event(screen_event);
413 }
414
setMousePosition(int x,int y)415 void QNXWindow::setMousePosition(int x, int y) {
416 screen_event_t screen_event;
417 if (screen_create_event(&screen_event)) return;
418
419 int param = SCREEN_EVENT_POINTER;
420 if (screen_set_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, ¶m)) return;
421
422 if (screen_set_event_property_pv(screen_event, SCREEN_PROPERTY_WINDOW, (void**)&mWindow))
423 return;
424 int coords[] = {x, y};
425 screen_set_event_property_iv(screen_event, SCREEN_PROPERTY_SOURCE_POSITION, coords);
426 screen_send_event(get_screen_context(), screen_event, mPid);
427 }
428
CreateOSWindow()429 OSWindow* CreateOSWindow() { return new QNXWindow(); }
430
setPosition(int x,int y)431 bool QNXWindow::setPosition(int x, int y) {
432 int pos[2] = {x, y};
433 screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_POSITION, pos);
434 screen_context_t screen_ctx = get_screen_context();
435 screen_flush_context(screen_ctx, 0);
436 return true;
437 }
438
resize(int width,int height)439 bool QNXWindow::resize(int width, int height) {
440 int size[2] = {width, height};
441 screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_SIZE, size);
442 size[0] = width;
443 size[1] = height;
444 screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_BUFFER_SIZE, size);
445 return true;
446 }
447
setVisible(bool isVisible)448 void QNXWindow::setVisible(bool isVisible) {
449 if (mVisible == isVisible) {
450 return;
451 }
452 int visible = isVisible ? 1 : 0;
453 if (!screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_VISIBLE, &visible))
454 mVisible = isVisible;
455 }
456
signalTestEvent()457 void QNXWindow::signalTestEvent() {
458 screen_event_t screen_event;
459 if (screen_create_event(&screen_event)) return;
460
461 int param = SCREEN_EVENT_POINTER;
462 if (screen_set_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, ¶m)) return;
463
464 if (screen_set_event_property_pv(screen_event, SCREEN_PROPERTY_WINDOW, (void**)&mWindow))
465 return;
466 int button = FAKE_MOUSE_BUTTON_FOR_TRIGGER_TEST_EVENT;
467 screen_set_event_property_iv(screen_event, SCREEN_PROPERTY_BUTTONS, &button);
468 screen_send_event(get_screen_context(), screen_event, mPid);
469 }
470
processMouseEvent(const screen_event_t & screen_event)471 void QNXWindow::processMouseEvent(const screen_event_t& screen_event) {
472 static int s_lastButtonState = 0;
473 int buttonState = 0;
474 screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_BUTTONS, &buttonState);
475 Event event;
476 if (buttonState == FAKE_MOUSE_BUTTON_FOR_TRIGGER_TEST_EVENT) {
477 event.Type = Event::EVENT_TEST;
478 pushEvent(event);
479 return;
480 }
481
482 int lastButtonState = s_lastButtonState;
483
484 s_lastButtonState = buttonState;
485 int wheel_ticks = 0;
486 screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_MOUSE_WHEEL, &wheel_ticks);
487 if (wheel_ticks)
488 event.Type = Event::EVENT_MOUSE_WHEEL_MOVED;
489 else if (buttonState == lastButtonState)
490 event.Type = Event::EVENT_MOUSE_MOVED;
491 else if (buttonState > lastButtonState)
492 event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED;
493 else
494 event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED;
495
496 switch (event.Type) {
497 case Event::EVENT_MOUSE_WHEEL_MOVED:
498 event.MouseWheel.Delta = wheel_ticks;
499 pushEvent(event);
500 break;
501 case Event::EVENT_MOUSE_MOVED:
502 int position[2];
503 screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_SOURCE_POSITION, position);
504 event.MouseMove.X = position[0];
505 event.MouseMove.Y = position[1];
506 pushEvent(event);
507 break;
508 case Event::EVENT_MOUSE_BUTTON_RELEASED:
509 case Event::EVENT_MOUSE_BUTTON_PRESSED:
510 event.MouseButton.Button = event.Type == Event::EVENT_MOUSE_BUTTON_RELEASED
511 ? QNXCodeToButton(lastButtonState)
512 : QNXCodeToButton(buttonState);
513 if (event.MouseButton.Button != MOUSEBUTTON_UNKNOWN) {
514 // int position[2];
515 screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_SOURCE_POSITION,
516 position);
517 event.MouseButton.X = position[0];
518 event.MouseButton.Y = position[1];
519 pushEvent(event);
520 }
521 break;
522 }
523 }
524
processKeyEvent(const screen_event_t & screen_event)525 void QNXWindow::processKeyEvent(const screen_event_t& screen_event) {
526 int modifiers = 0;
527 int flags = 0;
528 int cap = 0;
529
530 screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_MODIFIERS, &modifiers);
531 screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_FLAGS, &flags);
532 screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_CAP, &cap);
533
534 Event event;
535 event.Key.Code = QNXCodeToKey(cap);
536 event.Type = flags & KEY_DOWN || flags & KEY_REPEAT ? Event::EVENT_KEY_PRESSED
537 : Event::EVENT_KEY_RELEASED;
538 event.Key.Shift = modifiers & KEYMOD_SHIFT;
539 event.Key.Control = modifiers & KEYMOD_CTRL;
540 event.Key.Alt = modifiers & KEYMOD_ALT;
541 event.Key.System = 0;
542 pushEvent(event);
543 }
544
processPropertyChangedEvent(const screen_event_t & event)545 void QNXWindow::processPropertyChangedEvent(const screen_event_t& event) {
546 int property = 0;
547 screen_get_event_property_iv(event, SCREEN_PROPERTY_NAME, &property);
548 int type = 0;
549 screen_get_event_property_iv(event, SCREEN_PROPERTY_OBJECT_TYPE, &type);
550 if (type != SCREEN_OBJECT_TYPE_WINDOW) return;
551
552 if (property == SCREEN_PROPERTY_SIZE) {
553 screen_window_t screenWindow = 0;
554 if (screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&screenWindow))
555 return;
556 if (screenWindow != mWindow) return;
557
558 int size[2] = {0, 0};
559 if (screen_get_window_property_iv(screenWindow, SCREEN_PROPERTY_SIZE, size)) return;
560 Event event;
561 event.Type = Event::EVENT_RESIZED;
562 event.Size.Width = size[0];
563 event.Size.Height = size[1];
564 pushEvent(event);
565 } else if (property == SCREEN_PROPERTY_FOCUS) {
566 screen_window_t screenWindow = 0;
567 if (screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&screenWindow))
568 return;
569 if (screenWindow != mWindow) return;
570 int value;
571 if (screen_get_window_property_iv(screenWindow, property, &value)) return;
572 Event event;
573 event.Type = value ? Event::EVENT_GAINED_FOCUS : Event::EVENT_LOST_FOCUS;
574 }
575 }
576
processInputControlEvent(const screen_event_t & screen_event)577 void QNXWindow::processInputControlEvent(const screen_event_t& screen_event) {
578 int val;
579 if (screen_get_event_property_iv(screen_event, SCREEN_INPUT_CONTROL_POINTER_STOP, &val)) return;
580 if (!val) return;
581 screen_window_t screenWindow = 0;
582 if (screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_WINDOW, (void**)&screenWindow))
583 return;
584 if (screenWindow != mWindow) return;
585 Event event;
586 event.Type = Event::EVENT_MOUSE_LEFT;
587 pushEvent(event);
588 }
589
processCloseEvent(const screen_event_t & screen_event)590 void QNXWindow::processCloseEvent(const screen_event_t& screen_event) {
591 screen_window_t screenWindow = 0;
592 if (screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_WINDOW, (void**)&screenWindow))
593 return;
594 if (screenWindow != mWindow) return;
595 Event event;
596 event.Type = Event::EVENT_CLOSED;
597 pushEvent(event);
598 }
599