src/video/wincommon/SDL_sysevents.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 10 Apr 2002 02:14:33 +0000
changeset 335 bc4d50d2edd9
parent 333 f2ba51f64d49
child 338 518ffd98a8f6
permissions -rw-r--r--
*** empty log message ***
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999  Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 #include <stdlib.h>
    29 #include <stdio.h>
    30 #include <windows.h>
    31 
    32 #include "SDL_getenv.h"
    33 #include "SDL_events.h"
    34 #include "SDL_video.h"
    35 #include "SDL_error.h"
    36 #include "SDL_syswm.h"
    37 #include "SDL_sysevents.h"
    38 #include "SDL_events_c.h"
    39 #include "SDL_sysvideo.h"
    40 #include "SDL_lowvideo.h"
    41 #include "SDL_syswm_c.h"
    42 #include "SDL_main.h"
    43 
    44 #ifdef WMMSG_DEBUG
    45 #include "wmmsg.h"
    46 #endif
    47 
    48 #ifdef _WIN32_WCE
    49 #define NO_GETKEYBOARDSTATE
    50 #endif
    51 
    52 /* The window we use for everything... */
    53 const char *SDL_Appname = NULL;
    54 HINSTANCE SDL_Instance = NULL;
    55 HWND SDL_Window = NULL;
    56 RECT SDL_bounds = {0, 0, 0, 0};
    57 int SDL_resizing = 0;
    58 int mouse_relative = 0;
    59 int posted = 0;
    60 #ifndef NO_CHANGEDISPLAYSETTINGS
    61 DEVMODE SDL_fullscreen_mode;
    62 #endif
    63 
    64 
    65 /* Functions called by the message processing function */
    66 LONG
    67 (*HandleMessage)(_THIS, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)=NULL;
    68 void (*WIN_RealizePalette)(_THIS);
    69 void (*WIN_PaletteChanged)(_THIS, HWND window);
    70 void (*WIN_SwapGamma)(_THIS);
    71 void (*WIN_WinPAINT)(_THIS, HDC hdc);
    72 
    73 static void SDL_RestoreGameMode(void)
    74 {
    75 #ifndef NO_CHANGEDISPLAYSETTINGS
    76 	ShowWindow(SDL_Window, SW_RESTORE);
    77 	ChangeDisplaySettings(&SDL_fullscreen_mode, CDS_FULLSCREEN);
    78 #endif
    79 }
    80 static void SDL_RestoreDesktopMode(void)
    81 {
    82 #ifndef NO_CHANGEDISPLAYSETTINGS
    83 	ShowWindow(SDL_Window, SW_MINIMIZE);
    84 	ChangeDisplaySettings(NULL, 0);
    85 #endif
    86 }
    87 
    88 #ifdef WM_MOUSELEAVE
    89 /* 
    90    Special code to handle mouse leave events - this sucks...
    91    http://support.microsoft.com/support/kb/articles/q183/1/07.asp
    92 
    93    TrackMouseEvent() is only available on Win98 and WinNT.
    94    _TrackMouseEvent() is available on Win95, but isn't yet in the mingw32
    95    development environment, and only works on systems that have had IE 3.0
    96    or newer installed on them (which is not the case with the base Win95).
    97    Therefore, we implement our own version of _TrackMouseEvent() which
    98    uses our own implementation if TrackMouseEvent() is not available.
    99 */
   100 static BOOL (WINAPI *_TrackMouseEvent)(TRACKMOUSEEVENT *ptme) = NULL;
   101 
   102 static VOID CALLBACK
   103 TrackMouseTimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
   104 {
   105 	RECT rect;
   106 	POINT pt;
   107 
   108 	GetClientRect(hWnd, &rect);
   109 	MapWindowPoints(hWnd, NULL, (LPPOINT)&rect, 2);
   110 	GetCursorPos(&pt);
   111 	if ( !PtInRect(&rect, pt) || (WindowFromPoint(pt) != hWnd) ) {
   112 		if ( !KillTimer(hWnd, idEvent) ) {
   113 			/* Error killing the timer! */
   114 		}
   115 		PostMessage(hWnd, WM_MOUSELEAVE, 0, 0);
   116 	}
   117 }
   118 static BOOL WINAPI WIN_TrackMouseEvent(TRACKMOUSEEVENT *ptme)
   119 {
   120 	if ( ptme->dwFlags == TME_LEAVE ) {
   121 		return SetTimer(ptme->hwndTrack, ptme->dwFlags, 100,
   122 		                (TIMERPROC)TrackMouseTimerProc);
   123 	}
   124 	return FALSE;
   125 }
   126 #endif /* WM_MOUSELEAVE */
   127 
   128 /* Function to retrieve the current keyboard modifiers */
   129 static void WIN_GetKeyboardState(void)
   130 {
   131 #ifndef NO_GETKEYBOARDSTATE
   132 	SDLMod state;
   133 	BYTE keyboard[256];
   134 	Uint8 *kstate = SDL_GetKeyState(NULL);
   135 
   136 	state = KMOD_NONE;
   137 	if ( GetKeyboardState(keyboard) ) {
   138 		if ( keyboard[VK_LSHIFT] & 0x80) {
   139 			state |= KMOD_LSHIFT;
   140 		}
   141 		if ( keyboard[VK_RSHIFT] & 0x80) {
   142 			state |= KMOD_RSHIFT;
   143 		}
   144 		if ( keyboard[VK_LCONTROL] & 0x80) {
   145 			state |= KMOD_LCTRL;
   146 		}
   147 		if ( keyboard[VK_RCONTROL] & 0x80) {
   148 			state |= KMOD_RCTRL;
   149 		}
   150 		if ( keyboard[VK_LMENU] & 0x80) {
   151 			state |= KMOD_LALT;
   152 		}
   153 		if ( keyboard[VK_RMENU] & 0x80) {
   154 			state |= KMOD_RALT;
   155 		}
   156 		if ( keyboard[VK_NUMLOCK] & 0x01) {
   157 			state |= KMOD_NUM;
   158 			kstate[SDLK_NUMLOCK] = SDL_PRESSED;
   159 		}
   160 		if ( keyboard[VK_CAPITAL] & 0x01) {
   161 			state |= KMOD_CAPS;
   162 			kstate[SDLK_CAPSLOCK] = SDL_PRESSED;
   163 		}
   164 	}
   165 	SDL_SetModState(state);
   166 #endif /* !NO_GETKEYBOARDSTATE */
   167 }
   168 
   169 /* The main Win32 event handler
   170 DJM: This is no longer static as (DX5/DIB)_CreateWindow needs it
   171 */
   172 LONG CALLBACK WinMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
   173 {
   174 	SDL_VideoDevice *this = current_video;
   175 	static int mouse_pressed = 0;
   176 	static int in_window = 0;
   177 #ifdef WMMSG_DEBUG
   178 	fprintf(stderr, "Received windows message:  ");
   179 	if ( msg > MAX_WMMSG ) {
   180 		fprintf(stderr, "%d", msg);
   181 	} else {
   182 		fprintf(stderr, "%s", wmtab[msg]);
   183 	}
   184 	fprintf(stderr, " -- 0x%X, 0x%X\n", wParam, lParam);
   185 #endif
   186 	switch (msg) {
   187 
   188 		case WM_ACTIVATE: {
   189 			SDL_VideoDevice *this = current_video;
   190 			BOOL minimized;
   191 			Uint8 appstate;
   192 
   193 			minimized = HIWORD(wParam);
   194 			if ( !minimized && (LOWORD(wParam) != WA_INACTIVE) ) {
   195 				/* Gain the following states */
   196 				appstate = SDL_APPACTIVE|SDL_APPINPUTFOCUS;
   197 				if ( this->input_grab != SDL_GRAB_OFF ) {
   198 					WIN_GrabInput(this, SDL_GRAB_ON);
   199 				}
   200 				if ( !(SDL_GetAppState()&SDL_APPINPUTFOCUS) ) {
   201 					WIN_SwapGamma(this);
   202 					if ( WINDIB_FULLSCREEN() ) {
   203 						SDL_RestoreGameMode();
   204 					}
   205 				}
   206 				posted = SDL_PrivateAppActive(1, appstate);
   207 				WIN_GetKeyboardState();
   208 			} else {
   209 				/* Lose the following states */
   210 				appstate = SDL_APPINPUTFOCUS;
   211 				if ( minimized ) {
   212 					appstate |= SDL_APPACTIVE;
   213 				}
   214 				if ( this->input_grab != SDL_GRAB_OFF ) {
   215 					WIN_GrabInput(this, SDL_GRAB_OFF);
   216 				}
   217 				if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
   218 					WIN_SwapGamma(this);
   219 					if ( WINDIB_FULLSCREEN() ) {
   220 						SDL_RestoreDesktopMode();
   221 					}
   222 				}
   223 				posted = SDL_PrivateAppActive(0, appstate);
   224 			}
   225 			return(0);
   226 		}
   227 		break;
   228 
   229 		case WM_MOUSEMOVE: {
   230 			
   231 			/* Mouse is handled by DirectInput when fullscreen */
   232 			if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) {
   233 				Sint16 x, y;
   234 
   235 				/* mouse has entered the window */
   236 				if ( ! in_window ) {
   237 #ifdef WM_MOUSELEAVE
   238 					TRACKMOUSEEVENT tme;
   239 
   240 					tme.cbSize = sizeof(tme);
   241 					tme.dwFlags = TME_LEAVE;
   242 					tme.hwndTrack = SDL_Window;
   243 					_TrackMouseEvent(&tme);
   244 #endif /* WM_MOUSELEAVE */
   245 					in_window = TRUE;
   246 
   247 					posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
   248 				}
   249 
   250 				/* mouse has moved within the window */
   251 				x = LOWORD(lParam);
   252 				y = HIWORD(lParam);
   253 				if ( mouse_relative ) {
   254 					POINT center;
   255 					center.x = (SDL_VideoSurface->w/2);
   256 					center.y = (SDL_VideoSurface->h/2);
   257 					x -= (Sint16)center.x;
   258 					y -= (Sint16)center.y;
   259 					if ( x || y ) {
   260 						ClientToScreen(SDL_Window, &center);
   261 						SetCursorPos(center.x, center.y);
   262 						posted = SDL_PrivateMouseMotion(0, 1, x, y);
   263 					}
   264 				} else {
   265 					posted = SDL_PrivateMouseMotion(0, 0, x, y);
   266 				}
   267 			}
   268 		}
   269 		return(0);
   270 
   271 #ifdef WM_MOUSELEAVE
   272 		case WM_MOUSELEAVE: {
   273 
   274 			/* Mouse is handled by DirectInput when fullscreen */
   275 			if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) {
   276 				/* mouse has left the window */
   277 				/* or */
   278 				/* Elvis has left the building! */
   279 				in_window = FALSE;
   280 				posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
   281 			}
   282 		}
   283 		return(0);
   284 #endif /* WM_MOUSELEAVE */
   285 
   286 		case WM_LBUTTONDOWN:
   287 		case WM_LBUTTONUP:
   288 		case WM_MBUTTONDOWN:
   289 		case WM_MBUTTONUP:
   290 		case WM_RBUTTONDOWN:
   291 		case WM_RBUTTONUP: {
   292 			/* Mouse is handled by DirectInput when fullscreen */
   293 			if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) {
   294 				Sint16 x, y;
   295 				Uint8 button, state;
   296 
   297 				/* DJM:
   298 				   We want the SDL window to take focus so that
   299 				   it acts like a normal windows "component"
   300 				   (e.g. gains keyboard focus on a mouse click).
   301 				 */
   302 				SetFocus(SDL_Window);
   303 
   304 				/* Figure out which button to use */
   305 				switch (msg) {
   306 					case WM_LBUTTONDOWN:
   307 						button = 1;
   308 						state = SDL_PRESSED;
   309 						break;
   310 					case WM_LBUTTONUP:
   311 						button = 1;
   312 						state = SDL_RELEASED;
   313 						break;
   314 					case WM_MBUTTONDOWN:
   315 						button = 2;
   316 						state = SDL_PRESSED;
   317 						break;
   318 					case WM_MBUTTONUP:
   319 						button = 2;
   320 						state = SDL_RELEASED;
   321 						break;
   322 					case WM_RBUTTONDOWN:
   323 						button = 3;
   324 						state = SDL_PRESSED;
   325 						break;
   326 					case WM_RBUTTONUP:
   327 						button = 3;
   328 						state = SDL_RELEASED;
   329 						break;
   330 					default:
   331 						/* Eh? Unknown button? */
   332 						return(0);
   333 				}
   334 				if ( state == SDL_PRESSED ) {
   335 					/* Grab mouse so we get up events */
   336 					if ( ++mouse_pressed > 0 ) {
   337 						SetCapture(hwnd);
   338 					}
   339 				} else {
   340 					/* Release mouse after all up events */
   341 					if ( --mouse_pressed <= 0 ) {
   342 						ReleaseCapture();
   343 						mouse_pressed = 0;
   344 					}
   345 				}
   346 				if ( mouse_relative ) {
   347 				/*	RJR: March 28, 2000
   348 					report internal mouse position if in relative mode */
   349 					x = 0; y = 0;
   350 				} else {
   351 					x = (Sint16)LOWORD(lParam);
   352 					y = (Sint16)HIWORD(lParam);
   353 				}
   354 				posted = SDL_PrivateMouseButton(
   355 							state, button, x, y);
   356 			}
   357 		}
   358 		return(0);
   359 
   360 
   361 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
   362 		case WM_MOUSEWHEEL: 
   363 			if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) {
   364 				int move = (short)HIWORD(wParam);
   365 				if ( move ) {
   366 					Uint8 button;
   367 					if ( move > 0 )
   368 						button = 4;
   369 					else
   370 						button = 5;
   371 					posted = SDL_PrivateMouseButton(
   372 						SDL_PRESSED, button, 0, 0);
   373 					posted |= SDL_PrivateMouseButton(
   374 						SDL_RELEASED, button, 0, 0);
   375 				}
   376 			}
   377 			return(0);
   378 #endif
   379 
   380 #ifdef WM_GETMINMAXINFO
   381 		/* This message is sent as a way for us to "check" the values
   382 		 * of a position change.  If we don't like it, we can adjust
   383 		 * the values before they are changed.
   384 		 */
   385 		case WM_GETMINMAXINFO: {
   386 			MINMAXINFO *info;
   387 			RECT        size;
   388 			int x, y;
   389 			int width;
   390 			int height;
   391 
   392 			/* We don't want to clobber an internal resize */
   393 			if ( SDL_resizing )
   394 				return(0);
   395 
   396 			/* We allow resizing with the SDL_RESIZABLE flag */
   397 			if ( SDL_PublicSurface &&
   398 				(SDL_PublicSurface->flags & SDL_RESIZABLE) ) {
   399 				return(0);
   400 			}
   401 
   402 			/* Get the current position of our window */
   403 			GetWindowRect(SDL_Window, &size);
   404 			x = size.left;
   405 			y = size.top;
   406 
   407 			/* Calculate current width and height of our window */
   408 			size.top = 0;
   409 			size.left = 0;
   410 			if ( SDL_PublicSurface != NULL ) {
   411 				size.bottom = SDL_PublicSurface->h;
   412 				size.right = SDL_PublicSurface->w;
   413 			} else {
   414 				size.bottom = 0;
   415 				size.right = 0;
   416 			}
   417 			AdjustWindowRect(&size, GetWindowLong(hwnd, GWL_STYLE),
   418 									FALSE);
   419 			width = size.right - size.left;
   420 			height = size.bottom - size.top;
   421 
   422 			/* Fix our size to the current size */
   423 			info = (MINMAXINFO *)lParam;
   424 			info->ptMaxSize.x = width;
   425 			info->ptMaxSize.y = height;
   426 			info->ptMaxPosition.x = x;
   427 			info->ptMaxPosition.y = y;
   428 			info->ptMinTrackSize.x = width;
   429 			info->ptMinTrackSize.y = height;
   430 			info->ptMaxTrackSize.x = width;
   431 			info->ptMaxTrackSize.y = height;
   432 		}
   433 		return(0);
   434 #endif /* WM_GETMINMAXINFO */
   435 
   436 		case WM_MOVE: {
   437 			SDL_VideoDevice *this = current_video;
   438 
   439 			GetClientRect(SDL_Window, &SDL_bounds);
   440 			ClientToScreen(SDL_Window, (LPPOINT)&SDL_bounds);
   441 			ClientToScreen(SDL_Window, (LPPOINT)&SDL_bounds+1);
   442 			if ( this->input_grab != SDL_GRAB_OFF ) {
   443 				ClipCursor(&SDL_bounds);
   444 			}
   445 		}
   446 		break;
   447 	
   448 		case WM_SIZE: {
   449 			if ( SDL_PublicSurface &&
   450 				(SDL_PublicSurface->flags & SDL_RESIZABLE) ) {
   451 				SDL_PrivateResize(LOWORD(lParam), HIWORD(lParam));
   452 			}
   453 			return(0);
   454 		}
   455 		break;
   456 
   457 		/* We need to set the cursor */
   458 		case WM_SETCURSOR: {
   459 			Uint16 hittest;
   460 
   461 			hittest = LOWORD(lParam);
   462 			if ( hittest == HTCLIENT ) {
   463 				SetCursor(SDL_hcursor);
   464 				return(TRUE);
   465 			}
   466 		}
   467 		break;
   468 
   469 		/* We are about to get palette focus! */
   470 		case WM_QUERYNEWPALETTE: {
   471 			WIN_RealizePalette(current_video);
   472 			return(TRUE);
   473 		}
   474 		break;
   475 
   476 		/* Another application changed the palette */
   477 		case WM_PALETTECHANGED: {
   478 			WIN_PaletteChanged(current_video, (HWND)wParam);
   479 		}
   480 		break;
   481 
   482 		/* We were occluded, refresh our display */
   483 		case WM_PAINT: {
   484 			HDC hdc;
   485 			PAINTSTRUCT ps;
   486 
   487 			hdc = BeginPaint(SDL_Window, &ps);
   488 			if ( current_video->screen &&
   489 			     !(current_video->screen->flags & SDL_OPENGL) ) {
   490 				WIN_WinPAINT(current_video, hdc);
   491 			}
   492 			EndPaint(SDL_Window, &ps);
   493 		}
   494 		return(0);
   495 
   496 		/* DJM: Send an expose event in this case */
   497 		case WM_ERASEBKGND: {
   498 			posted = SDL_PrivateExpose();
   499 		}
   500 		return(0);
   501 
   502 		case WM_CLOSE: {
   503 			if ( (posted = SDL_PrivateQuit()) )
   504 				PostQuitMessage(0);
   505 		}
   506 		return(0);
   507 
   508 		case WM_DESTROY: {
   509 			PostQuitMessage(0);
   510 		}
   511 		return(0);
   512 
   513 		default: {
   514 			/* Special handling by the video driver */
   515 			if (HandleMessage) {
   516 				return(HandleMessage(current_video,
   517 			                     hwnd, msg, wParam, lParam));
   518 			}
   519 		}
   520 		break;
   521 	}
   522 	return(DefWindowProc(hwnd, msg, wParam, lParam));
   523 }
   524 
   525 /* Allow the application handle to be stored and retrieved later */
   526 static void *SDL_handle = NULL;
   527 
   528 void SDL_SetModuleHandle(void *handle)
   529 {
   530 	SDL_handle = handle;
   531 }
   532 void *SDL_GetModuleHandle(void)
   533 {
   534 	void *handle;
   535 
   536 	if ( SDL_handle ) {
   537 		handle = SDL_handle;
   538 	} else {
   539 		/* Warning:
   540 		   If SDL is built as a DLL, this will return a handle to
   541 		   the DLL, not the application, and DirectInput may fail
   542 		   to initialize.
   543 		 */
   544 		handle = GetModuleHandle(NULL);
   545 	}
   546 	return(handle);
   547 }
   548 
   549 /* This allows the SDL_WINDOWID hack */
   550 const char *SDL_windowid = NULL;
   551 
   552 /* Register the class for this application -- exported for winmain.c */
   553 int SDL_RegisterApp(char *name, Uint32 style, void *hInst)
   554 {
   555 	static int initialized = 0;
   556 	WNDCLASS class;
   557 #ifdef WM_MOUSELEAVE
   558 	HMODULE handle;
   559 #endif
   560 
   561 	/* Only do this once... */
   562 	if ( initialized ) {
   563 		return(0);
   564 	}
   565 
   566 	/* This function needs to be passed the correct process handle
   567 	   by the application.
   568 	 */
   569 	if ( ! hInst ) {
   570 		hInst = SDL_GetModuleHandle();
   571 	}
   572 
   573 	/* Register the application class */
   574 	class.hCursor		= NULL;
   575 #ifdef _WIN32_WCE
   576     {
   577 	/* WinCE uses the UNICODE version */
   578 	int nLen = strlen(name)+1;
   579 	LPWSTR lpszW = alloca(nLen*2);
   580 	MultiByteToWideChar(CP_ACP, 0, name, -1, lpszW, nLen);
   581 	class.hIcon		= LoadImage(hInst, lpszW, IMAGE_ICON,
   582 	                                    0, 0, LR_DEFAULTCOLOR);
   583 	class.lpszMenuName	= NULL;
   584 	class.lpszClassName	= lpszW;
   585     }
   586 #else
   587 	class.hIcon		= LoadImage(hInst, name, IMAGE_ICON,
   588 	                                    0, 0, LR_DEFAULTCOLOR);
   589 	class.lpszMenuName	= "(none)";
   590 	class.lpszClassName	= name;
   591 #endif /* _WIN32_WCE */
   592 	class.hbrBackground	= NULL;
   593 	class.hInstance		= hInst;
   594 	class.style		= style;
   595 #ifdef HAVE_OPENGL
   596 	class.style		|= CS_OWNDC;
   597 #endif
   598 	class.lpfnWndProc	= WinMessage;
   599 	class.cbWndExtra	= 0;
   600 	class.cbClsExtra	= 0;
   601 	if ( ! RegisterClass(&class) ) {
   602 		SDL_SetError("Couldn't register application class");
   603 		return(-1);
   604 	}
   605 	SDL_Appname = name;
   606 	SDL_Instance = hInst;
   607 
   608 #ifdef WM_MOUSELEAVE
   609 	/* Get the version of TrackMouseEvent() we use */
   610 	_TrackMouseEvent = NULL;
   611 	handle = GetModuleHandle("USER32.DLL");
   612 	if ( handle ) {
   613 		_TrackMouseEvent = (BOOL (WINAPI *)(TRACKMOUSEEVENT *))GetProcAddress(handle, "TrackMouseEvent");
   614 	}
   615 	if ( _TrackMouseEvent == NULL ) {
   616 		_TrackMouseEvent = WIN_TrackMouseEvent;
   617 	}
   618 #endif /* WM_MOUSELEAVE */
   619 
   620 	/* Check for SDL_WINDOWID hack */
   621 	SDL_windowid = getenv("SDL_WINDOWID");
   622 
   623 	initialized = 1;
   624 	return(0);
   625 }
   626