mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-11 18:50:46 +00:00
- added support for ZDoom-style GAMEINFO.
This commit is contained in:
parent
af80e64ecf
commit
3b955b7c94
6 changed files with 285 additions and 20 deletions
|
@ -51,6 +51,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "st_start.h"
|
#include "st_start.h"
|
||||||
#include "s_music.h"
|
#include "s_music.h"
|
||||||
#include "i_video.h"
|
#include "i_video.h"
|
||||||
|
#include "v_text.h"
|
||||||
|
#include "resourcefile.h"
|
||||||
#include "c_dispatch.h"
|
#include "c_dispatch.h"
|
||||||
#include "glbackend/glbackend.h"
|
#include "glbackend/glbackend.h"
|
||||||
#ifndef NETCODE_DISABLE
|
#ifndef NETCODE_DISABLE
|
||||||
|
@ -62,6 +64,7 @@ MapRecord *currentLevel; // level that is currently played. (The real level, not
|
||||||
MapRecord* lastLevel; // Same here, for the last level.
|
MapRecord* lastLevel; // Same here, for the last level.
|
||||||
MapRecord userMapRecord; // stand-in for the user map.
|
MapRecord userMapRecord; // stand-in for the user map.
|
||||||
|
|
||||||
|
FStartupInfo RazeStartupInfo;
|
||||||
FMemArena dump; // this is for memory blocks than cannot be deallocated without some huge effort. Put them in here so that they do not register on shutdown.
|
FMemArena dump; // this is for memory blocks than cannot be deallocated without some huge effort. Put them in here so that they do not register on shutdown.
|
||||||
|
|
||||||
FString progdir;
|
FString progdir;
|
||||||
|
@ -70,7 +73,9 @@ void C_CON_SetAliases();
|
||||||
InputState inputState;
|
InputState inputState;
|
||||||
void SetClipshapes();
|
void SetClipshapes();
|
||||||
int ShowStartupWindow(TArray<GrpEntry> &);
|
int ShowStartupWindow(TArray<GrpEntry> &);
|
||||||
|
FString GetGameFronUserFiles();
|
||||||
void InitFileSystem(TArray<GrpEntry>&);
|
void InitFileSystem(TArray<GrpEntry>&);
|
||||||
|
void I_SetWindowTitle(const char* caption);
|
||||||
bool gHaveNetworking;
|
bool gHaveNetworking;
|
||||||
bool AppActive;
|
bool AppActive;
|
||||||
|
|
||||||
|
@ -86,6 +91,7 @@ CVAR(Bool, disableautoload, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALC
|
||||||
//CVAR(Bool, autoloadbrightmaps, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG) // hopefully this is an option for later
|
//CVAR(Bool, autoloadbrightmaps, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG) // hopefully this is an option for later
|
||||||
//CVAR(Bool, autoloadlights, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG)
|
//CVAR(Bool, autoloadlights, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG)
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
@ -443,6 +449,12 @@ static TArray<GrpEntry> SetupGame()
|
||||||
|
|
||||||
// If the user has specified a file name, let's see if we know it.
|
// If the user has specified a file name, let's see if we know it.
|
||||||
//
|
//
|
||||||
|
FString game = GetGameFronUserFiles();
|
||||||
|
if (userConfig.gamegrp.IsEmpty())
|
||||||
|
{
|
||||||
|
userConfig.gamegrp = game;
|
||||||
|
}
|
||||||
|
|
||||||
if (userConfig.gamegrp.Len())
|
if (userConfig.gamegrp.Len())
|
||||||
{
|
{
|
||||||
FString gamegrplower = "/" + userConfig.gamegrp.MakeLower();
|
FString gamegrplower = "/" + userConfig.gamegrp.MakeLower();
|
||||||
|
@ -461,7 +473,6 @@ static TArray<GrpEntry> SetupGame()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (groupno == -1)
|
if (groupno == -1)
|
||||||
{
|
{
|
||||||
int pick = 0;
|
int pick = 0;
|
||||||
|
@ -510,6 +521,9 @@ static TArray<GrpEntry> SetupGame()
|
||||||
if (groupno == -1) return TArray<GrpEntry>();
|
if (groupno == -1) return TArray<GrpEntry>();
|
||||||
auto& group = groups[groupno];
|
auto& group = groups[groupno];
|
||||||
|
|
||||||
|
if (RazeStartupInfo.Name.IsNotEmpty()) I_SetWindowTitle(RazeStartupInfo.Name);
|
||||||
|
else I_SetWindowTitle(group.FileInfo.name);
|
||||||
|
|
||||||
// Now filter out the data we actually need and delete the rest.
|
// Now filter out the data we actually need and delete the rest.
|
||||||
|
|
||||||
usedgroups.Push(group);
|
usedgroups.Push(group);
|
||||||
|
|
|
@ -157,3 +157,17 @@ void S_SetSoundPaused(int state);
|
||||||
|
|
||||||
void G_HandleMemErr(int32_t lineNum, const char* fileName, const char* funcName);
|
void G_HandleMemErr(int32_t lineNum, const char* fileName, const char* funcName);
|
||||||
void G_FatalEngineError(void);
|
void G_FatalEngineError(void);
|
||||||
|
|
||||||
|
|
||||||
|
struct FStartupInfo
|
||||||
|
{
|
||||||
|
FString Name;
|
||||||
|
uint32_t FgColor; // Foreground color for title banner
|
||||||
|
uint32_t BkColor; // Background color for title banner
|
||||||
|
//FString Song;
|
||||||
|
//int Type;
|
||||||
|
//int LoadLights = -1;
|
||||||
|
//int LoadBrightmaps = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern FStartupInfo RazeStartupInfo;
|
|
@ -42,6 +42,9 @@
|
||||||
#include "printf.h"
|
#include "printf.h"
|
||||||
#include "m_argv.h"
|
#include "m_argv.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "sc_man.h"
|
||||||
|
#include "v_video.h"
|
||||||
|
#include "v_text.h"
|
||||||
#include "../platform/win32/i_findfile.h" // This is a temporary direct path. Needs to be fixed when stuff gets cleaned up.
|
#include "../platform/win32/i_findfile.h" // This is a temporary direct path. Needs to be fixed when stuff gets cleaned up.
|
||||||
|
|
||||||
#ifndef PATH_MAX
|
#ifndef PATH_MAX
|
||||||
|
@ -268,7 +271,7 @@ static void D_AddDirectory (TArray<FString> &wadfiles, const char *dir)
|
||||||
{
|
{
|
||||||
skindir[stuffstart++] = '/';
|
skindir[stuffstart++] = '/';
|
||||||
int savedstart = stuffstart;
|
int savedstart = stuffstart;
|
||||||
static const char* validexts[] = { "*.grp", "*.zip", "*.pk3", "*.pk4", "*.7z", "*.pk7", "*.dat" };
|
static const char* validexts[] = { "*.grp", "*.zip", "*.pk3", "*.pk4", "*.7z", "*.pk7", "*.dat", "*.rff" };
|
||||||
for (auto ext : validexts)
|
for (auto ext : validexts)
|
||||||
{
|
{
|
||||||
stuffstart = savedstart;
|
stuffstart = savedstart;
|
||||||
|
@ -290,6 +293,186 @@ static void D_AddDirectory (TArray<FString> &wadfiles, const char *dir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
static FString ParseGameInfo(TArray<FString>& pwads, const char* fn, const char* data, int size)
|
||||||
|
{
|
||||||
|
FScanner sc;
|
||||||
|
FString iwad;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
const char* lastSlash = strrchr(fn, '/');
|
||||||
|
|
||||||
|
sc.OpenMem("GAMEINFO", data, size);
|
||||||
|
sc.SetCMode(true);
|
||||||
|
while (sc.GetToken())
|
||||||
|
{
|
||||||
|
sc.TokenMustBe(TK_Identifier);
|
||||||
|
FString nextKey = sc.String;
|
||||||
|
sc.MustGetToken('=');
|
||||||
|
if (!nextKey.CompareNoCase("GAME"))
|
||||||
|
{
|
||||||
|
sc.MustGetString();
|
||||||
|
iwad = sc.String;
|
||||||
|
}
|
||||||
|
else if (!nextKey.CompareNoCase("LOAD"))
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
sc.MustGetString();
|
||||||
|
|
||||||
|
// Try looking for the wad in the same directory as the .wad
|
||||||
|
// before looking for it in the current directory.
|
||||||
|
|
||||||
|
FString checkpath;
|
||||||
|
if (lastSlash != NULL)
|
||||||
|
{
|
||||||
|
checkpath = FString(fn, (lastSlash - fn) + 1);
|
||||||
|
checkpath += sc.String;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
checkpath = sc.String;
|
||||||
|
}
|
||||||
|
if (!FileExists(checkpath))
|
||||||
|
{
|
||||||
|
pos += D_AddFile(pwads, sc.String, true, pos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos += D_AddFile(pwads, checkpath, true, pos);
|
||||||
|
}
|
||||||
|
} while (sc.CheckToken(','));
|
||||||
|
}
|
||||||
|
else if (!nextKey.CompareNoCase("STARTUPTITLE"))
|
||||||
|
{
|
||||||
|
sc.MustGetString();
|
||||||
|
RazeStartupInfo.Name = sc.String;
|
||||||
|
}
|
||||||
|
else if (!nextKey.CompareNoCase("STARTUPCOLORS"))
|
||||||
|
{
|
||||||
|
sc.MustGetString();
|
||||||
|
RazeStartupInfo.FgColor = V_GetColor(NULL, sc);
|
||||||
|
sc.MustGetStringName(",");
|
||||||
|
sc.MustGetString();
|
||||||
|
RazeStartupInfo.BkColor = V_GetColor(NULL, sc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Silently ignore unknown properties
|
||||||
|
do
|
||||||
|
{
|
||||||
|
sc.MustGetAnyToken();
|
||||||
|
} while (sc.CheckToken(','));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return iwad;
|
||||||
|
}
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
static FString CheckGameInfo(TArray<FString>& pwads)
|
||||||
|
{
|
||||||
|
// scan the list of WADs backwards to find the last one that contains a GAMEINFO lump
|
||||||
|
for (int i = pwads.Size() - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
bool isdir = false;
|
||||||
|
FResourceFile* resfile;
|
||||||
|
const char* filename = pwads[i];
|
||||||
|
|
||||||
|
// Does this exist? If so, is it a directory?
|
||||||
|
if (!DirEntryExists(pwads[i], &isdir))
|
||||||
|
{
|
||||||
|
Printf(TEXTCOLOR_RED "Could not find %s\n", filename);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isdir)
|
||||||
|
{
|
||||||
|
FileReader fr;
|
||||||
|
if (!fr.OpenFile(filename))
|
||||||
|
{
|
||||||
|
// Didn't find file
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
resfile = FResourceFile::OpenResourceFile(filename, fr, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
resfile = FResourceFile::OpenDirectory(filename, true);
|
||||||
|
|
||||||
|
FName gameinfo = "GAMEINFO.TXT";
|
||||||
|
if (resfile != NULL)
|
||||||
|
{
|
||||||
|
uint32_t cnt = resfile->LumpCount();
|
||||||
|
for (int i = cnt - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
FResourceLump* lmp = resfile->GetLump(i);
|
||||||
|
|
||||||
|
if (lmp->LumpName[0] == gameinfo)
|
||||||
|
{
|
||||||
|
// Found one!
|
||||||
|
FString iwad = ParseGameInfo(pwads, resfile->FileName, (const char*)lmp->Lock(), lmp->LumpSize);
|
||||||
|
delete resfile;
|
||||||
|
return iwad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete resfile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FString GetGameFronUserFiles()
|
||||||
|
{
|
||||||
|
TArray<FString> Files;
|
||||||
|
|
||||||
|
if (userConfig.AddFilesPre) for (auto& file : *userConfig.AddFilesPre)
|
||||||
|
{
|
||||||
|
D_AddFile(Files, file);
|
||||||
|
}
|
||||||
|
if (userConfig.AddFiles)
|
||||||
|
{
|
||||||
|
for (auto& file : *userConfig.AddFiles)
|
||||||
|
{
|
||||||
|
D_AddFile(Files, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, if the last entry in the chain is a directory, it's being considered the mod directory, and all GRPs inside need to be loaded, too.
|
||||||
|
if (userConfig.AddFiles->NumArgs() > 0)
|
||||||
|
{
|
||||||
|
auto fn = (*userConfig.AddFiles)[userConfig.AddFiles->NumArgs() - 1];
|
||||||
|
bool isdir = false;
|
||||||
|
if (DirEntryExists(fn, &isdir) && isdir)
|
||||||
|
{
|
||||||
|
// Insert the GRPs before this entry itself.
|
||||||
|
FString lastfn;
|
||||||
|
Files.Pop(lastfn);
|
||||||
|
D_AddDirectory(Files, fn);
|
||||||
|
Files.Push(lastfn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CheckGameInfo(Files);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
void InitFileSystem(TArray<GrpEntry>& groups)
|
void InitFileSystem(TArray<GrpEntry>& groups)
|
||||||
{
|
{
|
||||||
|
@ -338,6 +521,20 @@ void InitFileSystem(TArray<GrpEntry>& groups)
|
||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* key;
|
||||||
|
const char* value;
|
||||||
|
if (GameConfig->SetSection("global.Autoload"))
|
||||||
|
{
|
||||||
|
while (GameConfig->NextInSection(key, value))
|
||||||
|
{
|
||||||
|
if (stricmp(key, "Path") == 0)
|
||||||
|
{
|
||||||
|
FString nice = NicePath(value);
|
||||||
|
D_AddFile(Files, nice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!insertdirectoriesafter && userConfig.AddFilesPre) for (auto& file : *userConfig.AddFilesPre)
|
if (!insertdirectoriesafter && userConfig.AddFilesPre) for (auto& file : *userConfig.AddFilesPre)
|
||||||
{
|
{
|
||||||
D_AddFile(Files, file);
|
D_AddFile(Files, file);
|
||||||
|
@ -364,19 +561,7 @@ void InitFileSystem(TArray<GrpEntry>& groups)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const char* key;
|
|
||||||
const char* value;
|
|
||||||
if (GameConfig->SetSection("global.Autoload"))
|
|
||||||
{
|
|
||||||
while (GameConfig->NextInSection(key, value))
|
|
||||||
{
|
|
||||||
if (stricmp(key, "Path") == 0)
|
|
||||||
{
|
|
||||||
FString nice = NicePath(value);
|
|
||||||
D_AddFile(Files, nice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TArray<FString> todelete;
|
TArray<FString> todelete;
|
||||||
for (auto& g : groups)
|
for (auto& g : groups)
|
||||||
|
|
|
@ -102,6 +102,7 @@ public:
|
||||||
FString TakeValue(const char *check);
|
FString TakeValue(const char *check);
|
||||||
int NumArgs() const;
|
int NumArgs() const;
|
||||||
void FlushArgs();
|
void FlushArgs();
|
||||||
|
TArray<FString>& Array() { return Argv; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TArray<FString> Argv;
|
TArray<FString> Argv;
|
||||||
|
|
|
@ -336,17 +336,17 @@ void FConsoleWindow::SetTitleText()
|
||||||
// It's used in graphical startup screen, with Hexen style in particular
|
// It's used in graphical startup screen, with Hexen style in particular
|
||||||
// Native OS X backend doesn't implement this yet
|
// Native OS X backend doesn't implement this yet
|
||||||
|
|
||||||
if (DoomStartupInfo.FgColor == DoomStartupInfo.BkColor)
|
if (RazeStartupInfo.FgColor == RazeStartupInfo.BkColor)
|
||||||
{
|
{
|
||||||
DoomStartupInfo.FgColor = ~DoomStartupInfo.FgColor;
|
RazeStartupInfo.FgColor = ~RazeStartupInfo.FgColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSTextField* titleText = [[NSTextField alloc] initWithFrame:titleTextRect];
|
NSTextField* titleText = [[NSTextField alloc] initWithFrame:titleTextRect];
|
||||||
[titleText setStringValue:[NSString stringWithCString:DoomStartupInfo.Name
|
[titleText setStringValue:[NSString stringWithCString:RazeStartupInfo.Name
|
||||||
encoding:NSISOLatin1StringEncoding]];
|
encoding:NSISOLatin1StringEncoding]];
|
||||||
[titleText setAlignment:NSCenterTextAlignment];
|
[titleText setAlignment:NSCenterTextAlignment];
|
||||||
[titleText setTextColor:RGB(DoomStartupInfo.FgColor)];
|
[titleText setTextColor:RGB(RazeStartupInfo.FgColor)];
|
||||||
[titleText setBackgroundColor:RGB(DoomStartupInfo.BkColor)];
|
[titleText setBackgroundColor:RGB(RazeStartupInfo.BkColor)];
|
||||||
[titleText setFont:[NSFont fontWithName:@"Trebuchet MS Bold" size:18.0f]];
|
[titleText setFont:[NSFont fontWithName:@"Trebuchet MS Bold" size:18.0f]];
|
||||||
[titleText setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
|
[titleText setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
|
||||||
[titleText setSelectable:NO];
|
[titleText setSelectable:NO];
|
||||||
|
|
|
@ -426,6 +426,57 @@ LRESULT CALLBACK LConProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
case WM_DRAWITEM:
|
||||||
|
// Draw title banner.
|
||||||
|
if (wParam == IDC_STATIC_TITLE && RazeStartupInfo.Name.IsNotEmpty())
|
||||||
|
{
|
||||||
|
const PalEntry *c;
|
||||||
|
|
||||||
|
// Draw the game title strip at the top of the window.
|
||||||
|
auto drawitem = (LPDRAWITEMSTRUCT)lParam;
|
||||||
|
SIZE size;
|
||||||
|
|
||||||
|
// Draw the background.
|
||||||
|
auto rect = drawitem->rcItem;
|
||||||
|
rect.bottom -= 1;
|
||||||
|
c = (const PalEntry *)&RazeStartupInfo.BkColor;
|
||||||
|
auto hbr = CreateSolidBrush (RGB(c->r,c->g,c->b));
|
||||||
|
FillRect (drawitem->hDC, &drawitem->rcItem, hbr);
|
||||||
|
DeleteObject (hbr);
|
||||||
|
|
||||||
|
// Calculate width of the title string.
|
||||||
|
SetTextAlign (drawitem->hDC, TA_TOP);
|
||||||
|
oldfont = SelectObject (drawitem->hDC, GameTitleFont != NULL ? GameTitleFont : (HFONT)GetStockObject (DEFAULT_GUI_FONT));
|
||||||
|
auto widename = RazeStartupInfo.Name.WideString();
|
||||||
|
GetTextExtentPoint32W (drawitem->hDC, widename.c_str(), (int)widename.length(), &size);
|
||||||
|
|
||||||
|
// Draw the title.
|
||||||
|
c = (const PalEntry *)&RazeStartupInfo.FgColor;
|
||||||
|
SetTextColor (drawitem->hDC, RGB(c->r,c->g,c->b));
|
||||||
|
SetBkMode (drawitem->hDC, TRANSPARENT);
|
||||||
|
TextOutW (drawitem->hDC, rect.left + (rect.right - rect.left - size.cx) / 2, 2, widename.c_str(), (int)widename.length());
|
||||||
|
SelectObject (drawitem->hDC, oldfont);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
// Draw stop icon.
|
||||||
|
else if (wParam == IDC_ICONPIC)
|
||||||
|
{
|
||||||
|
HICON icon;
|
||||||
|
POINTL char_pos;
|
||||||
|
auto drawitem = (LPDRAWITEMSTRUCT)lParam;
|
||||||
|
|
||||||
|
// This background color should match the edit control's.
|
||||||
|
auto hbr = CreateSolidBrush (RGB(70,70,70));
|
||||||
|
FillRect (drawitem->hDC, &drawitem->rcItem, hbr);
|
||||||
|
DeleteObject (hbr);
|
||||||
|
|
||||||
|
// Draw the icon aligned with the first line of error text.
|
||||||
|
SendMessage (ConWindow, EM_POSFROMCHAR, (WPARAM)&char_pos, ErrorIconChar);
|
||||||
|
icon = (HICON)LoadImage (0, IDI_ERROR, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
|
||||||
|
DrawIcon (drawitem->hDC, 6, char_pos.y, icon);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
case WM_COMMAND:
|
case WM_COMMAND:
|
||||||
if (ErrorIcon != NULL && (HWND)lParam == ConWindow && HIWORD(wParam) == EN_UPDATE)
|
if (ErrorIcon != NULL && (HWND)lParam == ConWindow && HIWORD(wParam) == EN_UPDATE)
|
||||||
|
|
Loading…
Reference in a new issue