You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2265 lines
71 KiB
2265 lines
71 KiB
#include "ofAppEGLWindow.h"
|
|
|
|
#include "ofGraphics.h" // used in runAppViaInfiniteLoop()
|
|
#include "ofAppRunner.h"
|
|
#include "ofUtils.h"
|
|
#include "ofFileUtils.h"
|
|
#include "ofGLProgrammableRenderer.h"
|
|
#include "ofGLRenderer.h"
|
|
#include <assert.h>
|
|
|
|
using namespace std;
|
|
|
|
// native events
|
|
struct udev* udev;
|
|
struct udev_device* dev;
|
|
struct udev_monitor* mon;
|
|
static int udev_fd = -1;
|
|
|
|
static int keyboard_fd = -1; // defaults to 0 ie console
|
|
|
|
// minimal map
|
|
const int lowercase_map[] = {
|
|
0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
|
|
'-', '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
|
|
'o', 'p', '[', ']', '\n', 0, 'a', 's', 'd', 'f', 'g', 'h',
|
|
'j', 'k', 'l', ';', '\'', '\n', 0, '\\', 'z', 'x', 'c', 'v',
|
|
'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\r'
|
|
|
|
};
|
|
|
|
// minimal keyboard map
|
|
const int uppercase_map[] = {
|
|
0, 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
|
|
'_', '+', '\b', '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
|
|
'O', 'P', '{', '}', '\n', 0, 'A', 'S', 'D', 'F', 'G', 'H',
|
|
'J', 'K', 'L', ':', '"', '\n', 0, '\\', 'Z', 'X', 'C', 'V',
|
|
'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\r'
|
|
};
|
|
|
|
// keep track of a few things ...
|
|
typedef struct {
|
|
bool shiftPressed;
|
|
bool capsLocked;
|
|
} KeyboardState;
|
|
|
|
static KeyboardState kb;
|
|
|
|
static struct termios tc;
|
|
static struct termios ots;
|
|
|
|
typedef struct {
|
|
int mouseButtonState;
|
|
} MouseState;
|
|
|
|
// TODO, make this match the upcoming additions to ofWindow
|
|
#define MOUSE_BUTTON_LEFT_MASK 1
|
|
#define MOUSE_BUTTON_MIDDLE_MASK 1 << 1
|
|
#define MOUSE_BUTTON_RIGHT_MASK 2 << 1
|
|
|
|
static MouseState mb;
|
|
ofAppEGLWindow* ofAppEGLWindow::instance = NULL;
|
|
|
|
static int string_ends_with(const char *str, const char *suffix) {
|
|
if (!str || !suffix)
|
|
return 0;
|
|
size_t lenstr = strlen(str);
|
|
size_t lensuffix = strlen(suffix);
|
|
if (lensuffix > lenstr)
|
|
return 0;
|
|
return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
|
|
}
|
|
|
|
static int string_begins_with(const char *str, const char *prefix) {
|
|
if (!str || !prefix)
|
|
return 0;
|
|
size_t lenstr = strlen(str);
|
|
size_t lenprefix = strlen(prefix);
|
|
if (lenprefix > lenstr)
|
|
return 0;
|
|
return strncmp(str, prefix, lenprefix) == 0;
|
|
}
|
|
|
|
static int dummy_sort(const struct dirent **a,const struct dirent **b) {
|
|
return 1; // dummy sort
|
|
}
|
|
|
|
static int filter_kbd(const struct dirent *d) {
|
|
if(d->d_type != DT_DIR && string_ends_with(d->d_name,"event-kbd")) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int filter_mouse(const struct dirent *d) {
|
|
if(d->d_type != DT_DIR && string_ends_with(d->d_name,"event-mouse")) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int filter_event(const struct dirent *d) {
|
|
if(d->d_type != DT_DIR && string_begins_with(d->d_name,"event")) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// native
|
|
#define MOUSE_CURSOR_RUN_LENGTH_DECODE(image_buf, rle_data, size, bpp) do \
|
|
{ unsigned int __bpp; unsigned char *__ip; const unsigned char *__il, *__rd; \
|
|
__bpp = (bpp); __ip = (image_buf); __il = __ip + (size) * __bpp; \
|
|
__rd = (rle_data); \
|
|
while (__ip < __il) { unsigned int __l = *(__rd++); \
|
|
if (__l & 128) { __l = __l - 128; \
|
|
do { memcpy (__ip, __rd, 4); __ip += 4; } while (--__l); __rd += 4; \
|
|
} else { __l *= 4; memcpy (__ip, __rd, __l); \
|
|
__ip += __l; __rd += __l; } } \
|
|
} while (0)
|
|
static const struct {
|
|
unsigned int width;
|
|
unsigned int height;
|
|
unsigned int bpp; /* 2:RGB16, 3:RGB, 4:RGBA */
|
|
unsigned char rle_pixel_data[382 + 1];
|
|
} mouse_cursor_data = {
|
|
12, 19, 4,
|
|
"\1\0\0\0\377\213\377\377\377\0\202\0\0\0\377\212\377\377\377\0\3\0\0\0\377"
|
|
"\377\377\377\377\0\0\0\377\211\377\377\377\0\1\0\0\0\377\202\377\377\377"
|
|
"\377\1\0\0\0\377\210\377\377\377\0\1\0\0\0\377\203\377\377\377\377\1\0\0"
|
|
"\0\377\207\377\377\377\0\1\0\0\0\377\204\377\377\377\377\1\0\0\0\377\206"
|
|
"\377\377\377\0\1\0\0\0\377\205\377\377\377\377\1\0\0\0\377\205\377\377\377"
|
|
"\0\1\0\0\0\377\206\377\377\377\377\1\0\0\0\377\204\377\377\377\0\1\0\0\0"
|
|
"\377\207\377\377\377\377\1\0\0\0\377\203\377\377\377\0\1\0\0\0\377\210\377"
|
|
"\377\377\377\1\0\0\0\377\202\377\377\377\0\1\0\0\0\377\211\377\377\377\377"
|
|
"\3\0\0\0\377\377\377\377\0\0\0\0\377\212\377\377\377\377\202\0\0\0\377\206"
|
|
"\377\377\377\377\206\0\0\0\377\203\377\377\377\377\1\0\0\0\377\202\377\377"
|
|
"\377\377\1\0\0\0\377\204\377\377\377\0\1\0\0\0\377\202\377\377\377\377\3"
|
|
"\0\0\0\377\377\377\377\0\0\0\0\377\202\377\377\377\377\1\0\0\0\377\203\377"
|
|
"\377\377\0\3\0\0\0\377\377\377\377\377\0\0\0\377\202\377\377\377\0\1\0\0"
|
|
"\0\377\202\377\377\377\377\1\0\0\0\377\203\377\377\377\0\202\0\0\0\377\204"
|
|
"\377\377\377\0\1\0\0\0\377\202\377\377\377\377\1\0\0\0\377\210\377\377\377"
|
|
"\0\1\0\0\0\377\202\377\377\377\377\1\0\0\0\377\211\377\377\377\0\202\0\0"
|
|
"\0\377\203\377\377\377\0",
|
|
};
|
|
|
|
// from http://cantuna.googlecode.com/svn-history/r16/trunk/src/screen.cpp
|
|
#define CASE_STR(x,y) case x: str = y; break
|
|
|
|
static const char* eglErrorString(EGLint err) {
|
|
string str;
|
|
switch (err) {
|
|
CASE_STR(EGL_SUCCESS, "no error");
|
|
CASE_STR(EGL_NOT_INITIALIZED, "EGL not, or could not be, initialized");
|
|
CASE_STR(EGL_BAD_ACCESS, "access violation");
|
|
CASE_STR(EGL_BAD_ALLOC, "could not allocate resources");
|
|
CASE_STR(EGL_BAD_ATTRIBUTE, "invalid attribute");
|
|
CASE_STR(EGL_BAD_CONTEXT, "invalid context specified");
|
|
CASE_STR(EGL_BAD_CONFIG, "invald frame buffer configuration specified");
|
|
CASE_STR(EGL_BAD_CURRENT_SURFACE, "current window, pbuffer or pixmap surface is no longer valid");
|
|
CASE_STR(EGL_BAD_DISPLAY, "invalid display specified");
|
|
CASE_STR(EGL_BAD_SURFACE, "invalid surface specified");
|
|
CASE_STR(EGL_BAD_MATCH, "bad argument match");
|
|
CASE_STR(EGL_BAD_PARAMETER, "invalid paramater");
|
|
CASE_STR(EGL_BAD_NATIVE_PIXMAP, "invalid NativePixmap");
|
|
CASE_STR(EGL_BAD_NATIVE_WINDOW, "invalid NativeWindow");
|
|
CASE_STR(EGL_CONTEXT_LOST, "APM event caused context loss");
|
|
default: str = "unknown error " + err; break;
|
|
}
|
|
return str.c_str();
|
|
}
|
|
|
|
|
|
// X11 events
|
|
#include <X11/XKBlib.h>
|
|
|
|
|
|
#ifdef TARGET_RASPBERRY_PI
|
|
// TODO: remove these when they enter system headers
|
|
// From : https://github.com/raspberrypi/userland/blob/master/interface/vmcs_host/vc_vchi_dispmanx.h
|
|
#ifndef ELEMENT_CHANGE_LAYER
|
|
#define ELEMENT_CHANGE_LAYER (1<<0)
|
|
#endif
|
|
#ifndef ELEMENT_CHANGE_OPACITY
|
|
#define ELEMENT_CHANGE_OPACITY (1<<1)
|
|
#endif
|
|
#ifndef ELEMENT_CHANGE_DEST_RECT
|
|
#define ELEMENT_CHANGE_DEST_RECT (1<<2)
|
|
#endif
|
|
#ifndef ELEMENT_CHANGE_SRC_RECT
|
|
#define ELEMENT_CHANGE_SRC_RECT (1<<3)
|
|
#endif
|
|
#ifndef ELEMENT_CHANGE_MASK_RESOURCE
|
|
#define ELEMENT_CHANGE_MASK_RESOURCE (1<<4)
|
|
#endif
|
|
#ifndef ELEMENT_CHANGE_TRANSFORM
|
|
#define ELEMENT_CHANGE_TRANSFORM (1<<5)
|
|
#endif
|
|
#endif
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
ofAppEGLWindow::Settings::Settings()
|
|
:ofGLESWindowSettings(){
|
|
eglWindowPreference = OF_APP_WINDOW_AUTO;
|
|
eglWindowOpacity = 255;
|
|
|
|
// these are usually set as default, but set them here just to be sure
|
|
frameBufferAttributes[EGL_RED_SIZE] = 8; // 8 bits for red
|
|
frameBufferAttributes[EGL_GREEN_SIZE] = 8; // 8 bits for green
|
|
frameBufferAttributes[EGL_BLUE_SIZE] = 8; // 8 bits for blue
|
|
frameBufferAttributes[EGL_ALPHA_SIZE] = 8; // 8 bits for alpha
|
|
frameBufferAttributes[EGL_LUMINANCE_SIZE] = EGL_DONT_CARE; // 8 bits for alpha
|
|
frameBufferAttributes[EGL_DEPTH_SIZE] = 24; // 24 bits for depth
|
|
frameBufferAttributes[EGL_STENCIL_SIZE] = 8; // 8 bits for stencil
|
|
frameBufferAttributes[EGL_SAMPLES] = 1;
|
|
|
|
initialClearColor = ofColor(0.15 * 255, 0.15 * 255, 0.15 * 255, 255);
|
|
|
|
screenNum = 0; /* 0 = LCD on the raspberry pi */
|
|
layer = 0;
|
|
}
|
|
|
|
ofAppEGLWindow::Settings::Settings(const ofGLESWindowSettings & settings)
|
|
:ofGLESWindowSettings(settings){
|
|
eglWindowPreference = OF_APP_WINDOW_AUTO;
|
|
eglWindowOpacity = 255;
|
|
|
|
// these are usually set as default, but set them here just to be sure
|
|
frameBufferAttributes[EGL_RED_SIZE] = 8; // 8 bits for red
|
|
frameBufferAttributes[EGL_GREEN_SIZE] = 8; // 8 bits for green
|
|
frameBufferAttributes[EGL_BLUE_SIZE] = 8; // 8 bits for blue
|
|
frameBufferAttributes[EGL_ALPHA_SIZE] = 8; // 8 bits for alpha
|
|
frameBufferAttributes[EGL_LUMINANCE_SIZE] = EGL_DONT_CARE; // 8 bits for alpha
|
|
frameBufferAttributes[EGL_DEPTH_SIZE] = 24; // 24 bits for depth
|
|
frameBufferAttributes[EGL_STENCIL_SIZE] = 8; // 8 bits for stencil
|
|
frameBufferAttributes[EGL_SAMPLES] = 1;
|
|
|
|
initialClearColor = ofColor(0.15 * 255, 0.15 * 255, 0.15 * 255, 255);
|
|
|
|
screenNum = 0; /* 0 = LCD on the raspberry pi */
|
|
layer = 0;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
ofAppEGLWindow::ofAppEGLWindow() {
|
|
keyboardDetected = false;
|
|
mouseDetected = false;
|
|
threadTimeout = ofThread::INFINITE_JOIN_TIMEOUT;
|
|
bNewScreenMode = false;
|
|
buttonInUse = -1;
|
|
bEnableSetupScreen = false;
|
|
bShowCursor = true;
|
|
nFramesSinceWindowResized = 0;
|
|
mouseScaleX = 2.0f;
|
|
mouseScaleY = 2.0f;
|
|
isUsingX11 = false;
|
|
isWindowInited = false;
|
|
isSurfaceInited = false;
|
|
x11Display = NULL;
|
|
x11Screen = NULL;
|
|
x11ScreenNum = 0l;
|
|
glesVersion = 1;
|
|
|
|
if(instance!=NULL){
|
|
ofLogError("ofAppEGLWindow") << "trying to create more than one instance";
|
|
}
|
|
instance = this;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
ofAppEGLWindow::~ofAppEGLWindow() {
|
|
close();
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
EGLDisplay ofAppEGLWindow::getEglDisplay() const {
|
|
return eglDisplay;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
EGLSurface ofAppEGLWindow::getEglSurface() const {
|
|
return eglSurface;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
EGLContext ofAppEGLWindow::getEglContext() const {
|
|
return eglContext;
|
|
}
|
|
|
|
#ifndef TARGET_RASPBERRY_PI
|
|
//------------------------------------------------------------
|
|
Display* ofAppEGLWindow::getX11Display(){
|
|
return x11Display;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
Window ofAppEGLWindow::getX11Window(){
|
|
return x11Window;
|
|
}
|
|
#endif
|
|
//------------------------------------------------------------
|
|
EGLConfig ofAppEGLWindow::getEglConfig() const {
|
|
return eglConfig;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
EGLint ofAppEGLWindow::getEglVersionMajor () const {
|
|
return eglVersionMajor;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
EGLint ofAppEGLWindow::getEglVersionMinor() const {
|
|
return eglVersionMinor;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::initNative() {
|
|
#ifdef TARGET_RASPBERRY_PI
|
|
initRPiNative();
|
|
#endif
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::exitNative() {
|
|
#ifdef TARGET_RASPBERRY_PI
|
|
exitRPiNative();
|
|
#endif
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
EGLNativeWindowType ofAppEGLWindow::getNativeWindow() {
|
|
if(!isWindowInited) {
|
|
ofLogWarning("ofAppEGLWindow") << "getNativeDisplay(): window not initialized, returning NULL";
|
|
return NULL;
|
|
}
|
|
|
|
if(isUsingX11) {
|
|
return (EGLNativeWindowType)x11Window;
|
|
} else {
|
|
#ifdef TARGET_RASPBERRY_PI
|
|
return (EGLNativeWindowType)&dispman_native_window;
|
|
#else
|
|
ofLogNotice("ofAppEGLWindow") << "getNativeWindow(): no native window type for this system, perhaps try X11?";
|
|
return NULL;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
EGLNativeDisplayType ofAppEGLWindow::getNativeDisplay() {
|
|
if(!isWindowInited) {
|
|
ofLogWarning("ofAppEGLWindow") << "getNativeDisplay(): window not initialized, returning NULL";
|
|
return 0;
|
|
}
|
|
|
|
if(isUsingX11) {
|
|
return (EGLNativeDisplayType)x11Display;
|
|
} else {
|
|
#ifdef TARGET_RASPBERRY_PI
|
|
return (EGLNativeDisplayType)NULL;
|
|
#else
|
|
ofLogNotice("ofAppEGLWindow") << "getNativeDisplay(): no native window type for this system, perhaps try X11?";
|
|
return 0;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::setup(const ofGLESWindowSettings & settings){
|
|
const Settings * glSettings = dynamic_cast<const Settings*>(&settings);
|
|
if(glSettings){
|
|
setup(*glSettings);
|
|
}else{
|
|
setup(Settings(settings));
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::setup(const Settings & _settings) {
|
|
settings = _settings;
|
|
windowMode = OF_WINDOW;
|
|
bNewScreenMode = true;
|
|
nFramesSinceWindowResized = 0;
|
|
buttonInUse = 0;
|
|
bEnableSetupScreen = true;
|
|
eglDisplayString = "";
|
|
orientation = OF_ORIENTATION_DEFAULT;
|
|
|
|
//TODO: 2.0f is an arbitrary factor that makes mouse speed ok at 1024x768,
|
|
// to be totally correct we might need to take into account screen size
|
|
// and add acceleration
|
|
mouseScaleX = 2.0f;
|
|
mouseScaleY = 2.0f;
|
|
|
|
isUsingX11 = false;
|
|
isWindowInited = false;
|
|
isSurfaceInited = false;
|
|
|
|
eglDisplay = NULL;
|
|
eglSurface = NULL;
|
|
eglContext = NULL;
|
|
eglConfig = NULL;
|
|
eglVersionMajor = -1;
|
|
eglVersionMinor = -1;
|
|
glesVersion = 1;
|
|
|
|
// X11 check
|
|
// char * pDisplay;
|
|
// pDisplay = getenv ("DISPLAY");
|
|
// bool bIsX11Available = (pDisplay != NULL);
|
|
|
|
bool bIsX11Available = getenv("DISPLAY") != NULL;
|
|
|
|
if(settings.eglWindowPreference == OF_APP_WINDOW_AUTO) {
|
|
if(bIsX11Available) {
|
|
isUsingX11 = true;
|
|
} else {
|
|
isUsingX11 = false;
|
|
}
|
|
} else if(settings.eglWindowPreference == OF_APP_WINDOW_NATIVE) {
|
|
isUsingX11 = false;
|
|
} else if(settings.eglWindowPreference == OF_APP_WINDOW_X11) {
|
|
isUsingX11 = true;
|
|
if(!bIsX11Available) {
|
|
isUsingX11 = false;
|
|
ofLogError("ofAppEGLWindow") << "init(): X11 window requested, but X11 is not available";
|
|
}
|
|
}
|
|
|
|
////////////////
|
|
// TODO remove the following ifdef once x11 is accelerated on RPI
|
|
#ifdef TARGET_RASPBERRY_PI
|
|
if(isUsingX11) {
|
|
isUsingX11 = false;
|
|
ofLogWarning("ofAppEGLWindow") << "init(): X11 not availble on RPI yet, using a native window instead";
|
|
}
|
|
#endif
|
|
////////////////
|
|
|
|
initNative();
|
|
|
|
glesVersion = settings.glesVersion;
|
|
// we set this here, and if we need to make a fullscreen
|
|
// app, we do it during the first loop.
|
|
windowMode = settings.windowMode;
|
|
bShowCursor = true;
|
|
|
|
nonFullscreenWindowRect.set(0,0,settings.width,settings.height);
|
|
nonFullscreenWindowRect.standardize();
|
|
|
|
ofRectangle startRect = nonFullscreenWindowRect;
|
|
bNewScreenMode = false;
|
|
|
|
if(windowMode == OF_GAME_MODE) {
|
|
ofLogWarning("ofAppEGLWindow") << "setupOpenGL(): OF_GAME_MODE not supported, using OF_WINDOW";
|
|
startRect = nonFullscreenWindowRect;
|
|
} else if(windowMode == OF_FULLSCREEN) {
|
|
startRect = getScreenRect();
|
|
}
|
|
|
|
isWindowInited = createWindow(startRect);
|
|
isSurfaceInited = createSurface();
|
|
|
|
if(!isWindowInited) {
|
|
ofLogError("ofAppEGLWindow") << "setupOpenGL(): screen creation failed, window not inited";
|
|
}
|
|
|
|
setupPeripherals();
|
|
|
|
nFramesSinceWindowResized = 0;
|
|
|
|
if(settings.glesVersion>1){
|
|
currentRenderer = make_shared<ofGLProgrammableRenderer>(this);
|
|
}else{
|
|
currentRenderer = make_shared<ofGLRenderer>(this);
|
|
}
|
|
|
|
makeCurrent();
|
|
if(currentRenderer->getType()==ofGLProgrammableRenderer::TYPE){
|
|
static_cast<ofGLProgrammableRenderer*>(currentRenderer.get())->setup(settings.glesVersion,0);
|
|
}else{
|
|
static_cast<ofGLRenderer*>(currentRenderer.get())->setup();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::setupPeripherals() {
|
|
if(!isUsingX11) {
|
|
// roll our own cursor!
|
|
mouseCursor.allocate(mouse_cursor_data.width,mouse_cursor_data.height,OF_IMAGE_COLOR_ALPHA);
|
|
MOUSE_CURSOR_RUN_LENGTH_DECODE(mouseCursor.getPixels().getData(),mouse_cursor_data.rle_pixel_data,mouse_cursor_data.width*mouse_cursor_data.height,mouse_cursor_data.bpp);
|
|
mouseCursor.update();
|
|
ofLogNotice("ofAppEGLWindow") << "setupPeripherals(): peripheral setup complete";
|
|
setupNativeEvents();
|
|
ofLogNotice("ofAppEGLWindow") << "setupPeripherals(): native event setup complete";
|
|
|
|
} else {
|
|
ofLogError("ofAppEGLWindow") << "setupPeripherals(): peripherals not supported on X11";
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
bool ofAppEGLWindow::createSurface() {
|
|
|
|
EGLNativeWindowType nativeWindow = getNativeWindow();
|
|
EGLNativeDisplayType display = getNativeDisplay();
|
|
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): setting up EGL Display";
|
|
// get an EGL eglDisplay connection
|
|
|
|
isSurfaceInited = false;
|
|
|
|
EGLint result;
|
|
|
|
if(display==0){
|
|
eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
|
}else{
|
|
eglDisplay = eglGetDisplay(display);
|
|
}
|
|
|
|
if(eglDisplay == EGL_NO_DISPLAY) {
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): eglGetDisplay returned: " << eglDisplay;
|
|
return false;
|
|
}else{
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL Display correctly set " << eglDisplay;
|
|
}
|
|
|
|
// initialize the EGL eglDisplay connection
|
|
result = eglInitialize(eglDisplay,
|
|
&eglVersionMajor,
|
|
&eglVersionMinor);
|
|
|
|
if(result == EGL_BAD_DISPLAY) {
|
|
// eglDisplay is not an EGL connection
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): eglInitialize returned EGL_BAD_DISPLAY";
|
|
return false;
|
|
} else if(result == EGL_NOT_INITIALIZED) {
|
|
// eglDisplay cannot be intitialized
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): eglInitialize returned EGL_NOT_INITIALIZED";
|
|
return false;
|
|
} else if(result == EGL_FALSE) {
|
|
// eglinitialize was not initialiezd
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): eglInitialize returned EGL_FALSE";
|
|
return false;
|
|
} else {
|
|
// result == EGL_TRUE
|
|
// success!
|
|
}
|
|
|
|
EGLint glesVersion;
|
|
int glesVersionForContext;
|
|
|
|
if(ofGetCurrentRenderer()) {
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): current renderer type: " << ofGetCurrentRenderer()->getType();
|
|
} else {
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): no current renderer selected";
|
|
}
|
|
|
|
if(this->glesVersion==2){
|
|
glesVersion = EGL_OPENGL_ES2_BIT;
|
|
glesVersionForContext = 2;
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): GLES2 renderer detected";
|
|
}else{
|
|
glesVersion = EGL_OPENGL_ES_BIT;
|
|
glesVersionForContext = 1;
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): default renderer detected";
|
|
}
|
|
|
|
ofEGLAttributeListIterator iter, iterEnd;
|
|
int i;
|
|
|
|
// each attribute has 2 values, and we need one extra for the EGL_NONE terminator
|
|
EGLint attribute_list_framebuffer_config[settings.frameBufferAttributes.size() * 2 + 3];
|
|
|
|
iter = settings.frameBufferAttributes.begin();
|
|
iterEnd = settings.frameBufferAttributes.end();
|
|
i = 0;
|
|
for(; iter != iterEnd; iter++) {
|
|
attribute_list_framebuffer_config[i++] = iter->first;
|
|
attribute_list_framebuffer_config[i++] = iter->second;
|
|
}
|
|
attribute_list_framebuffer_config[i++] = EGL_RENDERABLE_TYPE;
|
|
attribute_list_framebuffer_config[i++] = glesVersion; //openGL ES version
|
|
attribute_list_framebuffer_config[i] = EGL_NONE; // add the terminator
|
|
|
|
EGLint num_configs;
|
|
|
|
// get an appropriate EGL frame buffer configuration
|
|
// http://www.khronos.org/registry/egl/sdk/docs/man/xhtml/eglChooseConfig.html
|
|
result = eglChooseConfig(eglDisplay,
|
|
attribute_list_framebuffer_config,
|
|
&eglConfig,
|
|
1, // we only want the first one. if we want more,
|
|
// we need to pass in an array.
|
|
// we are optimistic and don't give it more chances
|
|
// to find a good configuration
|
|
&num_configs);
|
|
|
|
if(result == EGL_FALSE) {
|
|
EGLint error = eglGetError();
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): error finding valid configuration based on settings: " << eglErrorString(error);
|
|
return false;
|
|
}
|
|
|
|
if(num_configs <= 0 || eglConfig == NULL) {
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): no matching configs were found, num_configs: " << num_configs;
|
|
return false;
|
|
}
|
|
|
|
|
|
// each attribute has 2 values, and we need one extra for the EGL_NONE terminator
|
|
EGLint attribute_list_window_surface[settings.windowSurfaceAttributes.size() * 2 + 1];
|
|
|
|
iter = settings.windowSurfaceAttributes.begin();
|
|
iterEnd = settings.windowSurfaceAttributes.end();
|
|
|
|
i = 0;
|
|
for(; iter != iterEnd; iter++) {
|
|
attribute_list_window_surface[i++] = iter->first;
|
|
attribute_list_window_surface[i++] = iter->second;
|
|
}
|
|
attribute_list_window_surface[i] = EGL_NONE; // add the terminator
|
|
|
|
// create a surface
|
|
eglSurface = eglCreateWindowSurface( eglDisplay, // our display handle
|
|
eglConfig, // our first config
|
|
nativeWindow, // our native window
|
|
attribute_list_window_surface); // surface attribute list
|
|
|
|
if(eglSurface == EGL_NO_SURFACE) {
|
|
EGLint error = eglGetError();
|
|
switch(error) {
|
|
case EGL_BAD_MATCH:
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: EGL_BAD_MATCH " << eglErrorString(error);
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): check window and EGLConfig attributes to determine compatibility, ";
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): or verify that the EGLConfig supports rendering to a window";
|
|
break;
|
|
case EGL_BAD_CONFIG:
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: EGL_BAD_CONFIG " << eglErrorString(error);
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): verify that provided EGLConfig is valid";
|
|
break;
|
|
case EGL_BAD_NATIVE_WINDOW:
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: EGL_BAD_NATIVE_WINDOW " << eglErrorString(error);
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): verify that provided EGLNativeWindow is valid";
|
|
break;
|
|
case EGL_BAD_ALLOC:
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: EGL_BAD_ALLOC " << eglErrorString(error);
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): not enough resources available";
|
|
break;
|
|
default:
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: << " << error << eglErrorString(error);
|
|
}
|
|
|
|
return false;
|
|
}else{
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): surface created correctly";
|
|
}
|
|
|
|
// get an appropriate EGL frame buffer configuration
|
|
result = eglBindAPI(EGL_OPENGL_ES_API);
|
|
|
|
if(result == EGL_FALSE) {
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): error binding API: " << eglErrorString(eglGetError());
|
|
return false;
|
|
}else{
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): API bound correctly";
|
|
}
|
|
|
|
// create an EGL rendering eglContext
|
|
EGLint attribute_list_surface_context[] = {
|
|
EGL_CONTEXT_CLIENT_VERSION, glesVersionForContext,
|
|
EGL_NONE
|
|
};
|
|
|
|
eglContext = eglCreateContext(eglDisplay,
|
|
eglConfig,
|
|
EGL_NO_CONTEXT,
|
|
attribute_list_surface_context);
|
|
|
|
if(eglContext == EGL_NO_CONTEXT) {
|
|
EGLint error = eglGetError();
|
|
if(error == EGL_BAD_CONFIG) {
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): error creating context: EGL_BAD_CONFIG " << eglErrorString(error);
|
|
return false;
|
|
} else {
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): error creating context: " << error << " " << eglErrorString(error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// connect the eglContext to the eglSurface
|
|
result = eglMakeCurrent(eglDisplay,
|
|
eglSurface, // draw surface
|
|
eglSurface, // read surface
|
|
eglContext);
|
|
|
|
if(eglContext == EGL_FALSE) {
|
|
EGLint error = eglGetError();
|
|
ofLogError("ofAppEGLWindow") << "createSurface(): couldn't making current surface: " << eglErrorString(error);
|
|
return false;
|
|
}
|
|
|
|
// Set background color and clear buffers
|
|
glClearColor(settings.initialClearColor.r / 255.0f,
|
|
settings.initialClearColor.g / 255.0f,
|
|
settings.initialClearColor.b / 255.0f,
|
|
settings.initialClearColor.a / 255.0f);
|
|
glClear( GL_COLOR_BUFFER_BIT );
|
|
glClear( GL_DEPTH_BUFFER_BIT );
|
|
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): -----EGL-----";
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_VERSION_MAJOR = " << eglVersionMajor;
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_VERSION_MINOR = " << eglVersionMinor;
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_CLIENT_APIS = " << eglQueryString(eglDisplay, EGL_CLIENT_APIS);
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_VENDOR = " << eglQueryString(eglDisplay, EGL_VENDOR);
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_VERSION = " << eglQueryString(eglDisplay, EGL_VERSION);
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_EXTENSIONS = " << eglQueryString(eglDisplay, EGL_EXTENSIONS);
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): GL_RENDERER = " << glGetString(GL_RENDERER);
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): GL_VERSION = " << glGetString(GL_VERSION);
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): GL_VENDOR = " << glGetString(GL_VENDOR);
|
|
ofLogNotice("ofAppEGLWindow") << "createSurface(): -------------";
|
|
|
|
isSurfaceInited = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
bool ofAppEGLWindow::destroySurface() {
|
|
if(isSurfaceInited) {
|
|
ofLogNotice("ofAppEGLWindow") << "destroySurface(): destroying EGL surface";
|
|
eglSwapBuffers(eglDisplay, eglSurface);
|
|
eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
eglDestroySurface(eglDisplay, eglSurface);
|
|
eglDestroyContext(eglDisplay, eglContext);
|
|
eglTerminate(eglDisplay);
|
|
isSurfaceInited = false;
|
|
|
|
eglDisplay = NULL;
|
|
eglSurface = NULL;
|
|
eglContext = NULL;
|
|
eglConfig = NULL;
|
|
eglVersionMinor = -1;
|
|
eglVersionMinor = -1;
|
|
|
|
return true;
|
|
} else {
|
|
ofLogError("ofAppEGLWindow") << "destroySurface(): attempted to destroy uninitialized window";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
bool ofAppEGLWindow::destroyWindow() {
|
|
if(isWindowInited) {
|
|
if(isUsingX11) {
|
|
// TODO: double check
|
|
XDestroyWindow(x11Display,x11Window); // or XCloseWindow?
|
|
XFree(x11Screen);
|
|
} else {
|
|
#ifdef TARGET_RASPBERRY_PI
|
|
dispman_update = vc_dispmanx_update_start(0);
|
|
if (dispman_element != DISPMANX_NO_HANDLE) {
|
|
vc_dispmanx_element_remove(dispman_update, dispman_element);
|
|
dispman_element = DISPMANX_NO_HANDLE;
|
|
}
|
|
|
|
vc_dispmanx_update_submit_sync(dispman_update);
|
|
|
|
if (dispman_display != DISPMANX_NO_HANDLE) {
|
|
vc_dispmanx_display_close(dispman_display);
|
|
dispman_display = DISPMANX_NO_HANDLE;
|
|
}
|
|
#else
|
|
ofLogNotice("ofAppEGLWindow") << "destroyWindow(): no native window type for this system, perhaps try X11?";
|
|
#endif
|
|
}
|
|
|
|
} else {
|
|
ofLogNotice("ofAppEGLWindow") << "destroyWindow(): destroying (uninited) native window (not implemented yet)";
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void ofAppEGLWindow::close(){
|
|
if(!isUsingX11) {
|
|
destroyNativeEvents();
|
|
}
|
|
|
|
// we got a terminate ... so clean up.
|
|
destroySurface();
|
|
destroyWindow();
|
|
|
|
exitNative();
|
|
events().notifyExit();
|
|
events().disable();
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::makeCurrent(){
|
|
eglMakeCurrent(eglDisplay,
|
|
eglSurface, // draw surface
|
|
eglSurface, // read surface
|
|
eglContext);
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::swapBuffers(){
|
|
EGLBoolean success = eglSwapBuffers(eglDisplay, eglSurface);
|
|
if(!success) {
|
|
GLint error = eglGetError();
|
|
ofLogNotice("ofAppEGLWindow") << "display(): eglSwapBuffers failed: " << eglErrorString(error);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------
|
|
void ofAppEGLWindow::startRender() {
|
|
renderer()->startRender();
|
|
}
|
|
|
|
//--------------------------------------------
|
|
void ofAppEGLWindow::finishRender() {
|
|
renderer()->finishRender();
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::update() {
|
|
coreEvents.notifyUpdate();
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::draw() {
|
|
// take care of any requests for a new screen mode
|
|
if (windowMode != OF_GAME_MODE && bNewScreenMode){
|
|
if( windowMode == OF_FULLSCREEN){
|
|
setWindowRect(getScreenRect());
|
|
} else if( windowMode == OF_WINDOW ){
|
|
setWindowRect(nonFullscreenWindowRect);
|
|
}
|
|
bNewScreenMode = false;
|
|
}
|
|
|
|
currentRenderer->startRender();
|
|
if( bEnableSetupScreen ) currentRenderer->setupScreen();
|
|
|
|
coreEvents.notifyDraw();
|
|
|
|
if(!isUsingX11) {
|
|
if(bShowCursor){
|
|
GLboolean bIsDepthTestEnabled = GL_FALSE;
|
|
glGetBooleanv(GL_DEPTH_TEST, &bIsDepthTestEnabled);
|
|
|
|
if(bIsDepthTestEnabled == GL_TRUE) {
|
|
glDisable(GL_DEPTH_TEST);
|
|
}
|
|
|
|
bool isUsingNormalizedTexCoords = ofGetUsingNormalizedTexCoords();
|
|
if(isUsingNormalizedTexCoords) {
|
|
ofDisableNormalizedTexCoords();
|
|
}
|
|
|
|
currentRenderer->pushStyle();
|
|
currentRenderer->setBlendMode(OF_BLENDMODE_ADD);
|
|
currentRenderer->setColor(255);
|
|
mouseCursor.draw(ofGetMouseX(),ofGetMouseY());
|
|
|
|
currentRenderer->popStyle();
|
|
|
|
if(bIsDepthTestEnabled == GL_TRUE) {
|
|
glEnable(GL_DEPTH_TEST);
|
|
}
|
|
|
|
if(isUsingNormalizedTexCoords) {
|
|
ofEnableNormalizedTexCoords();
|
|
}
|
|
}
|
|
}
|
|
currentRenderer->finishRender();
|
|
|
|
EGLBoolean success = eglSwapBuffers(eglDisplay, eglSurface);
|
|
if(!success) {
|
|
GLint error = eglGetError();
|
|
ofLogNotice("ofAppEGLWindow") << "display(): eglSwapBuffers failed: " << eglErrorString(error);
|
|
}
|
|
|
|
nFramesSinceWindowResized++;
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
ofCoreEvents & ofAppEGLWindow::events(){
|
|
return coreEvents;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
shared_ptr<ofBaseRenderer> & ofAppEGLWindow::renderer(){
|
|
return currentRenderer;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::setupNativeEvents() {
|
|
setupNativeUDev();
|
|
setupNativeMouse();
|
|
setupNativeKeyboard();
|
|
startThread();
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::destroyNativeEvents() {
|
|
destroyNativeUDev();
|
|
destroyNativeMouse();
|
|
destroyNativeKeyboard();
|
|
waitForThread(true, threadTimeout);
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::setWindowRect(const ofRectangle& requestedWindowRect) {
|
|
if(!isWindowInited) {
|
|
ofLogError("ofAppEGLWindow") << "setWindowRect(): window not inited";
|
|
return;
|
|
}
|
|
|
|
ofRectangle newRect = requestedWindowRect.getStandardized();
|
|
|
|
if(newRect != currentWindowRect) {
|
|
ofRectangle oldWindowRect = currentWindowRect;
|
|
|
|
if(isUsingX11) {
|
|
int ret = XMoveResizeWindow(x11Display,
|
|
x11Window,
|
|
(int)newRect.x,
|
|
(int)newRect.y,
|
|
(unsigned int)newRect.width,
|
|
(unsigned int)newRect.height);
|
|
if(ret == BadValue) {
|
|
ofLogError("ofAppEGLWindow") << "setWindowRect(): XMoveResizeWindow returned BadValue";
|
|
} else if(ret == BadWindow) {
|
|
ofLogError("ofAppEGLWindow") << "setWindowRect(): XMoveResizeWindow returned BadWindow";
|
|
} else {
|
|
// all is good
|
|
currentWindowRect = newRect;
|
|
}
|
|
} else {
|
|
#ifdef TARGET_RASPBERRY_PI
|
|
|
|
VC_RECT_T dst_rect;
|
|
dst_rect.x = (int32_t)newRect.x;
|
|
dst_rect.y = (int32_t)newRect.y;
|
|
dst_rect.width = (int32_t)newRect.width;
|
|
dst_rect.height = (int32_t)newRect.height;
|
|
|
|
VC_RECT_T src_rect;
|
|
src_rect.x = 0;
|
|
src_rect.y = 0;
|
|
src_rect.width = (int32_t)newRect.width << 16;
|
|
src_rect.height = (int32_t)newRect.height << 16;
|
|
|
|
DISPMANX_UPDATE_HANDLE_T dispman_update = vc_dispmanx_update_start(0);
|
|
|
|
vc_dispmanx_element_change_attributes(dispman_update,
|
|
dispman_element,
|
|
ELEMENT_CHANGE_SRC_RECT|ELEMENT_CHANGE_DEST_RECT, // we do both when resizing
|
|
0, // layer (we aren't changing it here)
|
|
0, // opactiy (we aren't changing it here)
|
|
&dst_rect,
|
|
&src_rect,
|
|
0, // mask (we aren't changing it here)
|
|
(DISPMANX_TRANSFORM_T)0);
|
|
|
|
|
|
vc_dispmanx_update_submit_sync(dispman_update);
|
|
|
|
// next time swapBuffers is called, it will be resized based on this eglwindow size data
|
|
dispman_native_window.element = dispman_element;
|
|
dispman_native_window.width = (int32_t)newRect.width;
|
|
dispman_native_window.height = (int32_t)newRect.height; // don't forget!
|
|
|
|
currentWindowRect = newRect;
|
|
|
|
#else
|
|
ofLogError("ofAppEGLWindow") << "createEGLWindow(): no native window type for this system, perhaps try X11?";
|
|
#endif
|
|
}
|
|
|
|
if(oldWindowRect.width != currentWindowRect.width || oldWindowRect.height != currentWindowRect.height) {
|
|
coreEvents.notifyWindowResized(currentWindowRect.width, currentWindowRect.height);
|
|
nFramesSinceWindowResized = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------
|
|
bool ofAppEGLWindow::createWindow(const ofRectangle& requestedWindowRect) {
|
|
if(isUsingX11) {
|
|
return createX11NativeWindow(requestedWindowRect);
|
|
} else {
|
|
#ifdef TARGET_RASPBERRY_PI
|
|
return createRPiNativeWindow(requestedWindowRect);
|
|
#else
|
|
ofLogError("ofAppEGLWindow") << "createEGLWindow(): no native window type for this system, perhaps try X11?";
|
|
return false;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
int ofAppEGLWindow::getWindowWidth() {
|
|
return currentWindowRect.width;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
int ofAppEGLWindow::getWindowHeight() {
|
|
return currentWindowRect.height;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::pollEvents(){
|
|
if(!instance) return;
|
|
if(instance->isUsingX11) {
|
|
while(1){
|
|
XEvent event;
|
|
if (::XCheckWindowEvent(instance->x11Display, instance->x11Window, -1, &event)){
|
|
handleX11Event(event);
|
|
}else if (::XCheckTypedEvent(instance->x11Display, ClientMessage, &event)){
|
|
handleX11Event(event);
|
|
}else{
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
queue<ofMouseEventArgs> mouseEventsCopy;
|
|
instance->lock();
|
|
mouseEventsCopy = instance->mouseEvents;
|
|
while(!instance->mouseEvents.empty()){
|
|
instance->mouseEvents.pop();
|
|
}
|
|
instance->unlock();
|
|
while(!mouseEventsCopy.empty()){
|
|
instance->coreEvents.notifyMouseEvent(mouseEventsCopy.front());
|
|
mouseEventsCopy.pop();
|
|
}
|
|
|
|
// KEYBOARD EVENTS
|
|
queue<ofKeyEventArgs> keyEventsCopy;
|
|
instance->lock();
|
|
keyEventsCopy = instance->keyEvents;
|
|
while(!instance->keyEvents.empty()){
|
|
instance->keyEvents.pop();
|
|
}
|
|
instance->unlock();
|
|
while(!keyEventsCopy.empty()){
|
|
instance->coreEvents.notifyKeyEvent(keyEventsCopy.front());
|
|
keyEventsCopy.pop();
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::hideCursor(){
|
|
bShowCursor = false;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::showCursor(){
|
|
bShowCursor = true;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::setWindowTitle(string title) {
|
|
ofLogNotice("ofAppEGLWindow") << "setWindowTitle(): not implemented";
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
glm::vec2 ofAppEGLWindow::getWindowSize(){
|
|
return {currentWindowRect.width, currentWindowRect.height};
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
glm::vec2 ofAppEGLWindow::getWindowPosition(){
|
|
return currentWindowRect.getPosition().xy();
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
glm::vec2 ofAppEGLWindow::getScreenSize(){
|
|
unsigned int screenWidth = 0;
|
|
unsigned int screenHeight = 0;
|
|
|
|
if(isUsingX11) {
|
|
// TODO, there must be a way to get screensize if the window is not inited
|
|
if(isWindowInited && x11Screen) {
|
|
screenWidth = XWidthOfScreen(x11Screen);
|
|
screenHeight = XHeightOfScreen(x11Screen);
|
|
} else {
|
|
ofLogError("ofAppEGLWindow") << "getScreenSize(): tried to get display size but failed, x11Screen is not inited";
|
|
}
|
|
|
|
} else {
|
|
#ifdef TARGET_RASPBERRY_PI
|
|
int success = graphics_get_display_size(settings.screenNum, &screenWidth, &screenHeight);
|
|
if(success < 0) {
|
|
ofLogError("ofAppEGLWindow") << "getScreenSize(): tried to get display size but failed";
|
|
}
|
|
|
|
#else
|
|
ofLogError("ofAppEGLWindow") << "getScreenSize(): no native window type for this system, perhaps try X11?";
|
|
#endif
|
|
|
|
}
|
|
|
|
return {screenWidth, screenHeight};
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
int ofAppEGLWindow::getWidth(){
|
|
if( orientation == OF_ORIENTATION_DEFAULT || orientation == OF_ORIENTATION_180 ){
|
|
return currentWindowRect.width;
|
|
}
|
|
return currentWindowRect.height;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
int ofAppEGLWindow::getHeight(){
|
|
if( orientation == OF_ORIENTATION_DEFAULT || orientation == OF_ORIENTATION_180 ){
|
|
return currentWindowRect.height;
|
|
}
|
|
return currentWindowRect.width;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::setOrientation(ofOrientation orientationIn){
|
|
orientation = orientationIn;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
ofOrientation ofAppEGLWindow::getOrientation(){
|
|
return orientation;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
bool ofAppEGLWindow::doesHWOrientation() {
|
|
return false;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::setWindowPosition(int x, int y){
|
|
if(!isWindowInited) {
|
|
ofLogError("ofAppEGLWindow") << "setWindowPosition(): window not inited";
|
|
return;
|
|
}
|
|
|
|
if(isUsingX11) {
|
|
int ret = XMoveWindow(x11Display,
|
|
x11Window,
|
|
x,
|
|
y);
|
|
if(ret == BadValue) {
|
|
ofLogError("ofAppEGLWindow") << "setWindowPosition(): XMoveWindow returned BadValue";
|
|
} else if(ret == BadWindow) {
|
|
ofLogError("ofAppEGLWindow") << "setWindowPosition(): XMoveWindow returned BadWindow";
|
|
} else {
|
|
currentWindowRect.x = x;
|
|
currentWindowRect.y = y;
|
|
nonFullscreenWindowRect = currentWindowRect;
|
|
}
|
|
} else {
|
|
#ifdef TARGET_RASPBERRY_PI
|
|
|
|
// keep it in bounds
|
|
auto screenSize = getScreenSize();
|
|
x = ofClamp(x, 0, screenSize.x - currentWindowRect.width);
|
|
y = ofClamp(y, 0, screenSize.y - currentWindowRect.height);
|
|
|
|
VC_RECT_T dst_rect;
|
|
dst_rect.x = (int32_t)x;
|
|
dst_rect.y = (int32_t)y;
|
|
dst_rect.width = (int32_t)currentWindowRect.width;
|
|
dst_rect.height = (int32_t)currentWindowRect.height;
|
|
|
|
dispman_update = vc_dispmanx_update_start(0);
|
|
|
|
vc_dispmanx_element_change_attributes(dispman_update,
|
|
dispman_native_window.element,
|
|
ELEMENT_CHANGE_DEST_RECT,
|
|
0,
|
|
0,
|
|
&dst_rect,
|
|
NULL,
|
|
0,
|
|
(DISPMANX_TRANSFORM_T)0);
|
|
|
|
|
|
vc_dispmanx_update_submit_sync(dispman_update);
|
|
|
|
currentWindowRect.x = x;
|
|
currentWindowRect.y = y;
|
|
nonFullscreenWindowRect = currentWindowRect;
|
|
|
|
#else
|
|
ofLogError("ofAppEGLWindow") << "setWindowPosition(): no native window type for this system, perhaps try X11?";
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::setWindowShape(int w, int h){
|
|
if(!isWindowInited) {
|
|
ofLogError("ofAppEGLWindow") << "setWindowPosition(): window not inited";
|
|
return;
|
|
}
|
|
|
|
if(isUsingX11) {
|
|
int ret = XResizeWindow(x11Display,
|
|
x11Window,
|
|
(unsigned int)w,
|
|
(unsigned int)h);
|
|
if(ret == BadValue) {
|
|
ofLogError("ofAppEGLWindow") << "setWindowPosition(): XMoveWindow returned BadValue";
|
|
} else if(ret == BadWindow) {
|
|
ofLogError("ofAppEGLWindow") << "setWindowPosition(): XMoveWindow returned BadWindow";
|
|
} else {
|
|
currentWindowRect.width = w;
|
|
currentWindowRect.height = h;
|
|
nonFullscreenWindowRect = currentWindowRect;
|
|
}
|
|
} else {
|
|
#ifdef TARGET_RASPBERRY_PI
|
|
setWindowRect(ofRectangle(currentWindowRect.x,currentWindowRect.y,w,h));
|
|
nonFullscreenWindowRect = currentWindowRect;
|
|
#else
|
|
ofLogError("ofAppEGLWindow") << "setWindowPosition(): no native window type for this system, perhaps try X11?";
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
ofWindowMode ofAppEGLWindow::getWindowMode(){
|
|
return windowMode;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::toggleFullscreen(){
|
|
if( windowMode == OF_GAME_MODE) return;
|
|
|
|
if( windowMode == OF_WINDOW ){
|
|
setFullscreen(true);
|
|
}else{
|
|
setFullscreen(false);
|
|
}
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::setFullscreen(bool fullscreen){
|
|
if( windowMode == OF_GAME_MODE) return;
|
|
|
|
if(fullscreen && windowMode != OF_FULLSCREEN){
|
|
bNewScreenMode = true;
|
|
windowMode = OF_FULLSCREEN;
|
|
}else if(!fullscreen && windowMode != OF_WINDOW) {
|
|
bNewScreenMode = true;
|
|
windowMode = OF_WINDOW;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::enableSetupScreen(){
|
|
bEnableSetupScreen = true;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::disableSetupScreen(){
|
|
bEnableSetupScreen = false;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
ofRectangle ofAppEGLWindow::getScreenRect(){
|
|
auto screenSize = getScreenSize();
|
|
return ofRectangle(0,0,screenSize.x,screenSize.y);
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::setVerticalSync(bool enabled){
|
|
eglSwapInterval(eglDisplay, enabled ? 1 : 0);
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::threadedFunction(){
|
|
// TODO: a way to setup mouse and keyboard if
|
|
// they are not plugged in upon start
|
|
// This can be done with our udev device callbacks
|
|
|
|
while(isThreadRunning()) {
|
|
readNativeUDevEvents();
|
|
readNativeMouseEvents();
|
|
readNativeKeyboardEvents();
|
|
|
|
// sleep briefly
|
|
ofSleepMillis(20);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
// PLATFORM SPECIFIC RPI
|
|
//------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::setupNativeUDev() {
|
|
|
|
udev = udev_new(); // create new udev object
|
|
if(!udev) {
|
|
ofLogError("ofAppEGLWindow") << "setupNativeUDev(): couldn't create udev object";
|
|
} else {
|
|
ofLogNotice("ofAppEGLWindow") << "setupNativeUDev(): created udev object";
|
|
// setup udev to monitor for input devices
|
|
mon = udev_monitor_new_from_netlink(udev, "udev");
|
|
// just listen for input devices
|
|
udev_monitor_filter_add_match_subsystem_devtype(mon, "input", NULL);
|
|
udev_monitor_enable_receiving(mon);
|
|
// get the file descriptor for the mon (used w/ select);
|
|
udev_fd = udev_monitor_get_fd(mon);
|
|
}
|
|
|
|
if(udev_fd < 0) {
|
|
ofLogError("ofAppEGLWindow") << "setupNativeUDev(): did not create udev object, udev_fd < 0";
|
|
}
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::destroyNativeUDev() {
|
|
udev_unref(udev); // clean up
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::setupNativeMouse() {
|
|
struct dirent **eps; // What eps is supposed to mean?
|
|
|
|
// fallback to /dev/input/eventX since some vnc servers use uinput to
|
|
// handle mouse & keyboard.
|
|
typedef int (*filter_ptr)(const struct dirent *d);
|
|
filter_ptr mouse_filters[2] = { filter_mouse, filter_event };
|
|
string devicePathBuffers[2] = { "/dev/input/by-path/", "/dev/input/" };
|
|
|
|
// Examine available input devices in directories at devicePathBuffers.
|
|
for(auto i = 0; i < 2; i++){
|
|
|
|
// Get number of devices in the current input device directory.
|
|
int n = scandir(devicePathBuffers[i].c_str(), &eps, mouse_filters[i], dummy_sort);
|
|
|
|
// Open the appropriate entries,
|
|
// we want to get all mouse device events.
|
|
if(n >= 0 && eps != 0 && eps[0] != 0) {
|
|
for(auto j = 0; j < n; ++j){
|
|
string devicePathBuffer;
|
|
devicePathBuffer.append(devicePathBuffers[i]);
|
|
devicePathBuffer.append(eps[j]->d_name);
|
|
|
|
ofLogNotice("ofAppEGLWindow::setupNativeMouse()")
|
|
<< "attempt to open " << devicePathBuffer;
|
|
|
|
// TODO: create a vector out of fildes entries
|
|
int fildes = open(devicePathBuffer.c_str(), O_RDONLY | O_NONBLOCK);
|
|
|
|
// No file descriptor, stop the current iteration of the nested loop here,
|
|
// continue with the next value of j.
|
|
if(fildes < 0){
|
|
ofLogError("ofAppEGLWindow::setupNativeMouse()")
|
|
<< "failed to open mouse device";
|
|
continue;
|
|
}
|
|
|
|
// Seems that we got a mouse device open!
|
|
// Get all the parameters.
|
|
ofAppEGLWindowMouseArgs mouseArgs;
|
|
mouseArgs.fildes = fildes;
|
|
|
|
// TODO: consider a more reasonable way for calculating these.
|
|
mouseArgs.scaleX = 2.0f;
|
|
mouseArgs.scaleY = 2.0f;
|
|
|
|
// Find out if input device is a absolute positioning device
|
|
// set the minimum and maximum values of the axes.
|
|
// Do this for the x axis. EVIOCGABS(0): 0 stands for x axis.
|
|
struct input_absinfo mabsx;
|
|
if (ioctl(fildes, EVIOCGABS(0), &mabsx) < 0){
|
|
ofLogError("ofAppEGLWindow::setupNativeMouse()")
|
|
<< "failed to get absolute limits of input x axis";
|
|
mouseArgs.absXMin = 0;
|
|
mouseArgs.absXMax = 0;
|
|
} else {
|
|
mouseArgs.absXMin = mabsx.minimum;
|
|
mouseArgs.absXMax = mabsx.maximum;
|
|
ofLogNotice("ofAppEGLWindow::setupNativeMouse()")
|
|
<< "mouse x axis min, max: " << mouseArgs.absXMin
|
|
<< ", " << mouseArgs.absXMax;
|
|
}
|
|
|
|
// Do that for the y axis. EVIOCGABS(1): 1 stands for y axis.
|
|
struct input_absinfo mabsy;
|
|
if (ioctl(fildes, EVIOCGABS(1), &mabsy) < 0){
|
|
ofLogError("ofAppEGLWindow::setupNativeMouse()")
|
|
<< "failed to get absolute limits of input y axis";
|
|
mouseArgs.absYMin = 0;
|
|
mouseArgs.absYMax = 0;
|
|
} else {
|
|
mouseArgs.absYMin = mabsy.minimum;
|
|
mouseArgs.absYMax = mabsy.maximum;
|
|
ofLogNotice("ofAppEGLWindow::setupNativeMouse()")
|
|
<< "mouse y axis min, max: " << mouseArgs.absYMin
|
|
<< ", " << mouseArgs.absYMax;
|
|
}
|
|
|
|
// Get input device name.
|
|
char deviceNameBuffer[256] = "Unknown Device";
|
|
ioctl(fildes, EVIOCGNAME(sizeof(deviceNameBuffer)), deviceNameBuffer);
|
|
mouseArgs.deviceName = string(deviceNameBuffer);
|
|
ofLogNotice("ofAppEGLWindow::setupNativeMouse()")
|
|
<< "setting up mouse device with name "
|
|
<< mouseArgs.deviceName;
|
|
|
|
mice.push_back(mouseArgs);
|
|
|
|
ofLogNotice("ofAppEGLWindow") << "setupMouse(): fildes="
|
|
<< fildes << " devicePath=" << devicePathBuffer;
|
|
} // Nested for loop
|
|
}
|
|
|
|
// Do not examine other input device directories if we found some mice here.
|
|
// This breaks the main for loop of setupNativeMouse().
|
|
if(mice.size()){
|
|
break;
|
|
}
|
|
} // Main for loop
|
|
|
|
mb.mouseButtonState = 0;
|
|
|
|
if(mice.size() <= 0) {
|
|
mouseDetected = false;
|
|
ofLogWrning("ofAppEGLWindow::setupNativeMouse()")
|
|
<< "no mouse found";
|
|
} else {
|
|
mouseDetected = true;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::setupNativeKeyboard() {
|
|
struct dirent **eps;
|
|
typedef int (*filter_ptr)(const struct dirent *d);
|
|
filter_ptr kbd_filters[2] = { filter_kbd, filter_event };
|
|
string devicePathBuffers[2] = { "/dev/input/by-path/", "/dev/input/" };
|
|
|
|
for(int i=0; i<2; i++){
|
|
int n = scandir(devicePathBuffers[i].c_str(), &eps, kbd_filters[i], dummy_sort);
|
|
|
|
// make sure that we found an appropriate entry
|
|
if(n >= 0 && eps != 0 && eps[0] != 0) {
|
|
string devicePathBuffer;
|
|
devicePathBuffer.append(devicePathBuffers[i]);
|
|
devicePathBuffer.append(eps[0]->d_name);
|
|
keyboard_fd = open(devicePathBuffer.c_str(), O_RDONLY | O_NONBLOCK);
|
|
ofLogNotice("ofAppEGLWindow") << "setupKeyboard(): keyboard_fd=" << keyboard_fd << " devicePath=" << devicePathBuffer;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (keyboard_fd >= 0) {
|
|
char deviceNameBuffer[256] = "Unknown Device";
|
|
ioctl(keyboard_fd, EVIOCGNAME(sizeof(deviceNameBuffer)), deviceNameBuffer);
|
|
ofLogNotice("ofAppEGLWindow") << "setupKeyboard(): keyboard device name = " << deviceNameBuffer;
|
|
|
|
|
|
// save current terminal settings
|
|
tcgetattr (STDIN_FILENO, &tc);
|
|
ots = tc;
|
|
// disable echo on our temporary settings
|
|
tc.c_lflag &= ~ECHO;
|
|
tc.c_lflag |= ECHONL;
|
|
tcsetattr(STDIN_FILENO, TCSAFLUSH, &tc);
|
|
|
|
} else {
|
|
ofLogError("ofAppEGLWindow") << "setupKeyboard(): did not open keyboard";
|
|
}
|
|
|
|
kb.shiftPressed = false;
|
|
kb.capsLocked = false;
|
|
|
|
if(keyboard_fd < 0) {
|
|
ofLogError("ofAppEGLWindow") << "setupKeyboard(): did not open keyboard, keyboard_fd < 0";
|
|
} else {
|
|
keyboardDetected = true;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::destroyNativeMouse() {
|
|
for(auto i = 0; i < mice.size(); ++i){
|
|
int retval = close(mice[i].fildes);
|
|
if(retval < 0){
|
|
ofLogError("ofAppEGLWindow::destroyNativeMouse()")
|
|
<< "Failed to close mouse device: "
|
|
<< mice[i].deviceName;
|
|
}
|
|
}
|
|
mice.clear();
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::destroyNativeKeyboard() {
|
|
ofLogNotice("ofAppEGLWindow") << "destroyNativeKeyboard()";
|
|
|
|
if (keyboard_fd >= 0) {
|
|
tcsetattr (STDIN_FILENO, TCSAFLUSH, &ots);
|
|
} else {
|
|
ofLogNotice("ofAppEGLWindow") << "destroyNativeKeyboard(): unable to reset terminal";
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::readNativeUDevEvents() {
|
|
// look for devices being attatched / detatched
|
|
|
|
fd_set fds;
|
|
struct timeval tv;
|
|
int ret;
|
|
|
|
FD_ZERO(&fds);
|
|
FD_SET(udev_fd, &fds);
|
|
tv.tv_sec = 0;
|
|
tv.tv_usec = 0;
|
|
|
|
ret = select(udev_fd+1, &fds, NULL, NULL, &tv);
|
|
|
|
/* Check if our file descriptor has received data. */
|
|
if (ret > 0 && FD_ISSET(udev_fd, &fds)) {
|
|
/* Make the call to receive the device.
|
|
select() ensured that this will not block. */
|
|
dev = udev_monitor_receive_device(mon);
|
|
if (dev) {
|
|
// TODO: finish auto connect
|
|
ofLogNotice() << "Got device";
|
|
ofLogNotice() << " node: %s\n", udev_device_get_devnode(dev);
|
|
ofLogNotice() << " subsystem: %s\n", udev_device_get_subsystem(dev);
|
|
ofLogNotice() << " devtype: %s\n", udev_device_get_devtype(dev);
|
|
ofLogNotice() << " action: %s\n", udev_device_get_action(dev);
|
|
udev_device_unref(dev);
|
|
}
|
|
else {
|
|
ofLogNotice("ofAppEGLWindow") << "readNativeUDevEvents(): device returned by receive_device() is NULL";
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::readNativeKeyboardEvents() {
|
|
// http://www.diegm.uniud.it/loghi/CE2/kbd.pdf
|
|
// http://cgit.freedesktop.org/~whot/evtest/plain/evtest.c
|
|
// https://strcpy.net/b/archives/2010/11/17/abusing_the_linux_input_subsystem/index.html
|
|
struct input_event ev;
|
|
char key = 0;
|
|
|
|
int nBytesRead = read(keyboard_fd, &ev,sizeof(struct input_event));
|
|
|
|
static ofKeyEventArgs keyEvent;
|
|
bool pushKeyEvent = false;
|
|
|
|
while(nBytesRead >= 0) {
|
|
|
|
if (ev.type==EV_KEY) {
|
|
if(ev.value == 0) {
|
|
// key released
|
|
keyEvent.type = ofKeyEventArgs::Released;
|
|
} else if(ev.value == 1) {
|
|
// key pressed
|
|
keyEvent.type = ofKeyEventArgs::Pressed;
|
|
} else if(ev.value == 2) {
|
|
// key repeated
|
|
keyEvent.type = ofKeyEventArgs::Pressed;
|
|
} else {
|
|
// unknown ev.value
|
|
}
|
|
|
|
switch (ev.code) {
|
|
case KEY_RIGHTSHIFT:
|
|
case KEY_LEFTSHIFT:
|
|
kb.shiftPressed = ev.value;
|
|
break;
|
|
case KEY_RIGHTCTRL:
|
|
case KEY_LEFTCTRL:
|
|
break;
|
|
case KEY_CAPSLOCK:
|
|
if (ev.value == 1) {
|
|
if (kb.capsLocked) {
|
|
kb.capsLocked = 0;
|
|
} else {
|
|
kb.capsLocked = 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case KEY_ESC:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_ESC;
|
|
break;
|
|
case KEY_BACKSPACE:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_BACKSPACE;
|
|
break;
|
|
case KEY_DELETE:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_DEL;
|
|
break;
|
|
case KEY_F1:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_F1;
|
|
break;
|
|
case KEY_F2:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_F2;
|
|
break;
|
|
case KEY_F3:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_F3;
|
|
break;
|
|
case KEY_F4:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_F4;
|
|
break;
|
|
case KEY_F5:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_F5;
|
|
break;
|
|
case KEY_F6:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_F6;
|
|
break;
|
|
case KEY_F7:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_F7;
|
|
break;
|
|
case KEY_F8:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_F8;
|
|
break;
|
|
case KEY_F9:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_F9;
|
|
break;
|
|
case KEY_F10:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_F10;
|
|
break;
|
|
case KEY_F11:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_F11;
|
|
break;
|
|
case KEY_F12:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_F12;
|
|
break;
|
|
case KEY_LEFT:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_LEFT;
|
|
break;
|
|
case KEY_UP:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_UP;
|
|
break;
|
|
case KEY_RIGHT:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_RIGHT;
|
|
break;
|
|
case KEY_DOWN:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_DOWN;
|
|
break;
|
|
case KEY_PAGEUP:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_PAGE_UP;
|
|
break;
|
|
case KEY_PAGEDOWN:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_PAGE_DOWN;
|
|
break;
|
|
case KEY_HOME:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_HOME;
|
|
break;
|
|
case KEY_END:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_END;
|
|
break;
|
|
case KEY_INSERT:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_INSERT;
|
|
break;
|
|
case KEY_ENTER:
|
|
case KEY_KPENTER:
|
|
pushKeyEvent = true;
|
|
keyEvent.key = OF_KEY_RETURN;
|
|
break;
|
|
|
|
default:
|
|
// VERY RUDIMENTARY KEY MAPPING WITH MAPS ABOVE
|
|
if(ev.code < sizeof(lowercase_map)) {
|
|
if (kb.shiftPressed) {
|
|
key = uppercase_map[ev.code];
|
|
if (kb.capsLocked) keyEvent.key = tolower(key);
|
|
keyEvent.key = key;
|
|
pushKeyEvent = true;
|
|
} else {
|
|
key = lowercase_map[ev.code];
|
|
if (kb.capsLocked) key = toupper(key);
|
|
keyEvent.key = key;
|
|
pushKeyEvent = true;
|
|
}
|
|
} else {
|
|
ofLogNotice("ofAppEGLWindow") << "readKeyboardEvents(): input_event.code is outside of our small range";
|
|
}
|
|
}
|
|
} else if(ev.type == EV_MSC) {
|
|
// EV_MSC events are used for input and output events that
|
|
// do not fall under other categories.
|
|
// ofLogVerbose("ofAppEGLWindow") << "readKeyboardEvents(): EV_MSC";
|
|
} else if(ev.type == EV_SYN ) {
|
|
// EV_SYN Used as markers to separate events. Events may be
|
|
// separated in time or in space, such as with the multitouch protocol.
|
|
// ofLogVerbose("ofAppEGLWindow") << "readKeyboardEvents(): EV_SYN";
|
|
} else {
|
|
// unhandled type
|
|
}
|
|
|
|
// do we have a mouse svent to push?
|
|
if(pushKeyEvent){
|
|
lock();
|
|
keyEvents.push(keyEvent);
|
|
unlock();
|
|
pushKeyEvent = false;
|
|
}
|
|
|
|
nBytesRead = read(keyboard_fd, &ev,sizeof(struct input_event));
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::readNativeMouseEvents() {
|
|
// http://cgit.freedesktop.org/~whot/evtest/plain/evtest.c
|
|
struct input_event ev;
|
|
static ofMouseEventArgs mouseEvent;
|
|
bool pushMouseEvent = false;
|
|
|
|
for(auto i = 0; i < mice.size(); ++i){
|
|
// Loop through all open mouse devices
|
|
|
|
// -------------
|
|
int nBytesRead = read(mice[i].fildes, &ev,sizeof(struct input_event));
|
|
|
|
bool axisValuePending = false;
|
|
|
|
while(nBytesRead >= 0) {
|
|
|
|
if(ev.type == EV_REL || ev.type == EV_ABS) {
|
|
int axis = ev.code;
|
|
int amount = ev.value;
|
|
|
|
switch(axis) {
|
|
case 0:
|
|
if(ev.type == EV_REL) {
|
|
mouseEvent.x += amount * mouseScaleX;
|
|
} else {
|
|
mouseEvent.x = amount * (float)currentWindowRect.width / (float)mouseAbsXMax;
|
|
}
|
|
|
|
mouseEvent.x = ofClamp(mouseEvent.x, 0, currentWindowRect.width);
|
|
axisValuePending = true;
|
|
break;
|
|
case 1:
|
|
if(ev.type == EV_REL) {
|
|
mouseEvent.y += amount * mouseScaleY;
|
|
} else {
|
|
mouseEvent.y = amount * (float)currentWindowRect.height / (float)mouseAbsYMax;
|
|
}
|
|
|
|
mouseEvent.y = ofClamp(mouseEvent.y, 0, currentWindowRect.height);
|
|
axisValuePending = true;
|
|
break;
|
|
default:
|
|
ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): unknown mouse axis (perhaps it's the scroll wheel?)";
|
|
break;
|
|
}
|
|
|
|
} else if(ev.type == EV_KEY) {
|
|
// only tracking three buttons now ...
|
|
if(ev.code == BTN_LEFT) {
|
|
if(ev.value == 0) { // release
|
|
mouseEvent.button = OF_MOUSE_BUTTON_LEFT;
|
|
mouseEvent.type = ofMouseEventArgs::Released;
|
|
mb.mouseButtonState &= ~MOUSE_BUTTON_LEFT_MASK;
|
|
pushMouseEvent = true;
|
|
} else if(ev.value == 1) { // press
|
|
mb.mouseButtonState |= MOUSE_BUTTON_LEFT_MASK;
|
|
mouseEvent.type = ofMouseEventArgs::Pressed;
|
|
mouseEvent.button = OF_MOUSE_BUTTON_LEFT;
|
|
pushMouseEvent = true;
|
|
} else { // unknown
|
|
ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): EV_KEY : unknown ev.value = " << ev.value;
|
|
}
|
|
} else if(ev.code == BTN_MIDDLE) {
|
|
if(ev.value == 0) { // release
|
|
mouseEvent.button = OF_MOUSE_BUTTON_MIDDLE;
|
|
mouseEvent.type = ofMouseEventArgs::Released;
|
|
mb.mouseButtonState &= ~MOUSE_BUTTON_MIDDLE_MASK;
|
|
pushMouseEvent = true;
|
|
} else if(ev.value == 1) { // press
|
|
mb.mouseButtonState |= MOUSE_BUTTON_MIDDLE_MASK;
|
|
mouseEvent.type = ofMouseEventArgs::Pressed;
|
|
mouseEvent.button = OF_MOUSE_BUTTON_MIDDLE;
|
|
pushMouseEvent = true;
|
|
} else { // unknown
|
|
ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): EV_KEY : unknown ev.value = " << ev.value;
|
|
}
|
|
} else if(ev.code == BTN_RIGHT) {
|
|
if(ev.value == 0) { // release
|
|
mouseEvent.button = OF_MOUSE_BUTTON_RIGHT;
|
|
mouseEvent.type = ofMouseEventArgs::Released;
|
|
mb.mouseButtonState &= ~MOUSE_BUTTON_RIGHT_MASK;
|
|
pushMouseEvent = true;
|
|
} else if(ev.value == 1) { // press
|
|
mb.mouseButtonState |= MOUSE_BUTTON_RIGHT_MASK;
|
|
mouseEvent.type = ofMouseEventArgs::Pressed;
|
|
mouseEvent.button = OF_MOUSE_BUTTON_RIGHT;
|
|
pushMouseEvent = true;
|
|
} else {
|
|
ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): EV_KEY : unknown ev.value = " << ev.value;
|
|
}
|
|
} else {
|
|
ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): EV_KEY : unknown ev.code = " << ev.code;
|
|
}
|
|
// not sure why we are getting that event here
|
|
} else if(ev.type == EV_MSC) {
|
|
// EV_MSC events are used for input and output events that
|
|
// do not fall under other categories.
|
|
// ofLogVerbose("ofAppEGLWindow") << "readMouseEvents() : EV_MSC";
|
|
} else if(ev.type == EV_SYN ) {
|
|
// EV_SYN Used as markers to separate events. Events may be
|
|
// separated in time or in space, such as with the multitouch protocol.
|
|
|
|
// EV_SYN events are sent when axis value (one or a pair) are changed
|
|
if(axisValuePending) {
|
|
// TODO, this state doesn't make as much sense when the mouse is not dragging
|
|
if(mb.mouseButtonState > 0) {
|
|
// dragging (what if dragging w/ more than one button?)
|
|
mouseEvent.type = ofMouseEventArgs::Dragged;
|
|
} else {
|
|
// just moving
|
|
mouseEvent.type = ofMouseEventArgs::Moved;
|
|
}
|
|
|
|
mouseEvent.button = mb.mouseButtonState;
|
|
|
|
pushMouseEvent = true;
|
|
axisValuePending = false;
|
|
}
|
|
|
|
//ofLogVerbose("ofAppEGLWindow") << "readMouseEvents(): EV_SYN";
|
|
} else {
|
|
// unhandled type
|
|
}
|
|
|
|
// do we have a mouse event to push?
|
|
if(pushMouseEvent){
|
|
// lock the thread for a moment while we copy the data
|
|
lock();
|
|
mouseEvents.push(mouseEvent);
|
|
unlock();
|
|
pushMouseEvent = false;
|
|
}
|
|
|
|
// Why another read?
|
|
nBytesRead = read(mice[i].fildes, &ev,sizeof(struct input_event));
|
|
} // While loop
|
|
// ------------
|
|
} // For loop
|
|
|
|
}
|
|
|
|
#ifdef TARGET_RASPBERRY_PI
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::initRPiNative() {
|
|
bcm_host_init();
|
|
|
|
memset(&dispman_native_window, 0x0, sizeof(EGL_DISPMANX_WINDOW_T));
|
|
dispman_element = DISPMANX_NO_HANDLE;
|
|
dispman_display = DISPMANX_NO_HANDLE;
|
|
dispman_update = DISPMANX_NO_HANDLE;
|
|
memset(&dispman_clamp, 0x0, sizeof(DISPMANX_CLAMP_T));
|
|
dispman_transform = DISPMANX_NO_ROTATE;
|
|
memset(&dispman_alpha, 0x0, sizeof(VC_DISPMANX_ALPHA_T)); // zero dispman_alpha
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::exitRPiNative() {
|
|
bcm_host_deinit();
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
bool ofAppEGLWindow::createRPiNativeWindow(const ofRectangle& requestedWindowRect){
|
|
|
|
ofRectangle screenRect = getScreenRect();
|
|
|
|
// make sure our requested window rectangle does not exceed the native
|
|
// screen size, or start outside of it.
|
|
ofRectangle windowRect = screenRect.getIntersection(requestedWindowRect);
|
|
|
|
ofLogNotice("ofAppEGLWindow") << "setupRPiNativeWindow(): screenRect: " << screenRect.width << "x" << screenRect.height;
|
|
ofLogNotice("ofAppEGLWindow") << "setupRPiNativeWindow(): windowRect: " << windowRect.width << "x" << windowRect.height;
|
|
|
|
//////////////////////////
|
|
VC_RECT_T dst_rect;
|
|
|
|
dst_rect.x = (int32_t)windowRect.x;
|
|
dst_rect.y = (int32_t)windowRect.y;
|
|
dst_rect.width = (int32_t)windowRect.width;
|
|
dst_rect.height = (int32_t)windowRect.height;
|
|
|
|
VC_RECT_T src_rect;
|
|
|
|
src_rect.x = 0;
|
|
src_rect.y = 0;
|
|
src_rect.width = dst_rect.width << 16;
|
|
src_rect.height = dst_rect.height << 16;
|
|
|
|
memset(&dispman_alpha, 0x0, sizeof(VC_DISPMANX_ALPHA_T)); // zero dispman_alpha
|
|
dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
|
|
dispman_alpha.opacity = ofClamp(settings.eglWindowOpacity,0,255);
|
|
dispman_alpha.mask = 0;
|
|
|
|
memset(&dispman_clamp, 0x0, sizeof(DISPMANX_CLAMP_T));
|
|
|
|
// there are other values for dispman_transform, but they do not seem to have an effect
|
|
dispman_transform = DISPMANX_NO_ROTATE;
|
|
|
|
// get the zero display
|
|
dispman_display = vc_dispmanx_display_open(settings.screenNum);
|
|
|
|
// begin the display manager interaction
|
|
dispman_update = vc_dispmanx_update_start( 0 );
|
|
|
|
// add a "display manager element" with our parameters so
|
|
// that it can fill in the structures. we will pass this
|
|
// filled dispman_element to our native window, which will
|
|
// be used to construct the EGL surface, etc.
|
|
dispman_element = vc_dispmanx_element_add ( dispman_update,
|
|
dispman_display,
|
|
settings.layer, // layer
|
|
&dst_rect, // dst rect
|
|
(DISPMANX_RESOURCE_HANDLE_T)0, // src
|
|
&src_rect, // src rect
|
|
DISPMANX_PROTECTION_NONE, // ?
|
|
&dispman_alpha, // alpha
|
|
&dispman_clamp, // clamp
|
|
dispman_transform // transform
|
|
);
|
|
|
|
if(dispman_element == DISPMANX_NO_HANDLE) {
|
|
ofLogError("ofAppEGLWindow") << "setupRPiNativeWindow(): dispman_element == DISPMANX_NO_HANDLE";
|
|
return false;
|
|
} else if(dispman_element == (unsigned)DISPMANX_INVALID) {
|
|
ofLogError("ofAppEGLWindow") << "setupRPiNativeWindow(): dispman_element == DISPMANX_INVALID";
|
|
return false;
|
|
}
|
|
|
|
// set dispman_native_window to zero
|
|
memset(&dispman_native_window, 0x0, sizeof(EGL_DISPMANX_WINDOW_T));
|
|
dispman_native_window.element = dispman_element;
|
|
dispman_native_window.width = (int32_t)windowRect.width;
|
|
dispman_native_window.height = (int32_t)windowRect.height;
|
|
|
|
// set background to black (not required)
|
|
vc_dispmanx_display_set_background(dispman_update, dispman_display, 0x00, 0x00, 0x00);
|
|
|
|
// finished with display manager update, so sync
|
|
vc_dispmanx_update_submit_sync( dispman_update );
|
|
|
|
currentWindowRect = windowRect;
|
|
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
//------------------------------------------------------------
|
|
// X11 BELOW
|
|
//------------------------------------------------------------
|
|
bool ofAppEGLWindow::createX11NativeWindow(const ofRectangle& requestedWindowRect){
|
|
|
|
// X11 variables
|
|
x11Window = 0;
|
|
x11Display = 0;
|
|
x11ScreenNum = 0; // TODO: settings.screenNum?
|
|
x11Screen = 0;
|
|
XVisualInfo* x11Visual = 0; // TODO does this need to be deleted?
|
|
Colormap x11Colormap = 0;
|
|
|
|
/*
|
|
Step 0 - Create a NativeWindowType that we can use it for OpenGL ES output
|
|
*/
|
|
Window sRootWindow;
|
|
XSetWindowAttributes sWA;
|
|
unsigned int ui32Mask;
|
|
int i32Depth;
|
|
|
|
//ofRectangle screenRect = getScreenRect();
|
|
|
|
// make sure our requested window rectangle does not exceed the native
|
|
// screen size, or start outside of it.
|
|
ofRectangle windowRect = requestedWindowRect.getStandardized();//screenRect.getIntersection(requestedWindowRect);
|
|
|
|
// Initializes the display and screen
|
|
x11Display = XOpenDisplay( 0 );
|
|
if (!x11Display) {
|
|
ofLogError("ofAppEGLWindow") << "unable to open X display";
|
|
return false;
|
|
}
|
|
|
|
x11ScreenNum = XDefaultScreen( x11Display );
|
|
|
|
x11Screen = XDefaultScreenOfDisplay(x11Display);
|
|
|
|
// Gets the window parameters
|
|
sRootWindow = RootWindow(x11Display, x11ScreenNum);
|
|
i32Depth = DefaultDepth(x11Display, x11ScreenNum);
|
|
x11Visual = new XVisualInfo();
|
|
|
|
XMatchVisualInfo( x11Display,
|
|
x11ScreenNum,
|
|
i32Depth,
|
|
TrueColor,
|
|
x11Visual);
|
|
|
|
if (!x11Visual) {
|
|
ofLogError("ofAppEGLWindow") << "unable to acquire XVisualInfo";
|
|
return false;
|
|
}
|
|
|
|
x11Colormap = XCreateColormap( x11Display, sRootWindow, x11Visual->visual, AllocNone );
|
|
|
|
delete x11Visual;
|
|
|
|
// set the colormap window attribuet
|
|
sWA.colormap = x11Colormap;
|
|
|
|
// Add to these for handling other events
|
|
sWA.event_mask = 0;
|
|
sWA.event_mask |= StructureNotifyMask;
|
|
sWA.event_mask |= ExposureMask;
|
|
sWA.event_mask |= ButtonPressMask;
|
|
sWA.event_mask |= ButtonReleaseMask;
|
|
sWA.event_mask |= PointerMotionMask;
|
|
sWA.event_mask |= KeyPressMask;
|
|
sWA.event_mask |= KeyReleaseMask;
|
|
|
|
// setup background pixel attributes
|
|
ui32Mask = 0;
|
|
ui32Mask |= CWBackPixel;
|
|
ui32Mask |= CWBorderPixel;
|
|
ui32Mask |= CWEventMask;
|
|
ui32Mask |= CWColormap;
|
|
|
|
// Creates the X11 window
|
|
x11Window = XCreateWindow(x11Display, // Specifies the connection to the X server.
|
|
sRootWindow, // Specifies the parent window.
|
|
(int)windowRect.x, (int)windowRect.y, // Specify the x and y coordinates,
|
|
// which are the top-left outside corner
|
|
// of the window's borders and are relative
|
|
// to the inside of the parent window's borders.
|
|
(unsigned int)windowRect.width, (unsigned int)windowRect.height, // Specify the width and height, which are the
|
|
// created window's inside dimensions and do
|
|
// not include the created window's borders.
|
|
0, // Specifies the width of the created
|
|
// window's border in pixels.
|
|
CopyFromParent, // Specifies the window's depth.
|
|
// A depth of CopyFromParent means
|
|
// the depth is taken from the parent.
|
|
InputOutput, // Specifies the created window's class.
|
|
// You can pass InputOutput, InputOnly,
|
|
// or CopyFromParent. A class of CopyFromParent
|
|
// means the class is taken from the parent.
|
|
CopyFromParent, // Specifies the visual type.
|
|
// A visual of CopyFromParent means the visual type
|
|
// is taken from the parent.
|
|
ui32Mask, // Specifies which window attributes are
|
|
// defined in the attributes argument. This mask is
|
|
// the bitwise inclusive OR of the valid attribute
|
|
// mask bits. If valuemask is zero, the attributes
|
|
// are ignored and are not referenced.
|
|
&sWA //Specifies the background pixel value of the window.
|
|
);
|
|
|
|
XMapWindow(x11Display, x11Window);
|
|
XFlush(x11Display);
|
|
|
|
// check success?
|
|
currentWindowRect = windowRect;
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
static KeySym KeyCodeToKeySym(Display * display, KeyCode keycode, unsigned int event_mask) {
|
|
KeySym keysym = NoSymbol;
|
|
|
|
//Get the map
|
|
XkbDescPtr keyboard_map = XkbGetMap(display, XkbAllClientInfoMask, XkbUseCoreKbd);
|
|
if (keyboard_map) {
|
|
//What is diff between XkbKeyGroupInfo and XkbKeyNumGroups?
|
|
unsigned char info = XkbKeyGroupInfo(keyboard_map, keycode);
|
|
unsigned int num_groups = XkbKeyNumGroups(keyboard_map, keycode);
|
|
|
|
//Get the group
|
|
unsigned int group = 0x00;
|
|
switch (XkbOutOfRangeGroupAction(info)) {
|
|
case XkbRedirectIntoRange:
|
|
/* If the RedirectIntoRange flag is set, the four least significant
|
|
* bits of the groups wrap control specify the index of a group to
|
|
* which all illegal groups correspond. If the specified group is
|
|
* also out of range, all illegal groups map to Group1.
|
|
*/
|
|
group = XkbOutOfRangeGroupInfo(info);
|
|
if (group >= num_groups) {
|
|
group = 0;
|
|
}
|
|
break;
|
|
|
|
case XkbClampIntoRange:
|
|
/* If the ClampIntoRange flag is set, out-of-range groups correspond
|
|
* to the nearest legal group. Effective groups larger than the
|
|
* highest supported group are mapped to the highest supported group;
|
|
* effective groups less than Group1 are mapped to Group1 . For
|
|
* example, a key with two groups of symbols uses Group2 type and
|
|
* symbols if the global effective group is either Group3 or Group4.
|
|
*/
|
|
group = num_groups - 1;
|
|
break;
|
|
|
|
case XkbWrapIntoRange:
|
|
/* If neither flag is set, group is wrapped into range using integer
|
|
* modulus. For example, a key with two groups of symbols for which
|
|
* groups wrap uses Group1 symbols if the global effective group is
|
|
* Group3 or Group2 symbols if the global effective group is Group4.
|
|
*/
|
|
default:
|
|
if (num_groups != 0) {
|
|
group %= num_groups;
|
|
}
|
|
break;
|
|
}
|
|
|
|
XkbKeyTypePtr key_type = XkbKeyKeyType(keyboard_map, keycode, group);
|
|
unsigned int active_mods = event_mask & key_type->mods.mask;
|
|
|
|
int i, level = 0;
|
|
for (i = 0; i < key_type->map_count; i++) {
|
|
if (key_type->map[i].active && key_type->map[i].mods.mask == active_mods) {
|
|
level = key_type->map[i].level;
|
|
}
|
|
}
|
|
|
|
keysym = XkbKeySymEntry(keyboard_map, keycode, level, group);
|
|
XkbFreeClientMap(keyboard_map, XkbAllClientInfoMask, true);
|
|
}
|
|
|
|
return keysym;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
void ofAppEGLWindow::handleX11Event(const XEvent& event){
|
|
ofMouseEventArgs mouseEvent;
|
|
ofKeyEventArgs keyEvent;
|
|
switch (event.type){
|
|
case KeyPress:
|
|
case KeyRelease:
|
|
{
|
|
KeySym key = KeyCodeToKeySym(instance->x11Display,event.xkey.keycode,event.xkey.state);
|
|
keyEvent.key = key;
|
|
if (event.type == KeyPress) {
|
|
keyEvent.type = ofKeyEventArgs::Pressed;
|
|
if(key == 65307){
|
|
keyEvent.key = OF_KEY_ESC;
|
|
}
|
|
} else if (event.type == KeyRelease){
|
|
keyEvent.type = ofKeyEventArgs::Released;
|
|
}
|
|
|
|
instance->coreEvents.notifyKeyEvent(keyEvent);
|
|
}
|
|
break;
|
|
case ButtonPress:
|
|
case ButtonRelease:
|
|
mouseEvent.x = static_cast<float>(event.xbutton.x);
|
|
mouseEvent.y = static_cast<float>(event.xbutton.y);
|
|
mouseEvent.button = event.xbutton.button;
|
|
if (event.type == ButtonPress){
|
|
mouseEvent.type = ofMouseEventArgs::Pressed;
|
|
} else {
|
|
mouseEvent.type = ofMouseEventArgs::Released;
|
|
}
|
|
|
|
instance->coreEvents.notifyMouseEvent(mouseEvent);
|
|
break;
|
|
case MotionNotify:
|
|
//cout << "motion notify" << endl;
|
|
mouseEvent.x = static_cast<float>(event.xmotion.x);
|
|
mouseEvent.y = static_cast<float>(event.xmotion.y);
|
|
mouseEvent.button = event.xbutton.button;
|
|
if(ofGetMousePressed()) {
|
|
mouseEvent.type = ofMouseEventArgs::Dragged;
|
|
} else {
|
|
mouseEvent.type = ofMouseEventArgs::Moved;
|
|
}
|
|
|
|
instance->coreEvents.notifyMouseEvent(mouseEvent);
|
|
break;
|
|
case ConfigureNotify:
|
|
instance->currentWindowRect.x = event.xconfigure.x;
|
|
instance->currentWindowRect.y = event.xconfigure.y;
|
|
instance->currentWindowRect.width = event.xconfigure.width;
|
|
instance->currentWindowRect.height = event.xconfigure.height;
|
|
instance->nonFullscreenWindowRect = instance->currentWindowRect;
|
|
instance->coreEvents.notifyWindowResized(event.xconfigure.width,event.xconfigure.height);
|
|
break;
|
|
/*case ClientMessage:{
|
|
if (event.xclient.message_type == wmProtocols_ &&
|
|
event.xclient.format == 32 &&
|
|
event.xclient.data.l[0] == (long) wmDeleteWindow_)
|
|
{
|
|
if (listener())
|
|
{
|
|
if (listener()->onClose(wrapper() ? *wrapper() : *(WindowInterface*)this))
|
|
isShuttingDown_ = true;
|
|
}
|
|
else
|
|
{
|
|
isShuttingDown_ = true;
|
|
}
|
|
}
|
|
break;
|
|
}*/
|
|
}
|
|
}
|
|
|