• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &param)) 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, &param)) 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