From e028581fabb68f8f28489bce7b570026c02e8df8 Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Wed, 3 Nov 2010 19:27:17 +0100 Subject: [PATCH] SDL: add input support, use SDL mainloop in a thread --- lib/driver/Makefile.am | 9 + lib/driver/rcsdl.cpp | 390 +++++++++++++++++++++++++++++++++++++++++ lib/driver/rcsdl.h | 37 ++++ lib/gdi/sdl.cpp | 131 ++++++++++---- lib/gdi/sdl.h | 26 ++- 5 files changed, 554 insertions(+), 39 deletions(-) create mode 100644 lib/driver/rcsdl.cpp create mode 100644 lib/driver/rcsdl.h diff --git a/lib/driver/Makefile.am b/lib/driver/Makefile.am index 88d9bec5..b498a6c8 100644 --- a/lib/driver/Makefile.am +++ b/lib/driver/Makefile.am @@ -4,6 +4,9 @@ AM_CPPFLAGS = \ -include Python.h \ -include $(top_builddir)/enigma2_config.h +AM_CXXFLAGS = \ + $(LIBSDL_CFLAGS) + noinst_LIBRARIES = libenigma_driver.a libenigma_driver_a_SOURCES = \ @@ -27,3 +30,9 @@ driverinclude_HEADERS = \ rcdreambox2.h \ rcinput.h \ rfmod.h + +if HAVE_LIBSDL +libenigma_driver_a_SOURCES += \ + rcsdl.cpp \ + rcsdl.h +endif diff --git a/lib/driver/rcsdl.cpp b/lib/driver/rcsdl.cpp new file mode 100644 index 00000000..a907b80a --- /dev/null +++ b/lib/driver/rcsdl.cpp @@ -0,0 +1,390 @@ +#include +//#include +#include +#include +#include + +/* + * eSDLInputDevice + */ + +eSDLInputDevice::eSDLInputDevice(eRCDriver *driver) : eRCDevice("SDL", driver), m_escape(false), m_unicode(0) +{ +} + +eSDLInputDevice::~eSDLInputDevice() +{ +} + +void eSDLInputDevice::handleCode(long arg) +{ + const SDL_KeyboardEvent *event = (const SDL_KeyboardEvent *)arg; + const SDL_keysym *key = &event->keysym; + int km = input->getKeyboardMode(); + int code, flags; + + if (event->type == SDL_KEYDOWN) { + m_unicode = key->unicode; + flags = eRCKey::flagMake; + } else { + flags = eRCKey::flagBreak; + } + + if (km == eRCInput::kmNone) { + code = translateKey(key->sym); + } else { + eDebug("unicode=%04x scancode=%02x", m_unicode, key->scancode); + if (m_unicode & 0xff80) { + eDebug("SDL: skipping unicode character"); + return; + } + code = m_unicode & ~0xff80; + // unicode not set...!? use key symbol + if (code == 0) { + // keysym is ascii + if (key->sym >= 128) { + eDebug("SDL: cannot emulate ASCII"); + return; + } + eDebug("SDL: emulate ASCII"); + code = key->sym; + } + if (km == eRCInput::kmAscii) { + // skip ESC c or ESC '[' c + if (m_escape) { + if (code != '[') + m_escape = false; + return; + } + + if (code == SDLK_ESCAPE) + m_escape = true; + + if ((code < SDLK_SPACE) || + (code == 0x7e) || // really? + (code == SDLK_DELETE)) + return; + } + flags |= eRCKey::flagAscii; + } + + eDebug("SDL code=%d flags=%d", code, flags); + input->keyPressed(eRCKey(this, code, flags)); +} + +const char *eSDLInputDevice::getDescription() const +{ + return "SDL"; +} + +int eSDLInputDevice::translateKey(SDLKey key) +{ + #define P(a) case SDLK_##a: return KEY_##a + #define P2(a,b) case SDLK_##a: return KEY_##b + + switch (key) { + P(BACKSPACE); + P(TAB); + P(CLEAR); + P2(RETURN,ENTER); + P(PAUSE); + P2(ESCAPE,ESC); + P(SPACE); +#if 0 + P(EXCLAIM); + P(QUOTEDBL); + P(HASH); +#endif + P(DOLLAR); +#if 0 + P(AMPERSAND); +#endif + P2(QUOTE,APOSTROPHE); +#if 0 + P(LEFTPAREN); + P(RIGHTPAREN); + P(ASTERISK); + P(PLUS); +#endif + P(COMMA); + P(MINUS); + P2(PERIOD,DOT); + P(SLASH); + P(0); + P(1); + P(2); + P(3); + P(4); + P(5); + P(6); + P(7); + P(8); + P(9); +#if 0 + P(COLON); +#endif + P(SEMICOLON); +#if 0 + P(LESS); +#endif + P2(EQUALS,EQUAL); +#if 0 + P(GREATER); +#endif + P(QUESTION); +#if 0 + P(AT); +#endif + P2(LEFTBRACKET,LEFTBRACE); + P(BACKSLASH); + P2(RIGHTBRACKET,RIGHTBRACE); + P2(CARET,GRAVE); +#if 0 + P(UNDERSCORE); + P(BACKQUOTE); +#endif + P2(a,A); + P2(b,B); + P2(c,C); + P2(d,D); + P2(e,E); + P2(f,F); + P2(g,G); + P2(h,H); + P2(i,I); + P2(j,J); + P2(k,K); + P2(l,L); + P2(m,M); + P2(n,N); + P2(o,O); + P2(p,P); + P2(q,Q); + P2(r,R); + P2(s,S); + P2(t,T); + P2(u,U); + P2(v,V); + P2(w,W); + P2(x,X); + P2(y,Y); + P2(z,Z); + P(DELETE); +#if 0 + P(WORLD_0); + P(WORLD_1); + P(WORLD_2); + P(WORLD_3); + P(WORLD_4); + P(WORLD_5); + P(WORLD_6); + P(WORLD_7); + P(WORLD_8); + P(WORLD_9); + P(WORLD_10); + P(WORLD_11); + P(WORLD_12); + P(WORLD_13); + P(WORLD_14); + P(WORLD_15); + P(WORLD_16); + P(WORLD_17); + P(WORLD_18); + P(WORLD_19); + P(WORLD_20); + P(WORLD_21); + P(WORLD_22); + P(WORLD_23); + P(WORLD_24); + P(WORLD_25); + P(WORLD_26); + P(WORLD_27); + P(WORLD_28); + P(WORLD_29); + P(WORLD_30); + P(WORLD_31); + P(WORLD_32); + P(WORLD_33); + P(WORLD_34); + P(WORLD_35); + P(WORLD_36); + P(WORLD_37); + P(WORLD_38); + P(WORLD_39); + P(WORLD_40); + P(WORLD_41); + P(WORLD_42); + P(WORLD_43); + P(WORLD_44); + P(WORLD_45); + P(WORLD_46); + P(WORLD_47); + P(WORLD_48); + P(WORLD_49); + P(WORLD_50); + P(WORLD_51); + P(WORLD_52); + P(WORLD_53); + P(WORLD_54); + P(WORLD_55); + P(WORLD_56); + P(WORLD_57); + P(WORLD_58); + P(WORLD_59); + P(WORLD_60); + P(WORLD_61); + P(WORLD_62); + P(WORLD_63); + P(WORLD_64); + P(WORLD_65); + P(WORLD_66); + P(WORLD_67); + P(WORLD_68); + P(WORLD_69); + P(WORLD_70); + P(WORLD_71); + P(WORLD_72); + P(WORLD_73); + P(WORLD_74); + P(WORLD_75); + P(WORLD_76); + P(WORLD_77); + P(WORLD_78); + P(WORLD_79); + P(WORLD_80); + P(WORLD_81); + P(WORLD_82); + P(WORLD_83); + P(WORLD_84); + P(WORLD_85); + P(WORLD_86); + P(WORLD_87); + P(WORLD_88); + P(WORLD_89); + P(WORLD_90); + P(WORLD_91); + P(WORLD_92); + P(WORLD_93); + P(WORLD_94); + P(WORLD_95); +#endif + P(KP0); + P(KP1); + P(KP2); + P(KP3); + P(KP4); + P(KP5); + P(KP6); + P(KP7); + P(KP8); + P(KP9); + P2(KP_PERIOD,KPDOT); + P2(KP_DIVIDE,KPSLASH); + P2(KP_MULTIPLY,KPASTERISK); + P2(KP_MINUS,KPMINUS); + P2(KP_PLUS,KPPLUS); + P2(KP_ENTER,KPENTER); + P2(KP_EQUALS,KPEQUAL); + P(UP); + P(DOWN); + P(RIGHT); + P(LEFT); + P(INSERT); + P(HOME); + P(END); + P(PAGEUP); + P(PAGEDOWN); + P(F1); + P(F2); + P(F3); + P(F4); + P(F5); + P(F6); + P(F7); + P(F8); + P(F9); + P(F10); + P(F11); + P(F12); + P(F13); + P(F14); + P(F15); + P(NUMLOCK); + P(CAPSLOCK); + P2(SCROLLOCK,SCROLLLOCK); + P2(RSHIFT,RIGHTSHIFT); + P2(LSHIFT,LEFTSHIFT); + P2(RCTRL,RIGHTCTRL); + P2(LCTRL,LEFTCTRL); + P2(RALT,RIGHTALT); + P2(LALT,LEFTALT); + P2(RMETA,RIGHTMETA); + P2(LMETA,LEFTMETA); +#if 0 + P(LSUPER); + P(RSUPER); +#endif + P(MODE); + P(COMPOSE); + P(HELP); + P(PRINT); + P2(SYSREQ,SYSRQ); + P(BREAK); + P(MENU); + P(POWER); + P(EURO); + P(UNDO); + default: + eDebug("unhandled SDL keycode: %d", key); + return KEY_RESERVED; + } + + #undef P2 + #undef P +} + +/* + * eSDLInputDriver + */ + +eSDLInputDriver *eSDLInputDriver::instance; + +eSDLInputDriver::eSDLInputDriver() : eRCDriver(eRCInput::getInstance()) +{ + ASSERT(instance == 0); + instance = this; +} + +eSDLInputDriver::~eSDLInputDriver() +{ + instance = 0; +} + +void eSDLInputDriver::keyPressed(const SDL_KeyboardEvent *key) +{ + eDebug("km=%d enabled=%d locked=%d", + input->getKeyboardMode(), enabled, input->islocked()); + + if (!enabled || input->islocked()) + return; + + std::list::iterator i(listeners.begin()); + while (i != listeners.end()) { + (*i)->handleCode((long)key); + ++i; + } +} + +class eRCSDLInit +{ +private: + eSDLInputDriver driver; + eSDLInputDevice device; + +public: + eRCSDLInit(): driver(), device(&driver) + { + } +}; + +eAutoInitP0 init_rcSDL(eAutoInitNumbers::rc+1, "SDL RC Driver"); diff --git a/lib/driver/rcsdl.h b/lib/driver/rcsdl.h new file mode 100644 index 00000000..9732f5e4 --- /dev/null +++ b/lib/driver/rcsdl.h @@ -0,0 +1,37 @@ +#ifndef __lib_driver_rcsdl_h +#define __lib_driver_rcsdl_h + +#include + +#include + +class eSDLInputDevice : public eRCDevice +{ +private: + bool m_escape; + unsigned int m_unicode; + int translateKey(SDLKey key); + +public: + eSDLInputDevice(eRCDriver *driver); + ~eSDLInputDevice(); + + virtual void handleCode(long arg); + virtual const char *getDescription() const; +}; + +class eSDLInputDriver : public eRCDriver +{ +private: + static eSDLInputDriver *instance; + +public: + eSDLInputDriver(); + ~eSDLInputDriver(); + + static eSDLInputDriver *getInstance() { return instance; } + + void keyPressed(const SDL_KeyboardEvent *key); +}; + +#endif diff --git a/lib/gdi/sdl.cpp b/lib/gdi/sdl.cpp index e816a185..eb4e2ae4 100644 --- a/lib/gdi/sdl.cpp +++ b/lib/gdi/sdl.cpp @@ -1,14 +1,15 @@ #include - +#include #include #include +#include +#include #include -gSDLDC::gSDLDC() +gSDLDC::gSDLDC() : m_pump(eApp, 1) { - if (SDL_Init(SDL_INIT_VIDEO) < 0) - { + if (SDL_Init(SDL_INIT_VIDEO) < 0) { eWarning("Could not initialize SDL: %s", SDL_GetError()); return; } @@ -18,48 +19,65 @@ gSDLDC::gSDLDC() CONNECT(m_pump.recv_msg, gSDLDC::pumpEvent); m_surface.type = 0; - m_surface.clut.colors=256; - m_surface.clut.data=new gRGB[m_surface.clut.colors]; - + m_surface.clut.colors = 256; + m_surface.clut.data = new gRGB[m_surface.clut.colors]; + m_pixmap = new gPixmap(&m_surface); - + memset(m_surface.clut.data, 0, sizeof(*m_surface.clut.data)*m_surface.clut.colors); + + run(); } gSDLDC::~gSDLDC() { + pushEvent(EV_QUIT); + kill(); SDL_Quit(); } -void gSDLDC::setPalette() +void gSDLDC::keyEvent(const SDL_Event &event) { - if (!m_surface.clut.data) - return; - -/* for (int i=0; i<256; ++i) - { - fb->CMAP()->red[i]=ramp[m_surface.clut.data[i].r]<<8; - fb->CMAP()->green[i]=ramp[m_surface.clut.data[i].g]<<8; - fb->CMAP()->blue[i]=ramp[m_surface.clut.data[i].b]<<8; - fb->CMAP()->transp[i]=rampalpha[m_surface.clut.data[i].a]<<8; - if (!fb->CMAP()->red[i]) - fb->CMAP()->red[i]=0x100; - } - fb->PutCMAP(); */ + eSDLInputDriver *driver = eSDLInputDriver::getInstance(); + + eDebug("SDL Key %s: key=%d", (event.type == SDL_KEYDOWN) ? "Down" : "Up", event.key.keysym.sym); + + if (driver) + driver->keyPressed(&event.key); } -void gSDLDC::exec(const gOpcode *o) +void gSDLDC::pumpEvent(const SDL_Event &event) { - switch (o->opcode) - { - case gOpcode::setPalette: - { - gDC::exec(o); - setPalette(); + switch (event.type) { + case SDL_KEYDOWN: + case SDL_KEYUP: + keyEvent(event); + break; + case SDL_QUIT: + eDebug("SDL Quit"); + extern void quitMainloop(int exit_code); + quitMainloop(0); break; } +} + +void gSDLDC::pushEvent(enum event code, void *data1, void *data2) +{ + SDL_Event event; + + event.type = SDL_USEREVENT; + event.user.code = code; + event.user.data1 = data1; + event.user.data2 = data2; + + SDL_PushEvent(&event); +} + +void gSDLDC::exec(const gOpcode *o) +{ + switch (o->opcode) { case gOpcode::flush: - SDL_Flip(m_screen); + pushEvent(EV_FLIP); eDebug("FLUSH"); break; default: @@ -69,11 +87,19 @@ void gSDLDC::exec(const gOpcode *o) } void gSDLDC::setResolution(int xres, int yres) +{ + pushEvent(EV_SET_VIDEO_MODE, (void *)xres, (void *)yres); +} + +/* + * SDL thread below... + */ + +void gSDLDC::evSetVideoMode(unsigned long xres, unsigned long yres) { m_screen = SDL_SetVideoMode(xres, yres, 32, SDL_HWSURFACE); - if (!m_screen) - { - eWarning("Could not create SDL surface: %s", SDL_GetError()); + if (!m_screen) { + eFatal("Could not create SDL surface: %s", SDL_GetError()); return; } @@ -83,6 +109,45 @@ void gSDLDC::setResolution(int xres, int yres) m_surface.bypp = m_screen->format->BytesPerPixel; m_surface.stride = m_screen->pitch; m_surface.data = m_screen->pixels; + + SDL_EnableUNICODE(1); +} + +void gSDLDC::evFlip() +{ + SDL_Flip(m_screen); +} + +void gSDLDC::thread() +{ + hasStarted(); + + bool stop = false; + while (!stop) { + SDL_Event event; + if (SDL_WaitEvent(&event)) { + switch (event.type) { + case SDL_KEYDOWN: + case SDL_KEYUP: + case SDL_QUIT: + m_pump.send(event); + break; + case SDL_USEREVENT: + switch (event.user.code) { + case EV_SET_VIDEO_MODE: + evSetVideoMode((unsigned long)event.user.data1, (unsigned long)event.user.data2); + break; + case EV_FLIP: + evFlip(); + break; + case EV_QUIT: + stop = true; + break; + } + break; + } + } + } } eAutoInitPtr init_gSDLDC(eAutoInitNumbers::graphic-1, "gSDLDC"); diff --git a/lib/gdi/sdl.h b/lib/gdi/sdl.h index 9f86cbbd..6d016cf9 100644 --- a/lib/gdi/sdl.h +++ b/lib/gdi/sdl.h @@ -1,21 +1,35 @@ #ifndef __lib_gdi_sdl_h #define __lib_gdi_sdl_h -#include "fb.h" -#include "gpixmap.h" -#include "gmaindc.h" +#include +#include #include -class gSDLDC: public gMainDC +class gSDLDC: public gMainDC, public eThread, public Object { +private: SDL_Surface *m_screen; void exec(const gOpcode *opcode); - void setPalette(); gSurface m_surface; + + eFixedMessagePump m_pump; + void keyEvent(const SDL_Event &event); + void pumpEvent(const SDL_Event &event); + virtual void thread(); + + enum event { + EV_SET_VIDEO_MODE, + EV_FLIP, + EV_QUIT, + }; + + void pushEvent(enum event code, void *data1 = 0, void *data2 = 0); + void evSetVideoMode(unsigned long xres, unsigned long yres); + void evFlip(); + public: - void setResolution(int xres, int yres); gSDLDC(); virtual ~gSDLDC(); -- 2.30.2