handle window focus to disable xsp
[drnoksnes] / platform / sdli.cpp
1 #include <SDL.h>
2 #include <math.h>
3
4 #include "platform.h"
5 #include "snes9x.h"
6 #include "display.h"
7
8 struct TouchButton {
9         unsigned short mask;
10         unsigned short x, y;
11         unsigned short x2, y2;
12         double fx, fy;
13         double fw, fh;
14 };
15
16 #define TOUCH_BUTTON_INITIALIZER(name, x, y, w, h) \
17         {SNES_##name##_MASK, 0, 0, 0, 0, x, y, w, h}
18
19 #define kCornerButtonWidth      (0.375)
20 #define kCornerButtonHeight     (0.0833333333334)
21 #define kBigButtonWidth         (0.125)
22 #define kBigButtonHeight        (0.2777777777778)
23
24 static TouchButton touchbuttons[] = {
25         TOUCH_BUTTON_INITIALIZER(TL, 0.0, 0.0, kCornerButtonWidth, kCornerButtonHeight),
26         TOUCH_BUTTON_INITIALIZER(TR, 0.625, 0.0, kCornerButtonWidth, kCornerButtonHeight),
27         TOUCH_BUTTON_INITIALIZER(UP, kBigButtonWidth, kCornerButtonHeight, kBigButtonWidth, kBigButtonHeight),
28         TOUCH_BUTTON_INITIALIZER(LEFT, 0.0, kCornerButtonHeight + kBigButtonHeight, kBigButtonWidth, kBigButtonHeight),
29         TOUCH_BUTTON_INITIALIZER(RIGHT, 2.0 * kBigButtonWidth, kCornerButtonHeight + kBigButtonHeight, kBigButtonWidth, kBigButtonHeight),
30         TOUCH_BUTTON_INITIALIZER(DOWN, kBigButtonWidth, 1.0 - (kCornerButtonHeight + kBigButtonHeight), kBigButtonWidth, kBigButtonHeight),
31         TOUCH_BUTTON_INITIALIZER(SELECT, 0.0, 1.0 - kCornerButtonHeight, kCornerButtonWidth, kCornerButtonHeight),
32         TOUCH_BUTTON_INITIALIZER(X, 1.0 - 2.0 * kBigButtonWidth, kCornerButtonHeight, kBigButtonWidth, kBigButtonHeight),
33         TOUCH_BUTTON_INITIALIZER(Y, 1.0 - 3.0 * kBigButtonWidth, kCornerButtonHeight + kBigButtonHeight, kBigButtonWidth, kBigButtonHeight),
34         TOUCH_BUTTON_INITIALIZER(A, 1.0 - kBigButtonWidth, kCornerButtonHeight + kBigButtonHeight, kBigButtonWidth, kBigButtonHeight),
35         TOUCH_BUTTON_INITIALIZER(B, 1.0 - 2.0 * kBigButtonWidth, 1.0 - (kCornerButtonHeight + kBigButtonHeight), kBigButtonWidth, kBigButtonHeight),
36         TOUCH_BUTTON_INITIALIZER(START, 1.0 - kCornerButtonWidth, 1.0 - kCornerButtonHeight, kCornerButtonWidth, kCornerButtonHeight),
37 };
38
39 static TouchButton* current = 0;
40
41 static uint32 joypads[2];
42 static struct {
43         unsigned x;
44         unsigned y;
45         bool enabled, pressed;
46 } mouse;
47
48 static TouchButton* getButtonFor(unsigned int x, unsigned int y) {
49         unsigned int i;
50
51         for (i = 0; i < sizeof(touchbuttons)/sizeof(TouchButton); i++) {
52                 if (x >= touchbuttons[i].x && x < touchbuttons[i].x2 &&
53                         y >= touchbuttons[i].y && y < touchbuttons[i].y2) {
54
55                         return &touchbuttons[i];
56                 }
57         }
58
59         return 0;
60 }
61
62 static inline void unpress(TouchButton* b) {
63         joypads[0] &= ~b->mask;
64 }
65 static inline void press(TouchButton* b) {
66         joypads[0] |= b->mask;
67 }
68
69 static void processMouse(unsigned int x, unsigned int y, int pressed = 0)
70 {
71         if (Config.touchscreenInput) {
72                 if (pressed < 0) {
73                         // Button up.
74                         if (current) {
75                                 // Leaving button
76                                 unpress(current);
77                                 current = 0;
78                         }
79                 } else {
80                         // Button down, or mouse motion.
81                         TouchButton* b = getButtonFor(x, y);
82                         if (current && b && current != b) {
83                                 // Moving from button to button
84                                 unpress(current);
85                                 current = b;
86                                 press(current);
87                         } else if (current && !b) {
88                                 // Leaving button
89                                 unpress(current);
90                                 current = 0;
91                         } else if (!current && b) {
92                                 // Entering button
93                                 current = b;
94                                 press(current);
95                         }
96                 }
97         } else if (mouse.enabled) {
98                 mouse.x = x;
99                 mouse.y = y;
100
101                 if (mouse.x < GUI.RenderX) mouse.x = 0;
102                 else {
103                         mouse.x -= GUI.RenderX;
104                         if (mouse.x > GUI.RenderW) mouse.x = GUI.RenderW;
105                 }
106
107                 if (mouse.y < GUI.RenderY) mouse.y = 0;
108                 else {
109                         mouse.y -= GUI.RenderY;
110                         if (mouse.y > GUI.RenderH) mouse.y = GUI.RenderH;
111                 }
112
113                 // Take care of scaling
114                 mouse.x /= GUI.Scale;
115                 mouse.y /= GUI.Scale;
116
117                 if (pressed > 0)
118                         mouse.pressed = true;
119                 else if (pressed < 0)
120                         mouse.pressed = false;
121         }
122 }
123
124 static void processEvent(const SDL_Event& event)
125 {
126         switch (event.type) 
127         {
128         case SDL_KEYDOWN:
129                 if (Config.action[event.key.keysym.scancode]) 
130                         S9xDoAction(Config.action[event.key.keysym.scancode]);
131                 joypads[0] |= Config.joypad1Mapping[event.key.keysym.scancode];
132                 break;
133         case SDL_KEYUP:
134                 joypads[0] &= ~Config.joypad1Mapping[event.key.keysym.scancode];
135                 break;
136         case SDL_MOUSEBUTTONUP:
137         case SDL_MOUSEBUTTONDOWN:
138                 processMouse(event.button.x, event.button.y,
139                                 (event.button.state == SDL_PRESSED) ? 1 : - 1);
140                 break;
141         case SDL_MOUSEMOTION:
142                 processMouse(event.motion.x, event.motion.y);
143                 break;
144         case SDL_ACTIVEEVENT:
145                 if (event.active.state & SDL_APPINPUTFOCUS) {
146                         S9xVideoOutputFocus(event.active.gain);
147                 }
148                 break;
149         case SDL_QUIT:
150                 Config.quitting = true;
151                 break;
152         }
153 }
154
155 uint32 S9xReadJoypad (int which)
156 {
157         if (which < 0 || which > 2) {
158                 return 0;
159         }
160
161         return joypads[which];
162 }
163
164 bool8 S9xReadMousePosition(int which1, int& x, int& y, uint32& buttons)
165 {
166         if (which1 != 0) return FALSE;
167
168         x = mouse.x;
169         y = mouse.y;
170         buttons = mouse.pressed ? 1 : 0;
171
172         return TRUE;
173 }
174
175 bool8 S9xReadSuperScopePosition(int& x, int& y, uint32& buttons)
176 {
177         x = mouse.x;
178         y = mouse.y;
179         buttons = mouse.pressed ? 8 : 0;
180
181         return TRUE;
182 }
183
184 void S9xProcessEvents(bool8_32 block)
185 {
186         SDL_Event event;
187
188         if (block) {
189                 SDL_WaitEvent(&event);
190                 processEvent(event);
191         } else {
192                 while(SDL_PollEvent(&event)) {
193                         processEvent(event);
194                 }
195         }
196 }
197
198 void S9xInitInputDevices()
199 {
200         joypads[0] = 0;
201         joypads[1] = 0;
202
203         switch (Settings.ControllerOption) {
204                 case SNES_JOYPAD:
205                         joypads[0] = 0x80000000UL;
206                         printf("Input: 1 joypad, keyboard only\n");
207                         break;
208                 case SNES_MOUSE:
209                         joypads[0] = 0x80000000UL;
210                         mouse.enabled = true;
211                         printf("Input: 1 joypad + mouse\n");
212                         break;
213                 case SNES_MOUSE_SWAPPED:
214                         printf("Input: mouse\n");
215                         mouse.enabled = true;
216                         break;
217                 case SNES_SUPERSCOPE:
218                         joypads[0] = 0x80000000UL;
219                         mouse.enabled = true;
220                         printf("Input: 1 joypad + superscope\n");
221                         break;
222                 default:
223                         printf("Input: unknown\n");
224                         break;
225         }
226
227         S9xInputScreenChanged();
228 }
229
230 void S9xDeinitInputDevices()
231 {
232
233 }
234
235 void S9xInputScreenChanged()
236 {
237         unsigned int i = 0;
238         const unsigned int w = GUI.Width, h = GUI.Height;
239         for (i = 0; i < sizeof(touchbuttons)/sizeof(TouchButton); i++) {
240                 touchbuttons[i].x = (unsigned int)(touchbuttons[i].fx * w);
241                 touchbuttons[i].y = (unsigned int)(touchbuttons[i].fy * h);
242                 touchbuttons[i].x2 = (unsigned int)(touchbuttons[i].x + touchbuttons[i].fw * w);
243                 touchbuttons[i].y2 = (unsigned int)(touchbuttons[i].y + touchbuttons[i].fh * h);
244         }
245 }
246
247 template <typename T>
248 static void drawControls(T * buffer, const int pitch)
249 {
250         unsigned int i = 0;
251         int x, y;
252         const T black = static_cast<T>(0xFFFFFFFFU);
253         T* temp;
254
255         for (i = 0; i < sizeof(touchbuttons)/sizeof(TouchButton); i++) {
256                 temp = buffer + touchbuttons[i].y * pitch + touchbuttons[i].x;
257                 for (x = touchbuttons[i].x; x < touchbuttons[i].x2; x++) {
258                         *temp = black;
259                         temp++;
260                 }
261                 temp = buffer + touchbuttons[i].y2 * pitch + touchbuttons[i].x;
262                 for (x = touchbuttons[i].x; x < touchbuttons[i].x2; x++) {
263                         *temp = black;
264                         temp++;
265                 }
266                 temp = buffer + touchbuttons[i].y * pitch + touchbuttons[i].x;
267                 for (y = touchbuttons[i].y; y < touchbuttons[i].y2; y++) {
268                         *temp = black;
269                         temp+=pitch;
270                 }
271                 temp = buffer + touchbuttons[i].y * pitch + touchbuttons[i].x2;
272                 for (y = touchbuttons[i].y; y < touchbuttons[i].y2; y++) {
273                         *temp = black;
274                         temp+=pitch;
275                 }
276         }
277 }
278
279 void S9xInputScreenDraw(int pixelSize, void * buffer, int pitch)
280 {
281         switch (pixelSize)
282         {
283                 case 1:
284                         drawControls(reinterpret_cast<uint8*>(buffer), pitch);
285                         break;
286                 case 2:
287                         drawControls(reinterpret_cast<uint16*>(buffer), pitch / 2);
288                         break;
289         }
290 }
291