Mercurial > sdl-ios-xcode
comparison src/video/quartz/SDL_QuartzWM.m @ 563:04dcaf3da918
Massive Quartz input enhancements from Darrell Walisser. His email:
Enclosed is a patch that addresses the following:
--Various minor cleanups.
Removed dead/obsolete code, made some style cleanups
--Mouse Events
Now keep track of what button(s) were pressed so we know when to send
the mouse up event. This fixes the case where the mouse is dragged
outside of the game window and released (in which case we want to send
the mouse up event even though the mouse is outside the game window).
--Input Grabbing
Here is my take on the grabbing situation, which is the basis for the
new implementation.
There are 3 grab states, ungrabbed (UG), visible (VG), and invisible
(IG). Both VG and IG keep the mouse constrained to the window and
produce relative motion events. In VG the cursor is visible (duh), in
IG it is not. In VG, absolute motion events also work.
There are 6 actions that can affect grabbing:
1. Set Fullscreen/Window (F/W). In fullscreen, a visible grab should do
nothing. However, a fullscreen visible grab can be treated just like a
windowed visible grab, which is what I have done to help simplify
things.
2. Cursor hide/show (H/S). If the cursor is hidden when grabbing, the
grab is an invisible grab. If the cursor is visible, the grab should
just constrain the mouse to the window.
3. Input grab/ungrab(G/U). If grabbed, the cursor should be confined to
the window as should the keyboard input. On Mac OS X, the keyboard
input is implicitly grabbed by confining the cursor, except for
command-tab which can switch away from the application. Should the
window come to the foreground if the application is deactivated and
grab input is called? This isn't necessary in this implementation
because the grab state will be asserted upon activation.
Using my notation, these are all the cases that need to be handled
(state + action = new state).
UG+U = UG
UG+G = VG or IG, if cursor is visible or not
UG+H = UG
UG+S = UG
VG+U = UG
VG+G = VG
VG+H = IG
VG+S = VG
IG+U = UG
IG+G = IG
IG+H = IG
IG+S = VG
The cases that result in the same state can be ignored in the code,
which cuts it down to just 5 cases.
Another issue is what happens when the app loses/gains input focus from
deactivate/activate or iconify/deiconify. I think that if input focus
is ever lost (outside of SDL's control), the grab state should be
suspended and the cursor should become visible and active again. When
regained, the cursor should reappear in its original location and/or
grab state. This way, when reactivating the cursor is still in the same
position as before so apps shouldn't get confused when the next motion
event comes in. This is what I've done in this patch.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Fri, 27 Dec 2002 20:52:41 +0000 |
parents | 74262d2647ca |
children | 1970e458070d |
comparison
equal
deleted
inserted
replaced
562:cb40b26523a5 | 563:04dcaf3da918 |
---|---|
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | 18 |
19 Sam Lantinga | 19 Sam Lantinga |
20 slouken@libsdl.org | 20 slouken@libsdl.org |
21 */ | 21 */ |
22 | |
23 static void QZ_ChangeGrabState (_THIS, int action); | |
22 | 24 |
23 struct WMcursor { | 25 struct WMcursor { |
24 Cursor curs; | 26 Cursor curs; |
25 }; | 27 }; |
26 | 28 |
64 cursor->curs.hotSpot.v = hot_y; | 66 cursor->curs.hotSpot.v = hot_y; |
65 | 67 |
66 return(cursor); | 68 return(cursor); |
67 } | 69 } |
68 | 70 |
69 static int QZ_cursor_visible = 1; | |
70 | |
71 static int QZ_ShowWMCursor (_THIS, WMcursor *cursor) { | 71 static int QZ_ShowWMCursor (_THIS, WMcursor *cursor) { |
72 | 72 |
73 if ( cursor == NULL) { | 73 if ( cursor == NULL) { |
74 if ( QZ_cursor_visible ) { | 74 if ( cursor_visible ) { |
75 HideCursor (); | 75 HideCursor (); |
76 QZ_cursor_visible = 0; | 76 cursor_visible = NO; |
77 QZ_ChangeGrabState (this, QZ_HIDECURSOR); | |
77 } | 78 } |
78 } | 79 } |
79 else { | 80 else { |
80 SetCursor(&cursor->curs); | 81 SetCursor(&cursor->curs); |
81 if ( ! QZ_cursor_visible ) { | 82 if ( ! cursor_visible ) { |
82 ShowCursor (); | 83 ShowCursor (); |
83 QZ_cursor_visible = 1; | 84 cursor_visible = YES; |
85 QZ_ChangeGrabState (this, QZ_SHOWCURSOR); | |
84 } | 86 } |
85 } | 87 } |
86 | 88 |
87 return 1; | 89 return 1; |
88 } | 90 } |
124 | 126 |
125 height -= 22; | 127 height -= 22; |
126 } | 128 } |
127 } | 129 } |
128 | 130 |
129 p->y = height - p->y; | 131 p->y = height - p->y - 1; |
130 } | 132 } |
131 | 133 |
132 /* Convert Cocoa coordinate to SDL coordinate */ | 134 /* Convert Cocoa coordinate to SDL coordinate */ |
133 static void QZ_PrivateCocoaToSDL (_THIS, NSPoint *p) { | 135 static void QZ_PrivateCocoaToSDL (_THIS, NSPoint *p) { |
134 | 136 |
177 | 179 |
178 NSPoint p; | 180 NSPoint p; |
179 CGPoint cgp; | 181 CGPoint cgp; |
180 | 182 |
181 p = NSMakePoint (x, y); | 183 p = NSMakePoint (x, y); |
182 cgp = QZ_PrivateSDLToCG (this, &p); | 184 cgp = QZ_PrivateSDLToCG (this, &p); |
183 CGDisplayMoveCursorToPoint (display_id, cgp); | 185 QZ_PrivateCGToSDL (this, &p); |
184 warp_ticks = SDL_GetTicks(); | 186 |
185 warp_flag = 1; | 187 /* this is the magic call that fixes cursor "freezing" after warp */ |
186 | 188 CGSetLocalEventsSuppressionInterval (0.0); |
187 SDL_PrivateMouseMotion(0, 0, x, y); | 189 CGWarpMouseCursorPosition (cgp); |
188 } | 190 } |
189 | 191 |
190 static void QZ_WarpWMCursor (_THIS, Uint16 x, Uint16 y) { | 192 static void QZ_WarpWMCursor (_THIS, Uint16 x, Uint16 y) { |
191 | 193 |
192 /* Only allow warping when in foreground */ | 194 /* Only allow warping when in foreground */ |
193 if ( ! in_foreground ) | 195 if ( ! in_foreground ) |
194 return; | 196 return; |
195 | 197 |
196 /* Do the actual warp */ | 198 /* Do the actual warp */ |
197 QZ_PrivateWarpCursor (this, x, y); | 199 QZ_PrivateWarpCursor (this, x, y); |
200 | |
201 /* Generate the mouse moved event */ | |
202 SDL_PrivateMouseMotion (0, 0, x, y); | |
198 } | 203 } |
199 | 204 |
200 static void QZ_MoveWMCursor (_THIS, int x, int y) { } | 205 static void QZ_MoveWMCursor (_THIS, int x, int y) { } |
201 static void QZ_CheckMouseMode (_THIS) { } | 206 static void QZ_CheckMouseMode (_THIS) { } |
202 | 207 |
287 static int QZ_GetWMInfo (_THIS, SDL_SysWMinfo *info) { | 292 static int QZ_GetWMInfo (_THIS, SDL_SysWMinfo *info) { |
288 info->nsWindowPtr = qz_window; | 293 info->nsWindowPtr = qz_window; |
289 return 0; | 294 return 0; |
290 }*/ | 295 }*/ |
291 | 296 |
297 static void QZ_ChangeGrabState (_THIS, int action) { | |
298 | |
299 /* | |
300 Figure out what the next state should be based on the action. | |
301 Ignore actions that can't change the current state. | |
302 */ | |
303 if ( grab_state == QZ_UNGRABBED ) { | |
304 if ( action == QZ_ENABLE_GRAB ) { | |
305 if ( cursor_visible ) | |
306 grab_state = QZ_VISIBLE_GRAB; | |
307 else | |
308 grab_state = QZ_INVISIBLE_GRAB; | |
309 } | |
310 } | |
311 else if ( grab_state == QZ_VISIBLE_GRAB ) { | |
312 if ( action == QZ_DISABLE_GRAB ) | |
313 grab_state = QZ_UNGRABBED; | |
314 else if ( action == QZ_HIDECURSOR ) | |
315 grab_state = QZ_INVISIBLE_GRAB; | |
316 } | |
317 else { | |
318 assert( grab_state == QZ_INVISIBLE_GRAB ); | |
319 | |
320 if ( action == QZ_DISABLE_GRAB ) | |
321 grab_state = QZ_UNGRABBED; | |
322 else if ( action == QZ_SHOWCURSOR ) | |
323 grab_state = QZ_VISIBLE_GRAB; | |
324 } | |
325 | |
326 /* now apply the new state */ | |
327 if (grab_state == QZ_UNGRABBED) { | |
328 | |
329 CGAssociateMouseAndMouseCursorPosition (1); | |
330 } | |
331 else if (grab_state == QZ_VISIBLE_GRAB) { | |
332 | |
333 CGAssociateMouseAndMouseCursorPosition (1); | |
334 } | |
335 else { | |
336 assert( grab_state == QZ_INVISIBLE_GRAB ); | |
337 | |
338 QZ_PrivateWarpCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2); | |
339 CGAssociateMouseAndMouseCursorPosition (0); | |
340 } | |
341 } | |
342 | |
292 static SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode) { | 343 static SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode) { |
293 | 344 |
294 switch (grab_mode) { | 345 int doGrab = grab_mode & SDL_GRAB_ON; |
295 case SDL_GRAB_QUERY: | 346 /*int fullscreen = grab_mode & SDL_GRAB_FULLSCREEN;*/ |
296 break; | 347 |
297 case SDL_GRAB_OFF: | 348 if ( this->screen == NULL ) { |
298 CGAssociateMouseAndMouseCursorPosition (1); | 349 SDL_SetError ("QZ_GrabInput: screen is NULL"); |
299 current_grab_mode = SDL_GRAB_OFF; | 350 return SDL_GRAB_OFF; |
300 break; | 351 } |
301 case SDL_GRAB_ON: | 352 |
302 QZ_WarpWMCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2); | 353 if ( ! video_set ) { |
303 CGAssociateMouseAndMouseCursorPosition (0); | 354 /*SDL_SetError ("QZ_GrabInput: video is not set, grab will take effect on mode switch"); */ |
304 current_grab_mode = SDL_GRAB_ON; | 355 current_grab_mode = grab_mode; |
305 break; | 356 return grab_mode; /* Will be set later on mode switch */ |
306 case SDL_GRAB_FULLSCREEN: | 357 } |
307 break; | 358 |
308 } | 359 if ( grab_mode != SDL_GRAB_QUERY ) { |
309 | 360 if ( doGrab ) |
361 QZ_ChangeGrabState (this, QZ_ENABLE_GRAB); | |
362 else | |
363 QZ_ChangeGrabState (this, QZ_DISABLE_GRAB); | |
364 | |
365 current_grab_mode = doGrab ? SDL_GRAB_ON : SDL_GRAB_OFF; | |
366 } | |
367 | |
310 return current_grab_mode; | 368 return current_grab_mode; |
311 } | 369 } |
312 | 370 |
313 /* Resize icon, BMP format */ | 371 /* Resize icon, BMP format */ |
314 static unsigned char QZ_ResizeIcon[] = { | 372 static unsigned char QZ_ResizeIcon[] = { |