mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-09 13:01:29 -10:00
git-svn-id: svn://svn.icculus.org/fs2open/trunk/fs2_open@9809 387891d4-d844-0410-90c0-e4c51a9137d3
837 lines
19 KiB
C++
837 lines
19 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <commctrl.h>
|
|
#include <stdio.h>
|
|
#include <io.h>
|
|
#include <fcntl.h>
|
|
#include <winsock.h>
|
|
#include <stdarg.h>
|
|
#include <direct.h>
|
|
|
|
#include "globalincs/pstypes.h"
|
|
#include "io/key.h"
|
|
#include "palman/palman.h"
|
|
#include "io/mouse.h"
|
|
#include "osapi/outwnd.h"
|
|
#include "sound/sound.h"
|
|
#include "freespace2/freespaceresource.h"
|
|
#include "playerman/managepilot.h"
|
|
#include "io/joy.h"
|
|
#include "io/joy_ff.h"
|
|
#include "gamesequence/gamesequence.h"
|
|
#include "freespace2/freespace.h"
|
|
#include "osapi/osregistry.h"
|
|
#include "cmdline/cmdline.h"
|
|
#include "sound/voicerec.h"
|
|
#include "graphics/2d.h"
|
|
|
|
#define THREADED // to use the proper set of macros
|
|
#include "osapi/osapi.h"
|
|
|
|
|
|
// used to be a THREADED define but only use multiple process threads if this is defined
|
|
// NOTE: may hang if set
|
|
//#define THREADED_PROCESS
|
|
|
|
|
|
// ----------------------------------------------------------------------------------------------------
|
|
// OSAPI DEFINES/VARS
|
|
//
|
|
|
|
// os-wide globals
|
|
static HINSTANCE hInstApp;
|
|
static HWND hwndApp = NULL;
|
|
static HDC dcApp = NULL;
|
|
static int fAppActive = 0;
|
|
static int fOldAppActive = 0;
|
|
static int main_window_inited = 0;
|
|
static char szWinTitle[128];
|
|
static char szWinClass[128];
|
|
static HANDLE hThread=NULL;
|
|
static DWORD ThreadID;
|
|
static int WinX, WinY, WinW, WinH;
|
|
static int Os_inited = 0;
|
|
|
|
static CRITICAL_SECTION Os_lock;
|
|
|
|
int Os_debugger_running = 0;
|
|
|
|
// ----------------------------------------------------------------------------------------------------
|
|
// OSAPI FORWARD DECLARATIONS
|
|
//
|
|
|
|
#ifdef THREADED_PROCESS
|
|
// thread handler for the main message thread
|
|
DWORD win32_process(DWORD lparam);
|
|
#else
|
|
DWORD win32_process1(DWORD lparam);
|
|
DWORD win32_process2(DWORD lparam);
|
|
#endif
|
|
|
|
// Fills in the Os_debugger_running with non-zero if debugger detected.
|
|
void os_check_debugger();
|
|
|
|
// called at shutdown. Makes sure all thread processing terminates.
|
|
void os_deinit();
|
|
|
|
// go through all windows and try and find the one that matches the search string
|
|
BOOL __stdcall os_enum_windows( HWND hwnd, char * search_string );
|
|
|
|
// message handler for the main thread
|
|
LRESULT CALLBACK win32_message_handler(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam);
|
|
|
|
|
|
// ----------------------------------------------------------------------------------------------------
|
|
// OSAPI FUNCTIONS
|
|
//
|
|
|
|
// detect home/base directory (placeholder for possible future Win32 userdir support, just returns current directory for now)
|
|
char Cur_path[MAX_PATH_LEN];
|
|
const char *detect_home(void)
|
|
{
|
|
if ( strlen(Cfile_root_dir) )
|
|
return Cfile_root_dir;
|
|
|
|
memset( Cur_path, 0, MAX_PATH_LEN );
|
|
GetCurrentDirectory( MAX_PATH_LEN-1, Cur_path );
|
|
|
|
return Cur_path;
|
|
}
|
|
|
|
// initialization/shutdown functions -----------------------------------------------
|
|
|
|
void os_set_process_affinity()
|
|
{
|
|
HANDLE pHandle = GetCurrentProcess();
|
|
DWORD pMaskProcess = 0, pMaskSystem = 0;
|
|
|
|
if ( GetProcessAffinityMask(pHandle, &pMaskProcess, &pMaskSystem) ) {
|
|
// only do this if we have at least 2 procs
|
|
if (pMaskProcess >= 3) {
|
|
// prefer running on the second processor by default
|
|
pMaskProcess = os_config_read_uint(NULL, "ProcessorAffinity", 2);
|
|
|
|
if (pMaskProcess > 0) {
|
|
SetProcessAffinityMask(pHandle, pMaskProcess);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If app_name is NULL or ommited, then TITLE is used
|
|
// for the app name, which is where registry keys are stored.
|
|
void os_init(const char * wclass, const char * title, const char *app_name, const char *version_string )
|
|
{
|
|
#ifndef NDEBUG
|
|
outwnd_init(1);
|
|
#endif
|
|
|
|
os_init_registry_stuff(Osreg_company_name, title, version_string);
|
|
|
|
strcpy_s( szWinTitle, title );
|
|
strcpy_s( szWinClass, wclass );
|
|
|
|
INITIALIZE_CRITICAL_SECTION( Os_lock );
|
|
/*
|
|
#ifdef THREADED_PROCESS
|
|
// Create an even to signal that the window is created,
|
|
// so that we don't return from this function until
|
|
// the window is all properly created.
|
|
HANDLE Window_created = CreateEvent( NULL, FALSE, FALSE, NULL );
|
|
hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)win32_process, Window_created, 0, &ThreadID );
|
|
if ( WaitForSingleObject( Window_created, 5000 )==WAIT_TIMEOUT) { //INFINITE );
|
|
mprintf(( "Wait timeout!\n" ));
|
|
}
|
|
CloseHandle(Window_created);
|
|
Window_created = NULL;
|
|
#endif // THREADED
|
|
*/
|
|
// initialized
|
|
Os_inited = 1;
|
|
|
|
// check to see if we're running under msdev
|
|
os_check_debugger();
|
|
|
|
// deal with processor affinity
|
|
os_set_process_affinity();
|
|
|
|
atexit(os_deinit);
|
|
}
|
|
|
|
// set the main window title
|
|
void os_set_title( const char * title )
|
|
{
|
|
strcpy_s( szWinTitle, title );
|
|
SetWindowText( hwndApp, szWinTitle );
|
|
}
|
|
|
|
extern void gr_opengl_shutdown();
|
|
|
|
// call at program end
|
|
void os_cleanup()
|
|
{
|
|
if (gr_screen.mode == GR_OPENGL)
|
|
gr_opengl_shutdown();
|
|
|
|
if (dcApp != NULL) {
|
|
ReleaseDC( hwndApp, dcApp );
|
|
}
|
|
|
|
// destroy the window (takes care of a lot of window related cleanup and sys messages)
|
|
DestroyWindow( hwndApp );
|
|
|
|
#ifndef NDEBUG
|
|
outwnd_close();
|
|
#endif
|
|
}
|
|
|
|
|
|
// window management -----------------------------------------------------------------
|
|
|
|
// Returns 1 if app is not the foreground app.
|
|
int os_foreground()
|
|
{
|
|
return fAppActive;
|
|
}
|
|
|
|
// Returns the handle to the main window
|
|
uint os_get_window()
|
|
{
|
|
return (uint)hwndApp;
|
|
}
|
|
|
|
uint os_get_dc()
|
|
{
|
|
if (dcApp == NULL) {
|
|
dcApp = GetDC(hwndApp);
|
|
}
|
|
|
|
return (uint)dcApp;
|
|
}
|
|
|
|
// Returns the handle to the main window
|
|
void os_set_window(uint new_handle)
|
|
{
|
|
hwndApp = (HWND)new_handle;
|
|
}
|
|
|
|
|
|
// process management -----------------------------------------------------------------
|
|
|
|
// Sleeps for n milliseconds or until app becomes active.
|
|
void os_sleep(int ms)
|
|
{
|
|
Sleep(ms);
|
|
}
|
|
|
|
// Used to stop message processing
|
|
void os_suspend()
|
|
{
|
|
ENTER_CRITICAL_SECTION( Os_lock );
|
|
}
|
|
|
|
// resume message processing
|
|
void os_resume()
|
|
{
|
|
LEAVE_CRITICAL_SECTION( Os_lock );
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------------------------------
|
|
// OSAPI FORWARD DECLARATIONS
|
|
//
|
|
|
|
#ifdef THREADED_PROCESS
|
|
|
|
// thread handler for the main message thread
|
|
DWORD win32_process(DWORD lparam)
|
|
{
|
|
/* MSG msg;
|
|
HANDLE Window_created = (HANDLE)lparam;
|
|
|
|
if ( !win32_create_window() )
|
|
return 0;
|
|
|
|
// Let the app continue once the window is created
|
|
SetEvent(Window_created);
|
|
|
|
while (1) {
|
|
if (WaitMessage() == TRUE) {
|
|
ENTER_CRITICAL_SECTION( Os_lock );
|
|
while(PeekMessage(&msg,0,0,0,PM_REMOVE)) {
|
|
if ( msg.message == WM_DESTROY ) {
|
|
LEAVE_CRITICAL_SECTION( Os_lock );
|
|
|
|
// cleanup and exit this thread!!
|
|
DELETE_CRITICAL_SECTION( Os_lock );
|
|
return 0;
|
|
}
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
LEAVE_CRITICAL_SECTION( Os_lock );
|
|
}
|
|
}*/
|
|
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
|
|
DWORD win32_process(DWORD lparam)
|
|
{
|
|
MSG msg;
|
|
|
|
while ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) ) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif // THREADED_PROCESS
|
|
|
|
// Fills in the Os_debugger_running with non-zero if debugger detected.
|
|
void os_check_debugger()
|
|
{
|
|
HMODULE hMod;
|
|
char search_string[256];
|
|
char myname[128];
|
|
int namelen;
|
|
char * p;
|
|
|
|
Os_debugger_running = 0; // Assume its not
|
|
|
|
// Find my EXE file name
|
|
hMod = GetModuleHandle(NULL);
|
|
if ( !hMod ) return;
|
|
namelen = GetModuleFileName( hMod, myname, 127 );
|
|
if ( namelen < 1 ) return;
|
|
|
|
// Strip off the .EXE
|
|
p = strstr( myname, ".exe" );
|
|
if (!p) return;
|
|
*p = '\0';
|
|
|
|
// Move p to point to first letter of EXE filename
|
|
while( (*p!='\\') && (*p!='/') && (*p!=':') )
|
|
p--;
|
|
p++;
|
|
if ( strlen(p) < 1 ) return;
|
|
|
|
// Build what the debugger's window title would be if the debugger is running...
|
|
sprintf( search_string, "[run] - %s -", p );
|
|
|
|
// ... and then search for it.
|
|
EnumWindows( (int (__stdcall *)(struct HWND__ *,long))os_enum_windows, (long)&search_string );
|
|
}
|
|
|
|
// called at shutdown. Makes sure all thread processing terminates.
|
|
void os_deinit()
|
|
{
|
|
if (hThread) {
|
|
CloseHandle(hThread);
|
|
hThread = NULL;
|
|
}
|
|
}
|
|
|
|
// go through all windows and try and find the one that matches the search string
|
|
BOOL __stdcall os_enum_windows( HWND hwnd, char * search_string )
|
|
{
|
|
char tmp[128];
|
|
int len;
|
|
|
|
len = GetWindowText( hwnd, tmp, 127 );
|
|
|
|
if ( len ) {
|
|
if ( strstr( tmp, search_string )) {
|
|
Os_debugger_running = 1; // found the search string!
|
|
return FALSE; // stop enumerating windows
|
|
}
|
|
}
|
|
|
|
return TRUE; // continue enumeration
|
|
}
|
|
|
|
void change_window_active_state()
|
|
{
|
|
if (fAppActive != fOldAppActive) {
|
|
if (fAppActive) {
|
|
// maximize it
|
|
joy_reacquire_ff();
|
|
|
|
game_unpause();
|
|
|
|
#ifdef THREADED_PROCESS
|
|
SetThreadPriority( hThread, THREAD_PRIORITY_HIGHEST );
|
|
#endif
|
|
|
|
if ( !Is_standalone )
|
|
disableWindowsKey();
|
|
|
|
if (!Cmdline_window)
|
|
{
|
|
SetWindowPos(hwndApp, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
|
}
|
|
} else {
|
|
joy_unacquire_ff();
|
|
|
|
if (Mouse_hidden)
|
|
Mouse_hidden = 0;
|
|
|
|
// Pause sounds and put up pause screen if necessary
|
|
game_pause();
|
|
|
|
#ifdef THREADED_PROCESS
|
|
SetThreadPriority( hThread, THREAD_PRIORITY_NORMAL );
|
|
#endif
|
|
|
|
if ( !Is_standalone )
|
|
enableWindowsKey();
|
|
|
|
if (!Cmdline_window)
|
|
{
|
|
SetWindowPos(hwndApp, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
|
}
|
|
}
|
|
|
|
gr_activate(fAppActive);
|
|
|
|
fOldAppActive = fAppActive;
|
|
}
|
|
}
|
|
|
|
int Got_message = 0;
|
|
extern bool Messagebox_active;
|
|
// message handler for the main thread
|
|
LRESULT CALLBACK win32_message_handler(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// Got_message++;
|
|
|
|
switch(msg) {
|
|
|
|
case WM_QUERYNEWPALETTE:
|
|
// mprintf(( "WM: QueryNewPalette\n" ));
|
|
return TRUE; // Say that I've realized my own palette
|
|
break;
|
|
case WM_PALETTECHANGED:
|
|
// mprintf(( "WM: PaletteChanged\n" ));
|
|
break;
|
|
case WM_PALETTEISCHANGING:
|
|
// mprintf(( "WM: PaletteIsChanging\n" ));
|
|
break;
|
|
|
|
case WM_DISPLAYCHANGE:
|
|
// mprintf(( "WM: DisplayChange\n" ));
|
|
break;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
|
|
break;
|
|
|
|
case WM_LBUTTONUP:
|
|
mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
|
|
break;
|
|
|
|
case WM_RBUTTONDOWN:
|
|
mouse_mark_button( MOUSE_RIGHT_BUTTON, 1 );
|
|
break;
|
|
|
|
case WM_RBUTTONUP:
|
|
mouse_mark_button( MOUSE_RIGHT_BUTTON, 0 );
|
|
break;
|
|
|
|
case WM_MBUTTONDOWN:
|
|
mouse_mark_button( MOUSE_MIDDLE_BUTTON, 1 );
|
|
break;
|
|
|
|
case WM_MBUTTONUP:
|
|
mouse_mark_button( MOUSE_MIDDLE_BUTTON, 0 );
|
|
break;
|
|
|
|
case WM_TIMER:
|
|
break;
|
|
|
|
case WM_SYSCHAR:
|
|
break;
|
|
|
|
case WM_SYSKEYDOWN:
|
|
case WM_KEYDOWN: {
|
|
int nVirtKey;
|
|
uint lKeyData;
|
|
|
|
int latency;
|
|
latency = timeGetTime() - GetMessageTime();
|
|
if ( latency < 0 )
|
|
latency=0;
|
|
|
|
nVirtKey = (int)wParam; // virtual-key code
|
|
lKeyData = (lParam>>16) & 255; // key data
|
|
if ( (lParam>>16) & 256 ) lKeyData += 0x80;
|
|
|
|
// Fix up print screen, whose OEM code is wrong under 95.
|
|
if ( nVirtKey == VK_SNAPSHOT ) {
|
|
lKeyData = KEY_PRINT_SCRN;
|
|
}
|
|
|
|
if (lKeyData == KEY_RSHIFT) // either shift is just a shift to us..
|
|
lKeyData = KEY_LSHIFT;
|
|
|
|
if (lKeyData == KEY_RALT) // Same with alt keys..
|
|
lKeyData = KEY_LALT;
|
|
|
|
// mprintf(( "Key down = 0x%x|%x\n", lKeyData, nVirtKey ));
|
|
key_mark( lKeyData, 1, latency );
|
|
// mprintf(( "Key down = 0x%x\n", lKeyData ));
|
|
//Warning( LOCATION, "Key = 0x%x", lKeyData );
|
|
}
|
|
break;
|
|
|
|
case WM_SYSKEYUP:
|
|
case WM_KEYUP: {
|
|
int nVirtKey;
|
|
uint lKeyData;
|
|
|
|
int latency;
|
|
latency = timeGetTime() - GetMessageTime();
|
|
if ( latency < 0 )
|
|
latency=0;
|
|
|
|
nVirtKey = (int) wParam; // virtual-key code
|
|
lKeyData = (lParam>>16) & 255; // key data
|
|
if ( (lParam>>16) & 256 ) lKeyData += 0x80;
|
|
|
|
// Fix up print screen, whose OEM code is wrong under 95.
|
|
if ( nVirtKey == VK_SNAPSHOT ) {
|
|
lKeyData = KEY_PRINT_SCRN;
|
|
}
|
|
|
|
if (lKeyData == KEY_RSHIFT) // either shift is just a shift to us..
|
|
lKeyData = KEY_LSHIFT;
|
|
|
|
if (lKeyData == KEY_RALT) // Same with alt keys..
|
|
lKeyData = KEY_LALT;
|
|
|
|
// mprintf(( "Key up = 0x%x|%x\n", lKeyData, nVirtKey ));
|
|
if ( lKeyData == 0xB7 ) {
|
|
// Hack for PrintScreen which only sends one up message!
|
|
key_mark( lKeyData, 1, latency );
|
|
key_mark( lKeyData, 0, latency );
|
|
|
|
} else {
|
|
key_mark( lKeyData, 0, latency );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_KILLFOCUS:
|
|
{
|
|
if (Messagebox_active)
|
|
break;
|
|
|
|
key_lost_focus();
|
|
mouse_lost_focus();
|
|
if ( !Is_standalone )
|
|
gr_activate(0);
|
|
break;
|
|
}
|
|
|
|
case WM_SETFOCUS:
|
|
{
|
|
if (Messagebox_active)
|
|
break;
|
|
|
|
key_got_focus();
|
|
mouse_got_focus();
|
|
if ( !Is_standalone )
|
|
gr_activate(1);
|
|
break;
|
|
}
|
|
|
|
|
|
case WM_ACTIVATE:
|
|
{
|
|
if (Messagebox_active)
|
|
break;
|
|
|
|
int flag = LOWORD(wParam);
|
|
fAppActive = (( flag == WA_ACTIVE) || (flag==WA_CLICKACTIVE)) ? TRUE : FALSE;
|
|
change_window_active_state();
|
|
break;
|
|
}
|
|
|
|
case WM_ACTIVATEAPP:
|
|
if (Messagebox_active)
|
|
break;
|
|
|
|
fAppActive = (BOOL)wParam;
|
|
change_window_active_state();
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
// mprintf(( "WM_DESTROY called\n" ));
|
|
PostQuitMessage(0);
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
gameseq_post_event(GS_EVENT_QUIT_GAME);
|
|
break;
|
|
|
|
case WM_SYSCOMMAND:
|
|
// mprintf(( "Sys command called '%x'\n", wParam ));
|
|
if ( wParam != SC_SCREENSAVE ){
|
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
|
}
|
|
break;
|
|
|
|
/*
|
|
case MM_WIM_DATA:
|
|
rtvoice_stream_data((uint)hwnd, (uint)wParam, (uint)lParam);
|
|
break;
|
|
*/
|
|
#ifdef FS2_VOICER
|
|
case WM_RECOEVENT:
|
|
if ( Game_mode & GM_IN_MISSION && Cmdline_voice_recognition)
|
|
{
|
|
VOICEREC_process_event( hwnd );
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
// report back that we handle this ourselves (with gr_clear()) in order to
|
|
// prevent flickering (especially with movies)
|
|
case WM_ERASEBKGND:
|
|
return TRUE;
|
|
|
|
default:
|
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// create the main window
|
|
void win32_create_window(int width, int height)
|
|
{
|
|
WNDCLASSEX wclass; // Huh?
|
|
HINSTANCE hInst = GetModuleHandle(NULL);
|
|
|
|
if (hwndApp != NULL) {
|
|
if (dcApp != NULL) {
|
|
ReleaseDC( hwndApp, dcApp );
|
|
dcApp = NULL;
|
|
}
|
|
|
|
DestroyWindow( hwndApp );
|
|
hwndApp = NULL;
|
|
}
|
|
|
|
memset( &wclass, 0, sizeof(WNDCLASSEX) );
|
|
|
|
wclass.hInstance = hInst;
|
|
wclass.lpszClassName = szWinClass;
|
|
wclass.lpfnWndProc = (WNDPROC)win32_message_handler;
|
|
|
|
// if (Cmdline_window) {
|
|
// wclass.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;
|
|
// } else {
|
|
// wclass.style = CS_BYTEALIGNCLIENT | CS_VREDRAW | CS_HREDRAW;
|
|
// }
|
|
wclass.style = CS_OWNDC; // using CS_OWNDC for better Win9x/WinME support (I think it's implied with WinNT+)
|
|
|
|
wclass.cbSize = sizeof(WNDCLASSEX);
|
|
wclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_APP_ICON) );
|
|
wclass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wclass.lpszMenuName = NULL; //"FreeSpaceMenu";
|
|
wclass.cbClsExtra = 0;
|
|
wclass.cbWndExtra = 0;
|
|
// set background to erase/clear with a black brush
|
|
// (NULL means that we had to do it ourselves, and created a white-screen problem)
|
|
wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
|
|
|
if ( !RegisterClassEx(&wclass) ) {
|
|
Error( LOCATION, "FATAL ERROR: Unable to register window class!!" );
|
|
}
|
|
|
|
int style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE;
|
|
|
|
if (Cmdline_window)
|
|
style |= (WS_CAPTION | WS_SYSMENU | WS_BORDER);
|
|
|
|
int x_add, y_add;
|
|
int start_x, start_y;
|
|
|
|
if (Cmdline_window || Cmdline_fullscreen_window) {
|
|
RECT my_rect;
|
|
|
|
// make sure we adjust for the actual window border
|
|
if (Cmdline_window) {
|
|
x_add = GetSystemMetrics(SM_CXFIXEDFRAME) * 2;
|
|
y_add = 2 * GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION);
|
|
} else {
|
|
x_add = y_add = 0;
|
|
}
|
|
|
|
GetWindowRect( GetDesktopWindow(), &my_rect );
|
|
|
|
start_x = (my_rect.right - width - x_add) / 2;
|
|
start_y = (my_rect.bottom - height - y_add) / 2;
|
|
|
|
if (start_x < 0)
|
|
start_x = 0;
|
|
if (start_y < 0)
|
|
start_y = 0;
|
|
} else {
|
|
x_add = y_add = 0;
|
|
start_x = start_y = 0;
|
|
}
|
|
|
|
// we don't sicky TOPMOST for windowed mode since we wouldn't be able to bring
|
|
// the debug window (or anything else) to the true foreground otherwise
|
|
hwndApp = CreateWindowEx( (Cmdline_window || Cmdline_fullscreen_window) ? 0 : WS_EX_TOPMOST,
|
|
szWinClass, szWinTitle,
|
|
style,
|
|
start_x, // x
|
|
start_y, // y
|
|
width + x_add, // w
|
|
height + y_add, // h
|
|
NULL, (HMENU)NULL, hInst,
|
|
(LPSTR)NULL );
|
|
|
|
if ( !hwndApp ) {
|
|
Error( LOCATION, "FATAL ERROR: Unable to create game window!!" );
|
|
}
|
|
|
|
main_window_inited = 1;
|
|
|
|
win32_process(0);
|
|
|
|
#ifndef NDEBUG
|
|
extern void outwnd_init_debug_window(int);
|
|
outwnd_init_debug_window(1);
|
|
#endif
|
|
|
|
ShowWindow( hwndApp, SW_SHOWNORMAL );
|
|
|
|
SetForegroundWindow( hwndApp );
|
|
SetActiveWindow( hwndApp );
|
|
SetFocus( hwndApp );
|
|
|
|
// Hack!! Turn off Window's cursor.
|
|
// ShowCursor(false);
|
|
// ClipCursor(NULL);
|
|
|
|
return;// TRUE;
|
|
}
|
|
|
|
void os_poll()
|
|
{
|
|
#ifndef THREADED_PROCESS
|
|
win32_process(0);
|
|
#else
|
|
MSG msg;
|
|
ENTER_CRITICAL_SECTION( Os_lock );
|
|
while(PeekMessage(&msg,0,0,0,PM_NOREMOVE)) {
|
|
if ( msg.message == WM_DESTROY ) {
|
|
break;
|
|
}
|
|
if (PeekMessage(&msg,0,0,0,PM_REMOVE)) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
Got_message++;
|
|
}
|
|
LEAVE_CRITICAL_SECTION( Os_lock );
|
|
#endif
|
|
}
|
|
|
|
void debug_int3(char *file, int line)
|
|
{
|
|
mprintf(("Int3(): From %s at line %d\n", file, line));
|
|
|
|
gr_activate(0);
|
|
|
|
#ifdef _WIN32
|
|
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
|
__debugbreak( );
|
|
#elif defined(_MSC_VER)
|
|
_asm int 3;
|
|
#elif defined __GNUC__
|
|
asm("int $3");
|
|
#else
|
|
#error debug_int3: unknown compiler
|
|
#endif
|
|
|
|
#else
|
|
#error debug_int3: unknown OS
|
|
#endif
|
|
|
|
gr_activate(1);
|
|
|
|
}
|
|
|
|
|
|
// Goober5000 - code provided by jr2 to disable windows key when FSO is in the foreground
|
|
|
|
#ifdef _WIN32
|
|
|
|
static HHOOK g_hKeyboardHook = NULL;
|
|
|
|
// ugh
|
|
#ifndef WH_KEYBOARD_LL
|
|
#define WH_KEYBOARD_LL 13
|
|
#endif
|
|
|
|
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (nCode < 0 || nCode != HC_ACTION) // do not process message
|
|
return CallNextHookEx(g_hKeyboardHook, nCode, wParam, lParam);
|
|
|
|
// hack!
|
|
// this is because the KBDLLHOOKSTRUCT type requires a mess of #includes,
|
|
// but all we need from it is the first field
|
|
DWORD vkCode = *( (DWORD *) lParam );
|
|
|
|
// determine key event
|
|
switch (wParam)
|
|
{
|
|
case WM_KEYDOWN:
|
|
case WM_KEYUP:
|
|
if ( (vkCode == VK_LWIN) || (vkCode == VK_RWIN) )
|
|
return 1;
|
|
}
|
|
|
|
return CallNextHookEx( g_hKeyboardHook, nCode, wParam, lParam );
|
|
}
|
|
|
|
void disableWindowsKey()
|
|
{
|
|
if (g_hKeyboardHook != NULL)
|
|
return;
|
|
|
|
g_hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 );
|
|
}
|
|
|
|
void enableWindowsKey()
|
|
{
|
|
if (g_hKeyboardHook == NULL)
|
|
return;
|
|
|
|
UnhookWindowsHookEx( g_hKeyboardHook );
|
|
g_hKeyboardHook = NULL;
|
|
}
|
|
|
|
#endif // _WIN32
|