SDL: add input support, use SDL mainloop in a thread
authorAndreas Oberritter <obi@opendreambox.org>
Wed, 3 Nov 2010 18:27:17 +0000 (19:27 +0100)
committerAndreas Oberritter <obi@opendreambox.org>
Tue, 16 Nov 2010 16:15:38 +0000 (17:15 +0100)
lib/driver/Makefile.am
lib/driver/rcsdl.cpp [new file with mode: 0644]
lib/driver/rcsdl.h [new file with mode: 0644]
lib/gdi/sdl.cpp
lib/gdi/sdl.h

index 88d9bec5418d94b293553e4e8fef9a2829a078ed..b498a6c829fd8ecbee6dc3a5e56e8439f66a909f 100644 (file)
@@ -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 (file)
index 0000000..a907b80
--- /dev/null
@@ -0,0 +1,390 @@
+#include <lib/driver/rcsdl.h>
+//#include <lib/actions/action.h>
+#include <lib/base/init.h>
+#include <lib/base/init_num.h>
+#include <lib/driver/input_fake.h>
+
+/*
+ * 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<eRCDevice*>::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<eRCSDLInit> init_rcSDL(eAutoInitNumbers::rc+1, "SDL RC Driver");
diff --git a/lib/driver/rcsdl.h b/lib/driver/rcsdl.h
new file mode 100644 (file)
index 0000000..9732f5e
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __lib_driver_rcsdl_h
+#define __lib_driver_rcsdl_h
+
+#include <lib/driver/rc.h>
+
+#include <SDL.h>
+
+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
index e816a185c7541a5ff2f15ad14b6f9a1b2f61bbd7..eb4e2ae48e78635c35adc5a81039ba4c694b3554 100644 (file)
@@ -1,14 +1,15 @@
 #include <lib/gdi/sdl.h>
-
+#include <lib/actions/action.h>
 #include <lib/base/init.h>
 #include <lib/base/init_num.h>
+#include <lib/driver/input_fake.h>
+#include <lib/driver/rcsdl.h>
 
 #include <SDL.h>
 
-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<gSDLDC> init_gSDLDC(eAutoInitNumbers::graphic-1, "gSDLDC");
index 9f86cbbde5d8a02bd194e152431425fe1e32b748..6d016cf9725cdd5f0366495e9326a2c306ad0793 100644 (file)
@@ -1,21 +1,35 @@
 #ifndef __lib_gdi_sdl_h
 #define __lib_gdi_sdl_h
 
-#include "fb.h"
-#include "gpixmap.h"
-#include "gmaindc.h"
+#include <lib/base/thread.h>
+#include <lib/gdi/gmaindc.h>
 
 #include <SDL.h>
 
-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<SDL_Event> 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();