1 /**
2 * SDL mouse+keyboard test
3
4 * Copyright (C) 2007 Sylvain Beucler
5
6 * This file is part of GNU FreeDink
7
8 * GNU FreeDink is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 3 of the
11 * License, or (at your option) any later version.
12
13 * GNU FreeDink is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see
20 * <http://www.gnu.org/licenses/>.
21 */
22
23 /* Moves the cursor using either the mouse or the keyboard - the
24 program tries to keep the mouse under control (otherwise the mouse
25 may move out of the window and lose focus), and no jumps when
26 switching from mouse to keyboard or vice-versa. */
27
28 #include <stdio.h>
29 #include "SDL.h"
30
31 #define IMIN(a,b) ((a < b) ? a : b)
32 #define IMAX(a,b) ((a > b) ? a : b)
33
34 static int ignore_mouse_event = 0;
35
mouse_event_filter(const SDL_Event * event)36 int mouse_event_filter(const SDL_Event *event)
37 {
38 if (ignore_mouse_event && event->type == SDL_MOUSEMOTION)
39 {
40 printf("Filtered mouse event\n");
41 return 0;
42 }
43 return 1;
44 }
45
main(int argc,char * argv[])46 int main(int argc, char *argv[])
47 {
48 SDL_Surface *screen, *pic;
49 int quit = 0;
50 double px = 320, py = 240;
51 int mouse_dx = 0, mouse_dy = 0;
52 int keyboard_dx = 0, keyboard_dy = 0;
53 SDL_Rect dst = {320, 240};
54 Uint32 last_update = 0;
55 int mouse_speed = 200; /* pixels per second */
56
57 if (SDL_Init(SDL_INIT_VIDEO) < 0)
58 {
59 fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
60 exit(1);
61 }
62
63 putenv("SDL_VIDEO_CENTERED=1");
64 screen = SDL_SetVideoMode(640, 480, 0, SDL_HWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF | SDL_ANYFORMAT);
65 if (screen == NULL)
66 {
67 fprintf(stderr, "Couldn't set video mode: %s\n", SDL_GetError());
68 exit(1);
69 }
70 SDL_WM_SetCaption("MouseTest", NULL);
71 SDL_ShowCursor(SDL_DISABLE);
72
73 pic = SDL_LoadBMP("S08.bmp");
74 if (pic == NULL)
75 {
76 fprintf(stderr, "Failed to load image: %s\n", SDL_GetError());
77 exit(1);
78 }
79 SDL_SetColorKey(pic, SDL_SRCCOLORKEY, SDL_MapRGB(pic->format, 0, 0, 0));
80
81 /* Fill screen in white */
82 SDL_FillRect(screen, NULL,
83 SDL_MapRGB(screen->format, 0, 0, 255));
84 SDL_Flip(screen);
85
86
87 /* SDL_SetEventFilter(mouse_event_filter); */
88
89 /* Synchronize physical and game mouse */
90 {
91 int tmp_dx, tmp_dy;
92
93 ignore_mouse_event = 1;
94 SDL_WarpMouse(320, 240);
95 SDL_PumpEvents();
96 ignore_mouse_event = 0;
97 SDL_GetRelativeMouseState(&tmp_dx, &tmp_dy);
98 }
99
100 /* SDL_MouseMotionEvent: If the cursor is hidden (SDL_ShowCursor(0))
101 and the input is grabbed (SDL_WM_GrabInput(SDL_GRAB_ON)), then
102 the mouse will give relative motion events even when the cursor
103 reaches the edge of the screen. This is currently only
104 implemented on Windows and Linux/Unix-alikes. */
105 /* So it's not portable and it blocks Alt+Tab, so let's try
106 something else */
107 /* SDL_WM_GrabInput(SDL_GRAB_ON); */
108
109 last_update = SDL_GetTicks();
110
111 /* Main game loop */
112 while(!quit) {
113 SDL_Event event;
114 while (SDL_PollEvent(&event))
115 {
116 switch(event.type)
117 {
118 case SDL_KEYDOWN:
119 switch (event.key.keysym.sym)
120 {
121 case 'q':
122 case SDLK_ESCAPE:
123 quit = 1;
124 break;
125 case 'f':
126 SDL_WM_ToggleFullScreen(screen);
127 break;
128 case SDLK_LEFT:
129 keyboard_dx = -1;
130 break;
131 case SDLK_RIGHT:
132 keyboard_dx = 1;
133 break;
134 case SDLK_UP:
135 keyboard_dy = -1;
136 break;
137 case SDLK_DOWN:
138 keyboard_dy = 1;
139 break;
140 default:
141 break;
142 }
143 break;
144
145 case SDL_KEYUP:
146 switch (event.key.keysym.sym)
147 {
148 case SDLK_LEFT:
149 case SDLK_RIGHT:
150 keyboard_dx = 0;
151 break;
152 case SDLK_UP:
153 case SDLK_DOWN:
154 keyboard_dy = 0;
155 break;
156 default:
157 break;
158 }
159 break;
160
161 case SDL_ACTIVEEVENT:
162 {
163 SDL_ActiveEvent *active_event = (SDL_ActiveEvent*) &event;
164 if (active_event->state & SDL_APPMOUSEFOCUS)
165 {
166 /* mouse_focus = active_event->gain; */
167 printf("mouse event: %d\n", active_event->gain);
168 }
169 }
170 break;
171
172 case SDL_QUIT:
173 quit = 1;
174
175 break;
176 }
177 }
178
179 /* Update position - mouse event*/
180 {
181 /* SDL_GetMouseState(&mouse_x, &mouse_y); */
182 SDL_GetRelativeMouseState(&mouse_dx, &mouse_dy);
183 if (mouse_dx != 0 || mouse_dy != 0)
184 {
185 px += mouse_dx;
186 py += mouse_dy;
187
188 /* Clip */
189 if (px < 0) px = 0;
190 if (py < 0) py = 0;
191 if (px > 640 - 1) px = 640 - 1;
192 if (py > 480 - 1) py = 480 - 1;
193
194 /* Try to get the mouse (and the focus) within the window,
195 not 100% safe but good enough */
196 SDL_WarpMouse(320, 240);
197 /* Ignore the mouse event generated by SDL_WarpMouse: */
198 SDL_PumpEvents();
199 SDL_GetRelativeMouseState(NULL, NULL);
200 }
201 }
202
203 {
204 SDL_Rect erase, update;
205 int prev_x, prev_y;
206 double dx, dy;
207 int update_p1_x, update_p1_y;
208 int update_p2_x, update_p2_y;
209 Uint32 dt;
210
211 /* Check elapsed time since last frame */
212 dt = SDL_GetTicks() - last_update;
213 last_update = SDL_GetTicks();
214
215 /* Erase last position */
216 prev_x = dst.x;
217 prev_y = dst.y;
218 erase.x = prev_x;
219 erase.y = prev_y;
220 erase.w = pic->w;
221 erase.h = pic->h;
222 SDL_FillRect(screen, &erase,
223 SDL_MapRGB(screen->format, 0, 0, 255));
224
225
226 /* Update position - keyboard event */
227 dx = 1.0 * keyboard_dx * mouse_speed * dt / 1000;
228 dy = 1.0 * keyboard_dy * mouse_speed * dt / 1000;
229 px += dx;
230 py += dy;
231 dst.x = px;
232 dst.y = py;
233
234 /* Display new position */
235 SDL_BlitSurface(pic, NULL, screen, &dst);
236
237
238 /* What to refresh */
239 update_p1_x = IMIN(prev_x, dst.x);
240 update_p1_y = IMIN(prev_y, dst.y);
241 update_p2_x = IMAX(prev_x, dst.x) + pic->w;
242 update_p2_y = IMAX(prev_y, dst.y) + pic->h;
243
244 /* Clipping */
245 update_p1_x = IMIN(IMAX(update_p1_x, 0), screen->w);
246 update_p1_y = IMIN(IMAX(update_p1_y, 0), screen->h);
247 update_p2_x = IMIN(IMAX(update_p2_x, 0), screen->w);
248 update_p2_y = IMIN(IMAX(update_p2_y, 0), screen->h);
249
250 /* Refresh */
251 update.x = update_p1_x;
252 update.y = update_p1_y;
253 update.w = update_p2_x - update_p1_x;
254 update.h = update_p2_y - update_p1_y;
255 SDL_UpdateRects(screen, 1, &update);
256 /* printf("pos %f,%f\n", px, py); */
257 }
258 }
259 SDL_Quit();
260
261 return 0;
262 }
263