add multitouch fixes
[drnoksnes] / platform / sdli.cpp
index 86b3223..3e0a118 100644 (file)
@@ -3,7 +3,15 @@
 
 #include "platform.h"
 #include "snes9x.h"
-#include "display.h"
+#include "sdlv.h" // Dispatching video-related events
+
+#if CONF_ZEEMOTE
+#include "zeemote.h"
+#endif
+
+#if !defined(SDL_MAXMOUSE)
+#define SDL_MAXMOUSE 1
+#endif
 
 struct TouchButton {
        unsigned short mask;
@@ -13,30 +21,36 @@ struct TouchButton {
        double fw, fh;
 };
 
-#define TOUCH_BUTTON_INITIALIZER(name, x, y, w, h) \
-       {SNES_##name##_MASK, 0, 0, 0, 0, x, y, w, h}
-
 #define kCornerButtonWidth     (0.375)
 #define kCornerButtonHeight    (0.0833333333334)
 #define kBigButtonWidth                (0.125)
 #define kBigButtonHeight       (0.2777777777778)
 
 static TouchButton touchbuttons[] = {
-       TOUCH_BUTTON_INITIALIZER(TL, 0.0, 0.0, kCornerButtonWidth, kCornerButtonHeight),
-       TOUCH_BUTTON_INITIALIZER(TR, 0.625, 0.0, kCornerButtonWidth, kCornerButtonHeight),
-       TOUCH_BUTTON_INITIALIZER(UP, kBigButtonWidth, kCornerButtonHeight, kBigButtonWidth, kBigButtonHeight),
-       TOUCH_BUTTON_INITIALIZER(LEFT, 0.0, kCornerButtonHeight + kBigButtonHeight, kBigButtonWidth, kBigButtonHeight),
-       TOUCH_BUTTON_INITIALIZER(RIGHT, 2.0 * kBigButtonWidth, kCornerButtonHeight + kBigButtonHeight, kBigButtonWidth, kBigButtonHeight),
-       TOUCH_BUTTON_INITIALIZER(DOWN, kBigButtonWidth, 1.0 - (kCornerButtonHeight + kBigButtonHeight), kBigButtonWidth, kBigButtonHeight),
-       TOUCH_BUTTON_INITIALIZER(SELECT, 0.0, 1.0 - kCornerButtonHeight, kCornerButtonWidth, kCornerButtonHeight),
-       TOUCH_BUTTON_INITIALIZER(X, 1.0 - 2.0 * kBigButtonWidth, kCornerButtonHeight, kBigButtonWidth, kBigButtonHeight),
-       TOUCH_BUTTON_INITIALIZER(Y, 1.0 - 3.0 * kBigButtonWidth, kCornerButtonHeight + kBigButtonHeight, kBigButtonWidth, kBigButtonHeight),
-       TOUCH_BUTTON_INITIALIZER(A, 1.0 - kBigButtonWidth, kCornerButtonHeight + kBigButtonHeight, kBigButtonWidth, kBigButtonHeight),
-       TOUCH_BUTTON_INITIALIZER(B, 1.0 - 2.0 * kBigButtonWidth, 1.0 - (kCornerButtonHeight + kBigButtonHeight), kBigButtonWidth, kBigButtonHeight),
-       TOUCH_BUTTON_INITIALIZER(START, 1.0 - kCornerButtonWidth, 1.0 - kCornerButtonHeight, kCornerButtonWidth, kCornerButtonHeight),
+#define TB(actions, x, y, w, h) \
+       {actions, 0, 0, 0, 0, x, y, w, h}
+#define P(x) SNES_##x##_MASK
+       TB(P(TL), 0.0, 0.0, kCornerButtonWidth, kCornerButtonHeight),
+       TB(P(TR), 0.625, 0.0, kCornerButtonWidth, kCornerButtonHeight),
+       TB(P(LEFT) | P(UP), 0.0, kCornerButtonHeight, kBigButtonWidth, kBigButtonHeight),
+       TB(P(UP), kBigButtonWidth, kCornerButtonHeight, kBigButtonWidth, kBigButtonHeight),
+       TB(P(RIGHT) | P(UP), 2.0 * kBigButtonWidth, kCornerButtonHeight, kBigButtonWidth, kBigButtonHeight),
+       TB(P(LEFT), 0.0, kCornerButtonHeight + kBigButtonHeight, kBigButtonWidth, kBigButtonHeight),
+       TB(P(RIGHT), 2.0 * kBigButtonWidth, kCornerButtonHeight + kBigButtonHeight, kBigButtonWidth, kBigButtonHeight),
+       TB(P(LEFT) | P(DOWN), 0, 1.0 - (kCornerButtonHeight + kBigButtonHeight), kBigButtonWidth, kBigButtonHeight),
+       TB(P(DOWN), kBigButtonWidth, 1.0 - (kCornerButtonHeight + kBigButtonHeight), kBigButtonWidth, kBigButtonHeight),
+       TB(P(RIGHT) | P(DOWN), 2.0 * kBigButtonWidth, 1.0 - (kCornerButtonHeight + kBigButtonHeight), kBigButtonWidth, kBigButtonHeight),
+       TB(P(SELECT), 0.0, 1.0 - kCornerButtonHeight, kCornerButtonWidth, kCornerButtonHeight),
+       TB(P(X), 1.0 - 2.0 * kBigButtonWidth, kCornerButtonHeight, kBigButtonWidth, kBigButtonHeight),
+       TB(P(Y), 1.0 - 3.0 * kBigButtonWidth, kCornerButtonHeight + kBigButtonHeight, kBigButtonWidth, kBigButtonHeight),
+       TB(P(A), 1.0 - kBigButtonWidth, kCornerButtonHeight + kBigButtonHeight, kBigButtonWidth, kBigButtonHeight),
+       TB(P(B), 1.0 - 2.0 * kBigButtonWidth, 1.0 - (kCornerButtonHeight + kBigButtonHeight), kBigButtonWidth, kBigButtonHeight),
+       TB(P(START), 1.0 - kCornerButtonWidth, 1.0 - kCornerButtonHeight, kCornerButtonWidth, kCornerButtonHeight),
+#undef P
+#undef TB
 };
 
-static TouchButton* current = 0;
+static TouchButton* current[SDL_MAXMOUSE] = { 0 };
 
 static uint32 joypads[2];
 static struct {
@@ -60,38 +74,45 @@ static TouchButton* getButtonFor(unsigned int x, unsigned int y) {
 }
 
 static inline void unpress(TouchButton* b) {
-       joypads[0] &= ~b->mask;
+       joypads[Config.touchscreenInput - 1] &= ~b->mask;
 }
 static inline void press(TouchButton* b) {
-       joypads[0] |= b->mask;
+       joypads[Config.touchscreenInput - 1] |= b->mask;
 }
 
-static void processMouse(unsigned int x, unsigned int y, int pressed = 0)
+static void processMouse(int which, unsigned int x, unsigned int y, int pressed = 0)
 {
+#if CONF_EXIT_BUTTON
+       /* no fullscreen escape button, we have to simulate one! */
+       /* TODO: don't hardcode sizes */
+       if (Config.fullscreen && x > (800 - 100) && y < 50 && pressed > 0) {
+               S9xDoAction(kActionQuit);
+       }
+#endif
        if (Config.touchscreenInput) {
                if (pressed < 0) {
                        // Button up.
-                       if (current) {
+                       if (current[which]) {
                                // Leaving button
-                               unpress(current);
-                               current = 0;
+                               unpress(current[which]);
+                               current[which] = 0;
                        }
                } else {
                        // Button down, or mouse motion.
                        TouchButton* b = getButtonFor(x, y);
-                       if (current && b && current != b) {
+                       if (current[which] && b && current[which] != b) {
                                // Moving from button to button
-                               unpress(current);
-                               current = b;
-                               press(current);
-                       } else if (current && !b) {
+                               unpress(current[which]);
+                               current[which] = b;
+                               press(current[which]);
+                       } else if (current[which] && !b) {
                                // Leaving button
-                               unpress(current);
-                               current = 0;
-                       } else if (!current && b) {
+                               unpress(current[which]);
+                               current[which] = 0;
+                       } else if (!current[which] && b) {
                                // Entering button
-                               current = b;
-                               press(current);
+                               current[which] = b;
+                               press(current[which]);
                        }
                }
        } else if (mouse.enabled) {
@@ -110,9 +131,10 @@ static void processMouse(unsigned int x, unsigned int y, int pressed = 0)
                        if (mouse.y > GUI.RenderH) mouse.y = GUI.RenderH;
                }
 
-               // Take care of scaling
-               mouse.x /= GUI.ScaleX;
-               mouse.y /= GUI.ScaleY;
+               // mouse.{x,y} are system coordinates.
+               // Scale them to emulated screen coordinates.
+               mouse.x = static_cast<unsigned int>(mouse.x / GUI.ScaleX);
+               mouse.y = static_cast<unsigned int>(mouse.y / GUI.ScaleY);
 
                if (pressed > 0)
                        mouse.pressed = true;
@@ -123,68 +145,90 @@ static void processMouse(unsigned int x, unsigned int y, int pressed = 0)
 
 static void processEvent(const SDL_Event& event)
 {
+       if (videoEventFilter(event)) return;
+
        switch (event.type) 
        {
-       case SDL_KEYDOWN:
-               if (Config.action[event.key.keysym.scancode]) 
-                       S9xDoAction(Config.action[event.key.keysym.scancode]);
-               joypads[0] |= Config.joypad1Mapping[event.key.keysym.scancode];
-               break;
-       case SDL_KEYUP:
-               joypads[0] &= ~Config.joypad1Mapping[event.key.keysym.scancode];
-               break;
-       case SDL_MOUSEBUTTONUP:
-       case SDL_MOUSEBUTTONDOWN:
-               processMouse(event.button.x, event.button.y,
-                               (event.button.state == SDL_PRESSED) ? 1 : - 1);
-               break;
-       case SDL_MOUSEMOTION:
-               processMouse(event.motion.x, event.motion.y);
-               break;
-       case SDL_ACTIVEEVENT:
-               if (event.active.state & SDL_APPINPUTFOCUS) {
-                       S9xVideoOutputFocus(event.active.gain);
-               }
-               break;
-       case SDL_QUIT:
-               Config.quitting = true;
-               break;
+               case SDL_KEYDOWN:
+                       if (Config.action[event.key.keysym.scancode]) 
+                               S9xDoAction(Config.action[event.key.keysym.scancode]);
+                       joypads[0] |= Config.joypad1Mapping[event.key.keysym.scancode];
+                       joypads[1] |= Config.joypad2Mapping[event.key.keysym.scancode];
+                       break;
+               case SDL_KEYUP:
+                       joypads[0] &= ~Config.joypad1Mapping[event.key.keysym.scancode];
+                       joypads[1] &= ~Config.joypad2Mapping[event.key.keysym.scancode];
+                       break;
+               case SDL_MOUSEBUTTONUP:
+               case SDL_MOUSEBUTTONDOWN:
+                       processMouse(event.button.which, event.button.x, event.button.y,
+                                       (event.button.state == SDL_PRESSED) ? 1 : - 1);
+                       break;
+               case SDL_MOUSEMOTION:
+                       processMouse(event.button.which, event.motion.x, event.motion.y);
+                       break;
+               case SDL_QUIT:
+                       Config.quitting = true;
+                       break;
        }
 }
 
+/** This function is called to return a bit-wise mask of the state of one of the
+       five emulated SNES controllers.
+
+       @return 0 if you're not supporting controllers past a certain number or
+               return the mask representing the current state of the controller number
+               passed as a parameter or'ed with 0x80000000.
+*/
+
 uint32 S9xReadJoypad (int which)
 {
-       if (which < 0 || which > 2) {
+       if (which < 0 || which >= 2) {
+               // More joypads that we currently handle (could happen if bad conf)
                return 0;
        }
 
        return joypads[which];
 }
 
-bool8 S9xReadMousePosition(int which1, int& x, int& y, uint32& buttons)
+/** Get the current position of the host pointing device, usually a mouse,
+       used to emulated the SNES mouse.
+
+       @param buttons The buttons return value is a bit-wise mask of the two SNES
+               mouse buttons, bit 0 for button 1 (left) and bit 1 for button 2 (right).
+*/
+bool8 S9xReadMousePosition(int which, int *x, int *y, uint32 *buttons)
 {
-       if (which1 != 0) return FALSE;
+       if (which != 0) return FALSE;
 
-       x = mouse.x;
-       y = mouse.y;
-       buttons = mouse.pressed ? 1 : 0;
+       *x = mouse.x;
+       *y = mouse.y;
+       *buttons = mouse.pressed ? 1 : 0;
 
        return TRUE;
 }
 
-bool8 S9xReadSuperScopePosition(int& x, int& y, uint32& buttons)
+bool8 S9xReadSuperScopePosition(int *x, int *y, uint32 *buttons)
 {
-       x = mouse.x;
-       y = mouse.y;
-       buttons = mouse.pressed ? 8 : 0;
+       *x = mouse.x;
+       *y = mouse.y;
+       *buttons = mouse.pressed ? 8 : 0;
 
        return TRUE;
 }
 
-void S9xProcessEvents(bool8_32 block)
+/** Get and process system/input events.
+       @param block true to block, false to poll until the queue is empty.
+*/
+void S9xProcessEvents(bool block)
 {
        SDL_Event event;
 
+#if CONF_ZEEMOTE
+       // Wheter blocking or non blocking, poll zeemotes now.
+       ZeeRead(joypads);
+#endif
+
        if (block) {
                SDL_WaitEvent(&event);
                processEvent(event);
@@ -199,37 +243,48 @@ void S9xInitInputDevices()
 {
        joypads[0] = 0;
        joypads[1] = 0;
+       mouse.enabled = false;
+       mouse.pressed = false;
 
-       switch (Settings.ControllerOption) {
-               case SNES_JOYPAD:
-                       joypads[0] = 0x80000000UL;
-                       printf("Input: 1 joypad, keyboard only\n");
-                       break;
-               case SNES_MOUSE:
-                       joypads[0] = 0x80000000UL;
-                       mouse.enabled = true;
-                       printf("Input: 1 joypad + mouse\n");
-                       break;
-               case SNES_MOUSE_SWAPPED:
-                       printf("Input: mouse\n");
-                       mouse.enabled = true;
-                       break;
-               case SNES_SUPERSCOPE:
-                       joypads[0] = 0x80000000UL;
-                       mouse.enabled = true;
-                       printf("Input: 1 joypad + superscope\n");
-                       break;
-               default:
-                       printf("Input: unknown\n");
-                       break;
+#if CONF_ZEEMOTE
+       ZeeInit();
+#endif
+
+       if (Config.joypad1Enabled) {
+               joypads[0] = 0x80000000UL;
+       }
+       if (Config.joypad2Enabled) {
+               joypads[1] = 0x80000000UL;
+       }
+
+       // Pretty print some information
+       printf("Input: ");
+       if (Config.joypad1Enabled) {
+               printf("Player 1 (joypad)");
+               if (Config.joypad2Enabled) {
+                       printf("+ player 2 (joypad)");
+               }
+       } else if (Config.joypad2Enabled) {
+               printf("Player 2 (joypad)");
+       } else {
+               printf("Nothing");
        }
+       printf("\n");
+
+       // TODO Non-awful mouse & superscope support
 
        S9xInputScreenChanged();
 }
 
 void S9xDeinitInputDevices()
 {
-
+#if CONF_ZEEMOTE
+       ZeeQuit();
+#endif
+       joypads[0] = 0;
+       joypads[1] = 0;
+       mouse.enabled = false;
+       mouse.pressed = false;
 }
 
 void S9xInputScreenChanged()
@@ -276,16 +331,8 @@ static void drawControls(T * buffer, const int pitch)
        }
 }
 
-void S9xInputScreenDraw(int pixelSize, void * buffer, int pitch)
+void S9xInputScreenDraw(void * buffer, int pitch)
 {
-       switch (pixelSize)
-       {
-               case 1:
-                       drawControls(reinterpret_cast<uint8*>(buffer), pitch);
-                       break;
-               case 2:
-                       drawControls(reinterpret_cast<uint16*>(buffer), pitch / 2);
-                       break;
-       }
+       drawControls(reinterpret_cast<uint16*>(buffer), pitch / 2);
 }