4 * The BlackBerry-specific windows message processing methods.
6 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7 * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8 * Copied for Platform code by Evan Felix <karcaw at gmail.com>
9 * Copyright (C) 2012 Sylvain Beucler
10 * Copyright (C) 2013 Vincent Simonetti
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
26 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #include <GL/freeglut.h>
31 #include "fg_internal.h"
32 #include "egl/fg_window_egl.h"
35 #define LOGI(...) ((void)slog2fa(NULL, 1337, SLOG2_INFO, __VA_ARGS__))
36 #define LOGW(...) ((void)slog2fa(NULL, 1337, SLOG2_WARNING, __VA_ARGS__))
37 #include <sys/keycodes.h>
38 #include <input/screen_helpers.h>
40 #include <bps/event.h>
41 #include <bps/screen.h>
42 #include <bps/navigator.h>
44 extern void fghOnReshapeNotify(SFG_Window *window, int width, int height, GLboolean forceNotify);
45 extern void fghOnPositionNotify(SFG_Window *window, int x, int y, GLboolean forceNotify);
46 extern void fgPlatformFullScreenToggle( SFG_Window *win );
47 extern void fgPlatformPositionWindow( SFG_Window *window, int x, int y );
48 extern void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height );
49 extern void fgPlatformPushWindow( SFG_Window *window );
50 extern void fgPlatformPopWindow( SFG_Window *window );
51 extern void fgPlatformHideWindow( SFG_Window *window );
52 extern void fgPlatformIconifyWindow( SFG_Window *window );
53 extern void fgPlatformShowWindow( SFG_Window *window );
55 static struct touchscreen touchscreen;
57 unsigned int key_special(int qnxKeycode)
85 return GLUT_KEY_PAGE_UP;
87 return GLUT_KEY_PAGE_DOWN;
93 return GLUT_KEY_INSERT;
98 //case KEYCODE_KP_DOWN:
101 //case KEYCODE_KP_LEFT:
102 return GLUT_KEY_LEFT;
104 //case KEYCODE_KP_RIGHT:
105 return GLUT_KEY_RIGHT;
106 case KEYCODE_NUM_LOCK:
107 return GLUT_KEY_NUM_LOCK;
108 case KEYCODE_LEFT_ALT:
109 return GLUT_KEY_ALT_L;
110 case KEYCODE_RIGHT_ALT:
111 return GLUT_KEY_ALT_R;
112 case KEYCODE_LEFT_SHIFT:
113 return GLUT_KEY_SHIFT_L;
114 case KEYCODE_RIGHT_SHIFT:
115 return GLUT_KEY_SHIFT_R;
116 case KEYCODE_LEFT_CTRL:
117 return GLUT_KEY_CTRL_L;
118 case KEYCODE_RIGHT_CTRL:
119 return GLUT_KEY_CTRL_R;
124 unsigned char key_ascii(int qnxKeycode)
126 if (qnxKeycode >= KEYCODE_PC_KEYS && qnxKeycode <= UNICODE_PRIVATE_USE_AREA_LAST) {
127 switch (qnxKeycode) {
128 case KEYCODE_BACKSPACE:
132 case KEYCODE_KP_ENTER:
142 uint64_t fgPlatformSystemTime ( void )
145 clock_gettime(CLOCK_REALTIME, &now);
146 return (1000 * now.tv_sec) + (now.tv_nsec / 1000000);
150 * Does the magic required to relinquish the CPU until something interesting
153 void fgPlatformSleepForEvents( uint64_t msec )
155 //XXX: Is this right? Is there a more direct way to access the context?
156 if(bps_get_event(&fgStructure.CurrentWindow->Window.pContext.event, (int)msec) != BPS_SUCCESS) {
157 LOGW("BPS couldn't get event");
161 void handle_left_mouse(int x, int y, int height, int eventType, SFG_Window* window)
163 bool handled = false;
164 /* Virtual arrows PAD */
165 /* Don't interfere with existing mouse move event */
166 if (!touchscreen.in_mmotion) {
167 struct vpad_state prev_vpad = touchscreen.vpad;
168 touchscreen.vpad.left = touchscreen.vpad.right = touchscreen.vpad.up = touchscreen.vpad.down = false;
170 if (eventType == SCREEN_EVENT_MTOUCH_TOUCH || eventType == SCREEN_EVENT_MTOUCH_MOVE) {
171 if ((x > 0 && x < 100) && (y > (height - 100) && y < height))
173 touchscreen.vpad.left = true;
175 if ((x > 200 && x < 300) && (y > (height - 100) && y < height))
177 touchscreen.vpad.right = true;
179 if ((x > 100 && x < 200) && (y > (height - 100) && y < height))
181 touchscreen.vpad.down = true;
183 if ((x > 100 && x < 200) && (y > (height - 200) && y < (height - 100)))
185 touchscreen.vpad.up = true;
189 if (eventType == SCREEN_EVENT_MTOUCH_TOUCH &&
190 (touchscreen.vpad.left || touchscreen.vpad.right || touchscreen.vpad.down || touchscreen.vpad.up)) {
191 touchscreen.vpad.on = true;
193 if (eventType == SCREEN_EVENT_MTOUCH_RELEASE) {
194 touchscreen.vpad.on = false;
197 if (prev_vpad.left != touchscreen.vpad.left
198 || prev_vpad.right != touchscreen.vpad.right
199 || prev_vpad.up != touchscreen.vpad.up
200 || prev_vpad.down != touchscreen.vpad.down
201 || prev_vpad.on != touchscreen.vpad.on) {
202 if (FETCH_WCB(*window, Special)) {
203 if (prev_vpad.left == false && touchscreen.vpad.left == true) {
204 INVOKE_WCB(*window, Special, (GLUT_KEY_LEFT, x, y));
206 else if (prev_vpad.right == false && touchscreen.vpad.right == true) {
207 INVOKE_WCB(*window, Special, (GLUT_KEY_RIGHT, x, y));
209 else if (prev_vpad.up == false && touchscreen.vpad.up == true) {
210 INVOKE_WCB(*window, Special, (GLUT_KEY_UP, x, y));
212 else if (prev_vpad.down == false && touchscreen.vpad.down == true) {
213 INVOKE_WCB(*window, Special, (GLUT_KEY_DOWN, x, y));
216 if (FETCH_WCB(*window, SpecialUp)) {
217 if (prev_vpad.left == true && touchscreen.vpad.left == false) {
218 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_LEFT, x, y));
220 if (prev_vpad.right == true && touchscreen.vpad.right == false) {
221 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_RIGHT, x, y));
223 if (prev_vpad.up == true && touchscreen.vpad.up == false) {
224 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_UP, x, y));
226 if (prev_vpad.down == true && touchscreen.vpad.down == false) {
227 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_DOWN, x, y));
234 /* Normal mouse events */
235 if (!handled && !touchscreen.vpad.on) {
236 window->State.MouseX = x;
237 window->State.MouseY = y;
239 if(eventType == SCREEN_EVENT_MTOUCH_MOVE) {
240 INVOKE_WCB(*window, Motion, (x, y));
241 } else if(FETCH_WCB(*window, Mouse)) {
242 touchscreen.in_mmotion = eventType == SCREEN_EVENT_MTOUCH_TOUCH;
243 int glutTouchType = eventType == SCREEN_EVENT_MTOUCH_TOUCH ? GLUT_DOWN : GLUT_UP;
244 INVOKE_WCB(*window, Mouse, (GLUT_LEFT_BUTTON, glutTouchType, x, y));
249 void fgPlatformProcessSingleEvent ( void )
252 bps_event_t** eventPtr = &fgStructure.CurrentWindow->Window.pContext.event; //XXX Is there a more direct way to access the context?
256 if(*eventPtr != NULL) {
257 SFG_Window* window = fgStructure.CurrentWindow;
258 if (window != NULL && window->Window.Handle != NULL) {
260 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
261 fghOnReshapeNotify(window,size[0],size[1],GL_FALSE);
265 domain = bps_event_get_domain(event);
266 if (domain == screen_get_domain()) {
268 screen_event_t screenEvent = screen_event_get_event(event);
269 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_TYPE, &eventType);
272 //Mostly from fg_main_android
273 case SCREEN_EVENT_MTOUCH_TOUCH:
274 case SCREEN_EVENT_MTOUCH_RELEASE:
275 case SCREEN_EVENT_MTOUCH_MOVE:
277 mtouch_event_t touchEvent;
278 screen_get_mtouch_event(screenEvent, &touchEvent, 0);
279 if(touchEvent.contact_id == 0) { //XXX Only support one contact for now
281 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
282 handle_left_mouse(touchEvent.x, touchEvent.y, size[1], eventType, window);
287 case SCREEN_EVENT_POINTER:
289 //Based off/part taken from GamePlay3d PlatformBlackBerry
290 static int mouse_pressed = 0;
293 // A move event will be fired unless a button state changed.
295 bool left_move = false;
296 // This is a mouse move event, it is applicable to a device with a usb mouse or simulator.
297 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_BUTTONS, &buttons);
298 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_SOURCE_POSITION, position);
300 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
302 // Handle left mouse. Interpret as touch if the left mouse event is not consumed.
303 if (buttons & SCREEN_LEFT_MOUSE_BUTTON) {
304 if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON) {
308 mouse_pressed |= SCREEN_LEFT_MOUSE_BUTTON;
309 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_TOUCH, window);
311 } else if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON) {
313 mouse_pressed &= ~SCREEN_LEFT_MOUSE_BUTTON;
314 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_RELEASE, window);
317 // Handle right mouse.
318 if (buttons & SCREEN_RIGHT_MOUSE_BUTTON) {
319 if ((mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) == 0) {
321 mouse_pressed |= SCREEN_RIGHT_MOUSE_BUTTON;
322 INVOKE_WCB(*window, Mouse, (GLUT_RIGHT_BUTTON, GLUT_DOWN, position[0], position[1]));
324 } else if (mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) {
326 mouse_pressed &= ~SCREEN_RIGHT_MOUSE_BUTTON;
327 INVOKE_WCB(*window, Mouse, (GLUT_RIGHT_BUTTON, GLUT_UP, position[0], position[1]));
330 // Handle middle mouse.
331 if (buttons & SCREEN_MIDDLE_MOUSE_BUTTON) {
332 if ((mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) == 0) {
334 mouse_pressed |= SCREEN_MIDDLE_MOUSE_BUTTON;
335 INVOKE_WCB(*window, Mouse, (GLUT_MIDDLE_BUTTON, GLUT_DOWN, position[0], position[1]));
337 } else if (mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) {
339 mouse_pressed &= ~SCREEN_MIDDLE_MOUSE_BUTTON;
340 INVOKE_WCB(*window, Mouse, (GLUT_MIDDLE_BUTTON, GLUT_UP, position[0], position[1]));
343 // Fire a move event if none of the buttons changed.
344 if (left_move || move) {
345 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_MOVE, window);
350 //Based off fg_main_android
351 case SCREEN_EVENT_KEYBOARD:
355 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_FLAGS, &flags);
356 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_SYM, &value);
357 LOGI("fgPlatformProcessSingleEvent: SCREEN_EVENT_KEYBOARD. Flags: 0x%X, Sym: 0x%X", SLOG2_FA_SIGNED(flags), SLOG2_FA_SIGNED(value), SLOG2_FA_END);
358 // Suppress key repeats if desired
359 if (!fgStructure.CurrentWindow->State.IgnoreKeyRepeat && (flags & KEY_REPEAT) == 0) {
360 unsigned int keypress = 0;
361 unsigned char ascii = 0;
362 if ((keypress = key_special(value))) {
363 if(flags & KEY_DOWN) {
364 INVOKE_WCB(*window, Special, (keypress, window->State.MouseX, window->State.MouseY));
366 INVOKE_WCB(*window, SpecialUp, (keypress, window->State.MouseX, window->State.MouseY));
368 } else if((flags & KEY_SYM_VALID) && (ascii = key_ascii(value))) {
369 if(flags & KEY_DOWN) {
370 INVOKE_WCB(*window, Keyboard, (ascii, window->State.MouseX, window->State.MouseY));
372 INVOKE_WCB(*window, KeyboardUp, (ascii, window->State.MouseX, window->State.MouseY));
379 } else if (domain == navigator_get_domain()) {
380 switch (bps_event_get_code(event)) {
382 case NAVIGATOR_WINDOW_STATE:
384 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE", SLOG2_FA_END);
385 navigator_window_state_t state = navigator_event_get_window_state(event);
388 case NAVIGATOR_WINDOW_FULLSCREEN:
389 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_FULLSCREEN", SLOG2_FA_END);
390 INVOKE_WCB(*window, AppStatus, (GLUT_APPSTATUS_RESUME));
392 case NAVIGATOR_WINDOW_THUMBNAIL:
393 case NAVIGATOR_WINDOW_INVISIBLE:
394 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_THUMBNAIL/NAVIGATOR_WINDOW_INVISIBLE", SLOG2_FA_END);
395 INVOKE_WCB(*window, AppStatus, (GLUT_APPSTATUS_PAUSE));
402 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_EXIT", SLOG2_FA_END);
403 /* User closed the application for good, let's kill the window */
405 SFG_Window* window = fgStructure.CurrentWindow;
406 if (window != NULL) {
407 fgDestroyWindow(window);
409 LOGI("NAVIGATOR_EXIT: No current window", SLOG2_FA_END);
416 } while(bps_get_event(eventPtr, 1) == BPS_SUCCESS && *eventPtr != NULL);
418 /* Reset event to reduce chances of triggering something */
422 void fgPlatformMainLoopPreliminaryWork ( void )
424 LOGI("fgPlatformMainLoopPreliminaryWork\n", SLOG2_FA_END);
428 /* deal with work list items */
429 void fgPlatformInitWork(SFG_Window* window)
431 /* notify windowStatus/visibility */
432 INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_RETAINED ) );
434 /* Position callback, always at 0,0 */
435 fghOnPositionNotify(window, 0, 0, GL_TRUE);
437 /* Size gets notified on window creation with size detection in mainloop above
438 * XXX CHECK: does this messages happen too early like on windows,
439 * so client code cannot have registered a callback yet and the message
440 * is thus never received by client?
444 void fgPlatformPosResZordWork(SFG_Window* window, unsigned int workMask)
446 if (workMask & GLUT_FULL_SCREEN_WORK)
447 fgPlatformFullScreenToggle( window );
448 if (workMask & GLUT_POSITION_WORK)
449 fgPlatformPositionWindow( window, window->State.DesiredXpos, window->State.DesiredYpos );
450 if (workMask & GLUT_SIZE_WORK)
451 fgPlatformReshapeWindow ( window, window->State.DesiredWidth, window->State.DesiredHeight );
452 if (workMask & GLUT_ZORDER_WORK)
454 if (window->State.DesiredZOrder < 0)
455 fgPlatformPushWindow( window );
457 fgPlatformPopWindow( window );
461 void fgPlatformVisibilityWork(SFG_Window* window)
463 /* Visibility status of window should get updated in the window message handlers
464 * For now, none of these functions called below do anything, so don't worry
467 SFG_Window *win = window;
468 switch (window->State.DesiredVisibility)
470 case DesireHiddenState:
471 fgPlatformHideWindow( window );
473 case DesireIconicState:
474 /* Call on top-level window */
477 fgPlatformIconifyWindow( win );
479 case DesireNormalState:
480 fgPlatformShowWindow( window );