mirror of
https://github.com/spiffcode/hostile-takeover.git
synced 2026-03-29 00:09:40 -06:00
666 lines
13 KiB
C++
666 lines
13 KiB
C++
#include <stdio.h>
|
|
#include "..\ht.h"
|
|
|
|
extern RECT g_arcSilkscreen[];
|
|
static MSG s_msgMouseLast;
|
|
static dword s_tLastMouseMsg;
|
|
int gxPenLast;
|
|
int gyPenLast;
|
|
|
|
void GetSilkRect(RECT *prcIn, RECT *prcOut, bool fScale)
|
|
{
|
|
*prcOut = *prcIn;
|
|
if (gpdisp != NULL) {
|
|
ModeInfo mode;
|
|
gpdisp->GetMode(&mode);
|
|
int nScale;
|
|
if (fScale) {
|
|
nScale = gpdisp->GetScale() * mode.cx / 160;
|
|
} else {
|
|
nScale = mode.cx / 160;
|
|
}
|
|
prcOut->left = prcIn->left * nScale;
|
|
prcOut->top = prcIn->top * nScale;
|
|
prcOut->right = prcIn->right * nScale;
|
|
prcOut->bottom = prcIn->bottom * nScale;
|
|
}
|
|
}
|
|
|
|
bool WaitForInput(dword msStart, dword cmsWaitTotal)
|
|
{
|
|
dword cmsWait = cmsWaitTotal;
|
|
if (cmsWaitTotal != INFINITE) {
|
|
dword cmsElapsed = GetTickCount() - msStart;
|
|
if (cmsElapsed > cmsWaitTotal)
|
|
return false;
|
|
cmsWait = cmsWaitTotal - cmsElapsed;
|
|
}
|
|
dword dw = MsgWaitForMultipleObjects(0, NULL, TRUE, cmsWait, QS_ALLEVENTS);
|
|
return dw != WAIT_TIMEOUT;
|
|
}
|
|
|
|
void ProcessKeyEvent(MSG *pmsg, Event *pevt)
|
|
{
|
|
// Palm mixes "chars" with "vkeys", however with values that don't
|
|
// overlap. The host will treat this the same.
|
|
|
|
pevt->eType = keyDownEvent;
|
|
switch (pmsg->wParam) {
|
|
case VK_UP:
|
|
pevt->chr = chrPageUp;
|
|
return;
|
|
|
|
case VK_DOWN:
|
|
pevt->chr = chrPageDown;
|
|
return;
|
|
|
|
case VK_LEFT:
|
|
pevt->chr = chrLeft;
|
|
return;
|
|
|
|
case VK_RIGHT:
|
|
pevt->chr = chrRight;
|
|
return;
|
|
|
|
case VK_BACK:
|
|
pevt->chr = chrBackspace;
|
|
return;
|
|
|
|
case VK_DELETE:
|
|
pevt->chr = chrDelete;
|
|
return;
|
|
|
|
case VK_F7:
|
|
if (gpavir == NULL) {
|
|
gpavir = new AviRecorder();
|
|
Size siz;
|
|
gpdisp->GetFrontDib()->GetSize(&siz);
|
|
if (!gpavir->Start(siz.cx, siz.cy)) {
|
|
delete gpavir;
|
|
gpavir = NULL;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VK_F8:
|
|
if (gpavir != NULL) {
|
|
gpavir->Stop();
|
|
delete gpavir;
|
|
gpavir = NULL;
|
|
}
|
|
break;
|
|
|
|
case VK_SUBTRACT: // numpad
|
|
case VK_OEM_MINUS: // '-' key
|
|
{
|
|
for (int i = 0; i < ARRAYSIZE(gatGameSpeeds); i++)
|
|
if (gatGameSpeeds[i] == gtGameSpeed)
|
|
break;
|
|
i--;
|
|
if (i < 0)
|
|
i = 0;
|
|
ggame.SetGameSpeed(gatGameSpeeds[i]);
|
|
}
|
|
break;
|
|
|
|
case VK_ADD: // numpad
|
|
case VK_OEM_PLUS: // '=' key
|
|
{
|
|
for (int i = 0; i < ARRAYSIZE(gatGameSpeeds); i++)
|
|
if (gatGameSpeeds[i] == gtGameSpeed)
|
|
break;
|
|
i++;
|
|
if (i >= ARRAYSIZE(gatGameSpeeds))
|
|
i = ARRAYSIZE(gatGameSpeeds) - 1;
|
|
ggame.SetGameSpeed(gatGameSpeeds[i]);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
#ifdef DEBUG_HELPERS
|
|
extern void DebugHelperKeyHandler(word vk);
|
|
DebugHelperKeyHandler(pmsg->wParam);
|
|
#endif
|
|
pevt->chr = pmsg->wParam;
|
|
break;
|
|
}
|
|
if (!TranslateMessage(pmsg))
|
|
return;
|
|
|
|
// A WM_CHAR *may* have been posted to the queue - we don't know for
|
|
// sure until we take a peek.
|
|
|
|
MSG msg;
|
|
if (PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, TRUE))
|
|
pevt->chr = msg.wParam;
|
|
}
|
|
|
|
bool ProcessMouseEvent(MSG *pmsg, Event *pevt, bool fHover = false)
|
|
{
|
|
static bool s_fAppButtonDown;
|
|
POINT ptT;
|
|
|
|
#ifdef DEBUG_HELPERS
|
|
// This allows the debug window to get events it needs
|
|
|
|
extern HWND s_hwndDebug;
|
|
if (pmsg->hwnd != Display::m_hwnd)
|
|
if (pmsg->hwnd != s_hwndDebug || LOWORD(pmsg->lParam) >= 320)
|
|
return false;
|
|
#endif
|
|
|
|
// Scale the position appropriately.
|
|
|
|
int nScale = gpdisp->GetScale();
|
|
gxPenLast = (int)((float)(short)LOWORD(pmsg->lParam) / (float)nScale);
|
|
gyPenLast = (int)((float)(short)HIWORD(pmsg->lParam) / (float)nScale);
|
|
|
|
// Remember the last
|
|
|
|
s_msgMouseLast = *pmsg;
|
|
s_tLastMouseMsg = GetTickCount();
|
|
|
|
// Setup
|
|
|
|
RECT rcApp;
|
|
GetSilkRect(&g_arcSilkscreen[2], &rcApp, true);
|
|
bool fGraffitiArea = false;
|
|
if (gpdisp != NULL) {
|
|
ModeInfo mode;
|
|
gpdisp->GetMode(&mode);
|
|
fGraffitiArea = (mode.cyGraffiti != 0);
|
|
}
|
|
|
|
switch (pmsg->message) {
|
|
case WM_LBUTTONDOWN:
|
|
pevt->eType = penDownEvent;
|
|
SetCapture(pmsg->hwnd);
|
|
|
|
ptT.x = LOWORD(pmsg->lParam);
|
|
ptT.y = HIWORD(pmsg->lParam);
|
|
if (fGraffitiArea) {
|
|
if (PtInRect(&rcApp, ptT))
|
|
s_fAppButtonDown = true;
|
|
}
|
|
break;
|
|
|
|
case WM_LBUTTONUP:
|
|
pevt->eType = penUpEvent;
|
|
ReleaseCapture();
|
|
|
|
// Check for soft silk screen buttons.
|
|
|
|
if (fGraffitiArea) {
|
|
ptT.x = LOWORD(pmsg->lParam);
|
|
ptT.y = HIWORD(pmsg->lParam);
|
|
if (s_fAppButtonDown && PtInRect(&rcApp, ptT))
|
|
PostMessage(pmsg->hwnd, WM_GAMEEVENT, appStopEvent, 0);
|
|
s_fAppButtonDown = false;
|
|
}
|
|
break;
|
|
|
|
case WM_MOUSEMOVE:
|
|
if (GetAsyncKeyState(VK_LBUTTON) < 0) {
|
|
pevt->eType = penMoveEvent;
|
|
break;
|
|
}
|
|
if (fHover)
|
|
break;
|
|
return false;
|
|
|
|
#if 0
|
|
#ifdef HOSTILE_TAKEOVER
|
|
case WM_RBUTTONDOWN:
|
|
pevt->chr = chrPageDown;
|
|
pevt->eType = keyDownEvent;
|
|
break;
|
|
#endif
|
|
#else
|
|
case WM_RBUTTONDOWN:
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
pevt->x = gxPenLast;
|
|
pevt->y = gyPenLast;
|
|
pevt->dw = 0;
|
|
return true;
|
|
}
|
|
|
|
bool ProcessEvent(MSG *pmsg, Event *pevt)
|
|
{
|
|
// Is it something the host will not process?
|
|
|
|
switch (pmsg->message) {
|
|
#ifdef HOSTILE_TAKEOVER
|
|
case WM_RBUTTONDOWN:
|
|
#endif
|
|
case WM_LBUTTONDOWN:
|
|
case WM_LBUTTONUP:
|
|
case WM_MOUSEMOVE:
|
|
return ProcessMouseEvent(pmsg, pevt);
|
|
|
|
case WM_KEYDOWN:
|
|
ProcessKeyEvent(pmsg, pevt);
|
|
return true;
|
|
|
|
case WM_GAMEEVENT:
|
|
pevt->eType = pmsg->wParam;
|
|
pevt->dw = pmsg->lParam;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#define kcmsMouseHover 1000
|
|
|
|
bool HostGetEvent(Event *pevt, long ctWait)
|
|
{
|
|
GdiFlush();
|
|
|
|
// See if we have a hover event
|
|
|
|
if (s_msgMouseLast.message == WM_MOUSEMOVE && (GetTickCount() - s_tLastMouseMsg) >= kcmsMouseHover) {
|
|
ProcessMouseEvent(&s_msgMouseLast, pevt, true);
|
|
pevt->eType = penHoverEvent;
|
|
s_msgMouseLast.message = 0;
|
|
return true;
|
|
}
|
|
|
|
// Check for input from the queue first
|
|
|
|
MSG msg;
|
|
while (PeekMessage(&msg, NULL, 0, 0, TRUE)) {
|
|
if (ProcessEvent(&msg, pevt))
|
|
return true;
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
// No input; wait for it
|
|
|
|
if (ctWait == 0)
|
|
return false;
|
|
|
|
dword msStart = GetTickCount();
|
|
dword cmsWaitTotal = INFINITE;
|
|
if (ctWait != -1) {
|
|
cmsWaitTotal = ctWait * 10;
|
|
}
|
|
|
|
while (true) {
|
|
// false means a timeout occured
|
|
|
|
if (!WaitForInput(msStart, cmsWaitTotal))
|
|
return false;
|
|
|
|
// We have input. See if it is returnable
|
|
|
|
MSG msg;
|
|
while (PeekMessage(&msg, NULL, 0, 0, TRUE)) {
|
|
if (ProcessEvent(&msg, pevt))
|
|
return true;
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
void HostOutputDebugString(char *pszFormat, ...)
|
|
{
|
|
va_list va;
|
|
va_start(va, pszFormat);
|
|
ReporterOutputDebugString(pszFormat, va);
|
|
va_end(va);
|
|
}
|
|
|
|
long HostGetTickCount()
|
|
{
|
|
return (long)(GetTickCount() / 10);
|
|
}
|
|
|
|
long HostRunSpeedTests(DibBitmap *pbmSrc)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
dword HostGetCurrentKeyState(dword keyBit)
|
|
{
|
|
if (GetForegroundWindow() != Display::m_hwnd)
|
|
return 0;
|
|
|
|
struct KeyBitVKey {
|
|
dword keyBit;
|
|
short vk;
|
|
} s_akk[] = {
|
|
// { keyBitPower, 0 },
|
|
#ifdef HOSTILE_TAKEOVER
|
|
{ keyBitPageUp, VK_SHIFT },
|
|
{ keyBitPageUp, VK_UP },
|
|
{ keyBitPageDown, VK_DOWN },
|
|
#else
|
|
{ keyBitPageUp, VK_PRIOR },
|
|
#endif
|
|
{ keyBitPageDown, VK_NEXT },
|
|
{ keyBitHard1, VK_INSERT },
|
|
{ keyBitHard2, VK_HOME },
|
|
{ keyBitHard3, VK_DELETE },
|
|
{ keyBitHard4, VK_END },
|
|
// { keyBitCradle, 0 },
|
|
// { keyBitAntenna, 0 },
|
|
// { keyBitContrast, 0 },
|
|
{ keyBitDpadLeft, VK_LEFT },
|
|
{ keyBitDpadRight, VK_RIGHT },
|
|
{ keyBitDpadButton, VK_RETURN },
|
|
};
|
|
|
|
Assert(keyBit != 0);
|
|
|
|
dword keyBitRet = 0;
|
|
for (int i = 0; i < sizeof(s_akk) / sizeof(KeyBitVKey); i++) {
|
|
if ((keyBit & s_akk[i].keyBit) != 0) {
|
|
if (GetAsyncKeyState(s_akk[i].vk) < 0)
|
|
keyBitRet |= s_akk[i].keyBit;
|
|
}
|
|
}
|
|
|
|
return keyBitRet;
|
|
}
|
|
|
|
bool HostIsPenDown()
|
|
{
|
|
return GetAsyncKeyState(VK_LBUTTON) < 0;
|
|
}
|
|
|
|
void HostMessageBox(TCHAR *pszFormat, ...)
|
|
{
|
|
va_list va;
|
|
va_start(va, pszFormat);
|
|
TCHAR sz[512];
|
|
vsprintf(sz, pszFormat, va);
|
|
MessageBox(NULL, sz, TEXT("Message"), MB_OK);
|
|
va_end(va);
|
|
}
|
|
|
|
void HostGetUserName(char *pszBuff, int cb)
|
|
{
|
|
// Can fail if WSAStartup hasn't been called yet
|
|
|
|
if (gethostname(pszBuff, cb - 1) != 0) {
|
|
strncpyz(pszBuff, "bogus name", cb);
|
|
}
|
|
}
|
|
|
|
bool HostGetOwnerName(char *pszBuff, int cb, bool fShowError)
|
|
{
|
|
if (gethostname(pszBuff, cb - 1) != 0) {
|
|
if (fShowError)
|
|
HtMessageBox(kfMbClearDib, "Hostile Takeover", "This PC has an invalid computer name! Set the computer name and try again.");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Override packfile.h's overrides
|
|
|
|
#undef FILE
|
|
#undef fopen
|
|
#undef fclose
|
|
#undef fread
|
|
#undef fwrite
|
|
|
|
// UNDONE: prefix directory?
|
|
|
|
FileHandle HostOpenFile(const char *pszFilename, word wf)
|
|
{
|
|
char *pszMode;
|
|
if (wf == kfOfRead)
|
|
pszMode = "rb";
|
|
else if (wf == kfOfWrite)
|
|
pszMode = "wb";
|
|
else if (wf == (kfOfRead | kfOfWrite))
|
|
pszMode = "rb+";
|
|
|
|
return (FileHandle)fopen((char *)pszFilename, pszMode);
|
|
}
|
|
|
|
void HostCloseFile(FileHandle hf)
|
|
{
|
|
fclose((FILE *)hf);
|
|
}
|
|
|
|
dword HostWriteFile(FileHandle hf, void *pv, dword cb)
|
|
{
|
|
dword cbWritten = fwrite(pv, 1, cb, (FILE *)hf);
|
|
#ifdef DEBUG
|
|
fflush((FILE *)hf);
|
|
#endif
|
|
return cbWritten;
|
|
}
|
|
|
|
dword HostReadFile(FileHandle hf, void *pv, dword cb)
|
|
{
|
|
return fread(pv, 1, cb, (FILE *)hf);
|
|
}
|
|
|
|
void HostSleep(dword ct)
|
|
{
|
|
Sleep(ct * 10);
|
|
}
|
|
|
|
void HostGetSilkRect(int irc, Rect *prc)
|
|
{
|
|
RECT rcT;
|
|
switch (irc) {
|
|
case kircSilkGraffiti:
|
|
rcT.left = g_arcSilkscreen[7].left;
|
|
rcT.top = g_arcSilkscreen[7].top;
|
|
rcT.right = g_arcSilkscreen[8].right;
|
|
rcT.bottom = g_arcSilkscreen[7].bottom;
|
|
break;
|
|
|
|
case kircSilkApps:
|
|
rcT = g_arcSilkscreen[2];
|
|
break;
|
|
|
|
case kircSilkMenu:
|
|
rcT = g_arcSilkscreen[3];
|
|
break;
|
|
|
|
case kircSilkCalc:
|
|
rcT = g_arcSilkscreen[4];
|
|
break;
|
|
|
|
case kircSilkFind:
|
|
rcT = g_arcSilkscreen[5];
|
|
break;
|
|
}
|
|
|
|
GetSilkRect(&rcT, &rcT, false);
|
|
prc->left = rcT.left;
|
|
prc->top = rcT.top;
|
|
prc->right = rcT.right;
|
|
prc->bottom = rcT.bottom;
|
|
}
|
|
|
|
// Figure out what kind of sound device exists, and return a SoundDevice for it
|
|
|
|
SoundDevice *HostOpenSoundDevice()
|
|
{
|
|
return CreateWin32SoundDevice();
|
|
}
|
|
|
|
SoundDevice::~SoundDevice()
|
|
{
|
|
}
|
|
|
|
// Used for sound buffer maintenance requirements
|
|
|
|
SoundDevice *gpsnddService;
|
|
void SetSoundServiceDevice(SoundDevice *psndd)
|
|
{
|
|
gpsnddService = psndd;
|
|
}
|
|
|
|
bool HostSoundServiceProc()
|
|
{
|
|
if (gpsnddService == NULL)
|
|
return false;
|
|
gpsnddService->ServiceProc();
|
|
return true;
|
|
}
|
|
|
|
void HostGetCurrentDate(Date *pdate)
|
|
{
|
|
SYSTEMTIME time;
|
|
GetLocalTime(&time);
|
|
pdate->nYear = time.wYear;
|
|
pdate->nMonth = time.wMonth;
|
|
pdate->nDay = time.wDay;
|
|
}
|
|
|
|
#define kszRegKey TEXT("Software\\Spiffcode\\Takeover")
|
|
#define kszRegValue TEXT("Preferences")
|
|
|
|
bool HostSavePreferences(void *pv, int cb)
|
|
{
|
|
// Open key / create if it doesn't exist
|
|
|
|
HKEY hkey;
|
|
DWORD dwDisposition;
|
|
LRESULT lr = RegCreateKeyEx(HKEY_CURRENT_USER, kszRegKey, 0, "", 0, KEY_WRITE, NULL, &hkey, &dwDisposition);
|
|
if (lr != ERROR_SUCCESS)
|
|
return false;
|
|
|
|
// Set value
|
|
|
|
lr = RegSetValueEx(hkey, kszRegValue, 0, REG_BINARY, (BYTE *)pv, cb);
|
|
if (lr != ERROR_SUCCESS) {
|
|
RegCloseKey(hkey);
|
|
return false;
|
|
}
|
|
|
|
// Done
|
|
|
|
RegCloseKey(hkey);
|
|
return true;
|
|
}
|
|
|
|
int HostLoadPreferences(void *pv, int cb)
|
|
{
|
|
// Key exist?
|
|
|
|
HKEY hkey;
|
|
LRESULT lr = RegOpenKeyEx(HKEY_CURRENT_USER, kszRegKey, 0, KEY_READ, &hkey);
|
|
if (lr != ERROR_SUCCESS)
|
|
return -1;
|
|
|
|
// Read the data
|
|
|
|
dword cbT = (dword)cb;
|
|
lr = RegQueryValueEx(hkey, kszRegValue, NULL, NULL, (BYTE *)pv, &cbT);
|
|
if (lr != ERROR_SUCCESS) {
|
|
byte *pb = new byte[cbT];
|
|
lr = RegQueryValueEx(hkey, kszRegValue, NULL, NULL, (BYTE *)pb, &cbT);
|
|
if (lr == ERROR_SUCCESS) {
|
|
cbT = min(cb, (int)cbT);
|
|
memcpy(pv, pb, cbT);
|
|
delete pb;
|
|
} else {
|
|
RegCloseKey(hkey);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// Close and return size read
|
|
|
|
RegCloseKey(hkey);
|
|
return (int)cbT;
|
|
}
|
|
|
|
char *HostGetDataDirectory()
|
|
{
|
|
// The data directory is the where the executable is executing from
|
|
// On Windows, use the current directory
|
|
// On CE, use the directory the executable is in (mostly because storage cards aren't
|
|
// the "current directory" when an app is executed from the CE launcher.
|
|
|
|
char szWorkingDir[_MAX_PATH];
|
|
GetCurrentDirectory(sizeof(szWorkingDir) - 1, szWorkingDir);
|
|
|
|
// Return it
|
|
|
|
static char s_szDataDir[_MAX_PATH];
|
|
strcpy(s_szDataDir, szWorkingDir);
|
|
return s_szDataDir;
|
|
}
|
|
|
|
void HostSuspendModalLoop(DibBitmap *pbm)
|
|
{
|
|
}
|
|
|
|
void HostNotEnoughMemory(bool fStorage, dword cbFree, dword cbNeed)
|
|
{
|
|
HostMessageBox(TEXT("Need %ld bytes of memory but only %ld bytes are free!"), cbNeed, cbFree);
|
|
}
|
|
|
|
bool HostEnumAddonFiles(Enum *penm, char *pszAddon, int cb)
|
|
{
|
|
WIN32_FIND_DATA find;
|
|
|
|
if (penm->m_wUser == (word)kEnmFirst) {
|
|
penm->m_wUser = 0;
|
|
|
|
char szFileSpec[_MAX_PATH];
|
|
PrependDataDirectory("*.pdb", szFileSpec);
|
|
|
|
TCHAR szT[_MAX_PATH];
|
|
#ifdef UNICODE
|
|
MultiByteToWideChar(CP_ACP, 0, szFileSpec, -1, szT, ARRAYSIZE(szT) - 1);
|
|
#else
|
|
strcpy(szT, szFileSpec);
|
|
#endif
|
|
|
|
penm->m_pvNext = (void *)FindFirstFile(szT, &find);
|
|
if (penm->m_pvNext == NULL)
|
|
return false;
|
|
} else {
|
|
if (FindNextFile((HANDLE)penm->m_pvNext, &find) == 0) {
|
|
FindClose((HANDLE)penm->m_pvNext);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
while (true) {
|
|
// Get file
|
|
|
|
char szFilename[_MAX_PATH];
|
|
#ifdef UNICODE
|
|
WideCharToMultiByte(CP_ACP, 0, find.cFileName, -1, szFilename, ARRAYSIZE(szFilename) - 1, NULL, NULL);
|
|
#else
|
|
strcpy(szFilename, find.cFileName);
|
|
#endif
|
|
|
|
char szPath[_MAX_PATH];
|
|
PrependDataDirectory(szFilename, szPath);
|
|
|
|
// See if it is an extension file
|
|
|
|
FILE *pf = fopen(szPath, "rb");
|
|
if (pf != NULL) {
|
|
char szType[5];
|
|
szType[4] = 0;
|
|
fseek(pf, 0x3c, SEEK_SET);
|
|
fread(szType, 4, 1, pf);
|
|
fclose(pf);
|
|
if (strcmp(szType, kszTypeAddon) == 0) {
|
|
strncpyz(pszAddon, szFilename, cb);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (FindNextFile((HANDLE)penm->m_pvNext, &find) == 0) {
|
|
FindClose((HANDLE)penm->m_pvNext);
|
|
return false;
|
|
}
|
|
}
|
|
} |