Browse Source

Use SDL events directly

Removes redundant miniwin events and queue, using SDL events directly instead.

Demo migrated using this script: https://gist.github.com/glebm/8a73b04f695de96f344cc2e35151e03e
pull/5182/head
Gleb Mazovetskiy 4 years ago committed by Anders Jenbo
parent
commit
ba34bafb3f
  1. 9
      Source/debug.cpp
  2. 177
      Source/diablo.cpp
  3. 2
      Source/diablo.h
  4. 188
      Source/engine/demomode.cpp
  5. 6
      Source/engine/demomode.h
  6. 43
      Source/init.cpp
  7. 2
      Source/init.h
  8. 35
      Source/interfac.cpp
  9. 33
      Source/interfac.h
  10. 180
      Source/miniwin/misc_msg.cpp
  11. 41
      Source/miniwin/misc_msg.h
  12. 16
      Source/movie.cpp
  13. 12
      Source/player.cpp
  14. 1
      Source/utils/display.cpp
  15. BIN
      test/fixtures/timedemo/WarriorLevel1to2/demo_0.dmo

9
Source/debug.cpp

@ -116,14 +116,15 @@ void PrintDebugMonster(const Monster &monster)
void ProcessMessages() void ProcessMessages()
{ {
tagMSG msg; SDL_Event event;
while (FetchMessage(&msg)) { uint16_t modState;
if (msg.message == DVL_WM_QUIT) { while (FetchMessage(&event, &modState)) {
if (event.type == SDL_QUIT) {
gbRunGameResult = false; gbRunGameResult = false;
gbRunGame = false; gbRunGame = false;
break; break;
} }
PushMessage(&msg); HandleMessage(event, modState);
} }
} }

177
Source/diablo.cpp

@ -594,110 +594,79 @@ void PressKey(SDL_Keycode vkey, uint16_t modState)
} }
} }
void GetMousePos(uint32_t lParam) void GameEventHandler(const SDL_Event &event, uint16_t modState)
{ {
MousePosition = { (std::int16_t)(lParam & 0xffff), (std::int16_t)((lParam >> 16) & 0xffff) }; switch (event.type) {
} case SDL_KEYDOWN:
PressKey(event.key.keysym.sym, modState);
void GameEventHandler(uint32_t uMsg, uint32_t wParam, uint16_t lParam)
{
switch (uMsg) {
case DVL_WM_KEYDOWN:
PressKey(static_cast<SDL_Keycode>(wParam), lParam);
return; return;
case DVL_WM_KEYUP: case SDL_KEYUP:
ReleaseKey(static_cast<SDL_Keycode>(wParam)); ReleaseKey(event.key.keysym.sym);
return; return;
case DVL_WM_MOUSEMOVE: case SDL_MOUSEMOTION:
GetMousePos(wParam); MousePosition = { event.motion.x, event.motion.y };
gmenu_on_mouse_move(); gmenu_on_mouse_move();
return; return;
case DVL_WM_LBUTTONDOWN: case SDL_MOUSEBUTTONDOWN:
GetMousePos(wParam); MousePosition = { event.button.x, event.button.y };
if (sgbMouseDown == CLICK_NONE) { if (sgbMouseDown == CLICK_NONE) {
sgbMouseDown = CLICK_LEFT; switch (event.button.button) {
LeftMouseDown(lParam); case SDL_BUTTON_LEFT:
sgbMouseDown = CLICK_LEFT;
LeftMouseDown(modState);
break;
case SDL_BUTTON_RIGHT:
sgbMouseDown = CLICK_RIGHT;
RightMouseDown((modState & KMOD_SHIFT) != 0);
break;
default:
sgOptions.Keymapper.KeyPressed(event.button.button | KeymapperMouseButtonMask);
break;
}
} }
return; return;
case DVL_WM_LBUTTONUP: case SDL_MOUSEBUTTONUP:
GetMousePos(wParam); MousePosition = { event.button.x, event.button.y };
if (sgbMouseDown == CLICK_LEFT) {
if (sgbMouseDown == CLICK_LEFT && event.button.button == SDL_BUTTON_LEFT) {
LastMouseButtonAction = MouseActionType::None; LastMouseButtonAction = MouseActionType::None;
sgbMouseDown = CLICK_NONE; sgbMouseDown = CLICK_NONE;
LeftMouseUp(lParam); LeftMouseUp(modState);
} } else if (sgbMouseDown == CLICK_RIGHT && event.button.button == SDL_BUTTON_RIGHT) {
return; LastMouseButtonAction = MouseActionType::None;
case DVL_WM_RBUTTONDOWN: sgbMouseDown = CLICK_NONE;
GetMousePos(wParam); } else {
if (sgbMouseDown == CLICK_NONE) { sgOptions.Keymapper.KeyReleased(event.button.button | KeymapperMouseButtonMask);
sgbMouseDown = CLICK_RIGHT;
RightMouseDown((lParam & KMOD_SHIFT) != 0);
} }
return; return;
case DVL_WM_RBUTTONUP: default:
GetMousePos(wParam); if (IsCustomEvent(event.type)) {
if (sgbMouseDown == CLICK_RIGHT) { if (gbIsMultiplayer)
pfile_write_hero();
nthread_ignore_mutex(true);
PaletteFadeOut(8);
sound_stop();
LastMouseButtonAction = MouseActionType::None; LastMouseButtonAction = MouseActionType::None;
sgbMouseDown = CLICK_NONE; sgbMouseDown = CLICK_NONE;
ShowProgress(GetCustomEvent(event.type));
force_redraw = 255;
DrawAndBlit();
LoadPWaterPalette();
if (gbRunGame)
PaletteFadeIn(8);
nthread_ignore_mutex(false);
gbGameLoopStartup = true;
return;
} }
return; MainWndProc(event);
case DVL_WM_MBUTTONDOWN:
sgOptions.Keymapper.KeyPressed(SDL_BUTTON_MIDDLE | KeymapperMouseButtonMask);
return;
case DVL_WM_MBUTTONUP:
sgOptions.Keymapper.KeyReleased(SDL_BUTTON_MIDDLE | KeymapperMouseButtonMask);
return;
case DVL_WM_X1BUTTONDOWN:
sgOptions.Keymapper.KeyPressed(SDL_BUTTON_X1 | KeymapperMouseButtonMask);
return;
case DVL_WM_X1BUTTONUP:
sgOptions.Keymapper.KeyReleased(SDL_BUTTON_X1 | KeymapperMouseButtonMask);
return;
case DVL_WM_X2BUTTONDOWN:
sgOptions.Keymapper.KeyPressed(SDL_BUTTON_X2 | KeymapperMouseButtonMask);
return;
case DVL_WM_X2BUTTONUP:
sgOptions.Keymapper.KeyReleased(SDL_BUTTON_X2 | KeymapperMouseButtonMask);
return;
case DVL_WM_CAPTURECHANGED:
sgbMouseDown = CLICK_NONE;
LastMouseButtonAction = MouseActionType::None;
break; break;
case WM_DIABNEXTLVL:
case WM_DIABPREVLVL:
case WM_DIABRTNLVL:
case WM_DIABSETLVL:
case WM_DIABWARPLVL:
case WM_DIABTOWNWARP:
case WM_DIABTWARPUP:
case WM_DIABRETOWN:
if (gbIsMultiplayer)
pfile_write_hero();
nthread_ignore_mutex(true);
PaletteFadeOut(8);
sound_stop();
LastMouseButtonAction = MouseActionType::None;
sgbMouseDown = CLICK_NONE;
ShowProgress((interface_mode)uMsg);
force_redraw = 255;
DrawAndBlit();
LoadPWaterPalette();
if (gbRunGame)
PaletteFadeIn(8);
nthread_ignore_mutex(false);
gbGameLoopStartup = true;
return;
} }
MainWndProc(uMsg);
} }
void RunGameLoop(interface_mode uMsg) void RunGameLoop(interface_mode uMsg)
{ {
demo::NotifyGameLoopStart(); demo::NotifyGameLoopStart();
tagMSG msg;
nthread_ignore_mutex(true); nthread_ignore_mutex(true);
StartGame(uMsg); StartGame(uMsg);
assert(HeadlessMode || ghMainWnd); assert(HeadlessMode || ghMainWnd);
@ -730,13 +699,15 @@ void RunGameLoop(interface_mode uMsg)
} }
#endif #endif
while (FetchMessage(&msg)) { SDL_Event event;
if (msg.message == DVL_WM_QUIT) { uint16_t modState;
while (FetchMessage(&event, &modState)) {
if (event.type == SDL_QUIT) {
gbRunGameResult = false; gbRunGameResult = false;
gbRunGame = false; gbRunGame = false;
break; break;
} }
PushMessage(&msg); HandleMessage(event, modState);
} }
if (!gbRunGame) if (!gbRunGame)
break; break;
@ -2015,41 +1986,31 @@ bool PressEscKey()
return rv; return rv;
} }
void DisableInputEventHandler(uint32_t uMsg, uint32_t wParam, uint16_t /*lParam*/) void DisableInputEventHandler(const SDL_Event &event, uint16_t modState)
{ {
switch (uMsg) { switch (event.type) {
case DVL_WM_KEYDOWN: case SDL_MOUSEMOTION:
case DVL_WM_KEYUP: MousePosition = { event.motion.x, event.motion.y };
return;
case DVL_WM_MOUSEMOVE:
GetMousePos(wParam);
return; return;
case DVL_WM_LBUTTONDOWN: case SDL_MOUSEBUTTONDOWN:
if (sgbMouseDown != CLICK_NONE) if (sgbMouseDown != CLICK_NONE)
return; return;
sgbMouseDown = CLICK_LEFT; switch (event.button.button) {
return; case SDL_BUTTON_LEFT:
case DVL_WM_LBUTTONUP: sgbMouseDown = CLICK_LEFT;
if (sgbMouseDown != CLICK_LEFT)
return; return;
sgbMouseDown = CLICK_NONE; case SDL_BUTTON_RIGHT:
return; sgbMouseDown = CLICK_RIGHT;
case DVL_WM_RBUTTONDOWN:
if (sgbMouseDown != CLICK_NONE)
return; return;
sgbMouseDown = CLICK_RIGHT; default:
return;
case DVL_WM_RBUTTONUP:
if (sgbMouseDown != CLICK_RIGHT)
return; return;
sgbMouseDown = CLICK_NONE; }
return; case SDL_MOUSEBUTTONUP:
case DVL_WM_CAPTURECHANGED:
sgbMouseDown = CLICK_NONE; sgbMouseDown = CLICK_NONE;
return; return;
} }
MainWndProc(uMsg); MainWndProc(event);
} }
void LoadGameLevel(bool firstflag, lvl_entry lvldir) void LoadGameLevel(bool firstflag, lvl_entry lvldir)

2
Source/diablo.h

@ -93,7 +93,7 @@ bool diablo_is_focused();
void diablo_focus_pause(); void diablo_focus_pause();
void diablo_focus_unpause(); void diablo_focus_unpause();
bool PressEscKey(); bool PressEscKey();
void DisableInputEventHandler(uint32_t uMsg, uint32_t wParam, uint16_t lParam); void DisableInputEventHandler(const SDL_Event &event, uint16_t modState);
void LoadGameLevel(bool firstflag, lvl_entry lvldir); void LoadGameLevel(bool firstflag, lvl_entry lvldir);
/** /**

188
Source/engine/demomode.cpp

@ -25,12 +25,39 @@ enum class DemoMsgType {
Message = 2, Message = 2,
}; };
struct MouseMotionEventData {
uint16_t x;
uint16_t y;
};
struct MouseButtonEventData {
uint8_t button;
uint16_t x;
uint16_t y;
uint16_t mod;
};
struct MouseWheelEventData {
int32_t x;
int32_t y;
uint16_t mod;
};
struct KeyEventData {
SDL_Keycode sym;
SDL_Keymod mod;
};
struct DemoMsg { struct DemoMsg {
DemoMsgType type; DemoMsgType type;
uint32_t message;
uint32_t wParam;
uint16_t lParam;
float progressToNextGameTick; float progressToNextGameTick;
SDL_EventType eventType;
union {
MouseMotionEventData motion;
MouseButtonEventData button;
MouseWheelEventData wheel;
KeyEventData key;
};
}; };
int DemoNumber = -1; int DemoNumber = -1;
@ -48,11 +75,6 @@ int StartTime = 0;
uint16_t DemoGraphicsWidth = 640; uint16_t DemoGraphicsWidth = 640;
uint16_t DemoGraphicsHeight = 480; uint16_t DemoGraphicsHeight = 480;
void PumpDemoMessage(DemoMsgType demoMsgType, uint32_t message, uint32_t wParam, uint16_t lParam, float progressToNextGameTick)
{
Demo_Message_Queue.push_back(DemoMsg { demoMsgType, message, wParam, lParam, progressToNextGameTick });
}
bool LoadDemoMessages(int i) bool LoadDemoMessages(int i)
{ {
std::ifstream demofile; std::ifstream demofile;
@ -78,14 +100,45 @@ bool LoadDemoMessages(int i)
switch (type) { switch (type) {
case DemoMsgType::Message: { case DemoMsgType::Message: {
const uint32_t message = ReadLE32(demofile); const auto eventType = static_cast<SDL_EventType>(ReadLE32(demofile));
const uint32_t wParam = ReadLE32(demofile); DemoMsg msg { type, progressToNextGameTick, eventType, {} };
const uint16_t lParam = ReadLE16(demofile); switch (eventType) {
PumpDemoMessage(type, message, wParam, lParam, progressToNextGameTick); case SDL_MOUSEMOTION:
msg.motion.x = ReadLE16(demofile);
msg.motion.y = ReadLE16(demofile);
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
msg.button.button = ReadByte(demofile);
msg.button.x = ReadLE16(demofile);
msg.button.y = ReadLE16(demofile);
msg.button.mod = ReadLE16(demofile);
break;
#ifndef USE_SDL1
case SDL_MOUSEWHEEL:
msg.wheel.x = ReadLE32<int32_t>(demofile);
msg.wheel.y = ReadLE32<int32_t>(demofile);
msg.wheel.mod = ReadLE16(demofile);
break;
#endif
case SDL_KEYDOWN:
case SDL_KEYUP:
msg.key.sym = static_cast<SDL_Keycode>(ReadLE32(demofile));
msg.key.mod = static_cast<SDL_Keymod>(ReadLE16(demofile));
break;
case SDL_QUIT:
break;
default:
if (eventType < SDL_USEREVENT) {
app_fatal(StrCat("Unknown event ", static_cast<uint32_t>(eventType)));
}
break;
}
Demo_Message_Queue.push_back(msg);
break; break;
} }
default: default:
PumpDemoMessage(type, 0, 0, 0, progressToNextGameTick); Demo_Message_Queue.push_back(DemoMsg { type, progressToNextGameTick, static_cast<SDL_EventType>(0), {} });
break; break;
} }
} }
@ -97,6 +150,13 @@ bool LoadDemoMessages(int i)
return true; return true;
} }
void RecordEventHeader(const SDL_Event &event)
{
WriteLE32(DemoRecording, static_cast<uint32_t>(DemoMsgType::Message));
WriteLEFloat(DemoRecording, gfProgressToNextGameTick);
WriteLE32(DemoRecording, event.type);
}
} // namespace } // namespace
namespace demo { namespace demo {
@ -180,19 +240,16 @@ bool GetRunGameLoop(bool &drawGame, bool &processInput)
return dmsg.type == DemoMsgType::GameTick; return dmsg.type == DemoMsgType::GameTick;
} }
bool FetchMessage(tagMSG *lpMsg) bool FetchMessage(SDL_Event *event, uint16_t *modState)
{ {
SDL_Event e; SDL_Event e;
if (SDL_PollEvent(&e) != 0) { if (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) { if (e.type == SDL_QUIT) {
lpMsg->message = DVL_WM_QUIT; *event = e;
lpMsg->wParam = 0;
lpMsg->lParam = 0;
return true; return true;
} }
if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE) { if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE) {
Demo_Message_Queue.clear(); Demo_Message_Queue.clear();
ClearMessageQueue();
DemoNumber = -1; DemoNumber = -1;
Timedemo = false; Timedemo = false;
last_tick = SDL_GetTicks(); last_tick = SDL_GetTicks();
@ -212,19 +269,45 @@ bool FetchMessage(tagMSG *lpMsg)
if (!Demo_Message_Queue.empty()) { if (!Demo_Message_Queue.empty()) {
const DemoMsg dmsg = Demo_Message_Queue.front(); const DemoMsg dmsg = Demo_Message_Queue.front();
if (dmsg.type == DemoMsgType::Message) { if (dmsg.type == DemoMsgType::Message) {
lpMsg->message = dmsg.message; event->type = dmsg.eventType;
lpMsg->wParam = dmsg.wParam; switch (dmsg.eventType) {
lpMsg->lParam = dmsg.lParam; case SDL_MOUSEMOTION:
event->motion.x = dmsg.motion.x;
event->motion.y = dmsg.motion.y;
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
event->button.button = dmsg.button.button;
event->button.state = dmsg.eventType == SDL_MOUSEBUTTONDOWN ? SDL_PRESSED : SDL_RELEASED;
event->button.x = dmsg.button.x;
event->button.y = dmsg.button.y;
*modState = dmsg.button.mod;
break;
#ifndef USE_SDL1
case SDL_MOUSEWHEEL:
event->wheel.x = dmsg.wheel.x;
event->wheel.y = dmsg.wheel.y;
*modState = dmsg.wheel.mod;
break;
#endif
case SDL_KEYDOWN:
case SDL_KEYUP:
event->key.state = dmsg.eventType == SDL_KEYDOWN ? SDL_PRESSED : SDL_RELEASED;
event->key.keysym.sym = dmsg.key.sym;
event->key.keysym.mod = dmsg.key.mod;
break;
default:
if (dmsg.eventType >= SDL_USEREVENT) {
event->type = CustomEventToSdlEvent(static_cast<interface_mode>(dmsg.eventType - SDL_USEREVENT));
}
break;
}
gfProgressToNextGameTick = dmsg.progressToNextGameTick; gfProgressToNextGameTick = dmsg.progressToNextGameTick;
Demo_Message_Queue.pop_front(); Demo_Message_Queue.pop_front();
return true; return true;
} }
} }
lpMsg->message = 0;
lpMsg->wParam = 0;
lpMsg->lParam = 0;
return false; return false;
} }
@ -234,15 +317,58 @@ void RecordGameLoopResult(bool runGameLoop)
WriteLEFloat(DemoRecording, gfProgressToNextGameTick); WriteLEFloat(DemoRecording, gfProgressToNextGameTick);
} }
void RecordMessage(tagMSG *lpMsg) void RecordMessage(const SDL_Event &event, uint16_t modState)
{ {
if (!gbRunGame || !DemoRecording.is_open()) if (!gbRunGame || !DemoRecording.is_open())
return; return;
WriteLE32(DemoRecording, static_cast<uint32_t>(DemoMsgType::Message)); switch (event.type) {
WriteLEFloat(DemoRecording, gfProgressToNextGameTick); case SDL_MOUSEMOTION:
WriteLE32(DemoRecording, lpMsg->message); RecordEventHeader(event);
WriteLE32(DemoRecording, lpMsg->wParam); WriteLE16(DemoRecording, event.motion.x);
WriteLE16(DemoRecording, lpMsg->lParam); WriteLE16(DemoRecording, event.motion.y);
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
RecordEventHeader(event);
WriteByte(DemoRecording, event.button.button);
WriteLE16(DemoRecording, event.button.x);
WriteLE16(DemoRecording, event.button.y);
WriteLE16(DemoRecording, modState);
break;
#ifndef USE_SDL1
case SDL_MOUSEWHEEL:
RecordEventHeader(event);
WriteLE32(DemoRecording, event.wheel.x);
WriteLE32(DemoRecording, event.wheel.y);
WriteLE16(DemoRecording, modState);
break;
#endif
case SDL_KEYDOWN:
case SDL_KEYUP:
RecordEventHeader(event);
WriteLE32(DemoRecording, static_cast<uint32_t>(event.key.keysym.sym));
WriteLE16(DemoRecording, static_cast<uint16_t>(event.key.keysym.mod));
break;
#ifndef USE_SDL1
case SDL_WINDOWEVENT:
if (event.window.type == SDL_WINDOWEVENT_CLOSE) {
SDL_Event quitEvent;
quitEvent.type = SDL_QUIT;
RecordEventHeader(quitEvent);
}
break;
#endif
case SDL_QUIT:
RecordEventHeader(event);
break;
default:
if (IsCustomEvent(event.type)) {
SDL_Event stableCustomEvent;
stableCustomEvent.type = SDL_USEREVENT + static_cast<uint32_t>(GetCustomEvent(event.type));
RecordEventHeader(stableCustomEvent);
}
break;
}
} }
void NotifyGameLoopStart() void NotifyGameLoopStart()

6
Source/engine/demomode.h

@ -5,6 +5,8 @@
*/ */
#pragma once #pragma once
#include <SDL.h>
#include "miniwin/misc_msg.h" #include "miniwin/misc_msg.h"
namespace devilution { namespace devilution {
@ -19,9 +21,9 @@ bool IsRunning();
bool IsRecording(); bool IsRecording();
bool GetRunGameLoop(bool &drawGame, bool &processInput); bool GetRunGameLoop(bool &drawGame, bool &processInput);
bool FetchMessage(tagMSG *lpMsg); bool FetchMessage(SDL_Event *event, uint16_t *modState);
void RecordGameLoopResult(bool runGameLoop); void RecordGameLoopResult(bool runGameLoop);
void RecordMessage(tagMSG *lpMsg); void RecordMessage(const SDL_Event &event, uint16_t modState);
void NotifyGameLoopStart(); void NotifyGameLoopStart();
void NotifyGameLoopEnd(); void NotifyGameLoopEnd();

43
Source/init.cpp

@ -229,15 +229,50 @@ void init_create_window()
#endif #endif
} }
void MainWndProc(uint32_t msg) void MainWndProc(const SDL_Event &event)
{ {
switch (msg) { #ifndef USE_SDL1
case DVL_WM_PAINT: if (event.type != SDL_WINDOWEVENT)
return;
switch (event.window.event) {
case SDL_WINDOWEVENT_HIDDEN:
gbActive = false;
break;
case SDL_WINDOWEVENT_SHOWN:
gbActive = false;
force_redraw = 255;
break;
case SDL_WINDOWEVENT_EXPOSED:
force_redraw = 255;
break;
case SDL_WINDOWEVENT_LEAVE:
sgbMouseDown = CLICK_NONE;
LastMouseButtonAction = MouseActionType::None;
force_redraw = 255; force_redraw = 255;
break; break;
case DVL_WM_QUERYENDSESSION: case SDL_WINDOWEVENT_CLOSE:
diablo_quit(0); diablo_quit(0);
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
diablo_focus_pause();
break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
diablo_focus_unpause();
break;
default:
LogVerbose("Unhandled SDL_WINDOWEVENT event: ", event.window.event);
break;
}
#else
if (event.type != SDL_ACTIVEEVENT)
return;
if ((event.active.state & SDL_APPINPUTFOCUS) != 0) {
if (event.active.gain == 0)
diablo_focus_pause();
else
diablo_focus_unpause();
} }
#endif
} }
EventHandler SetEventHandler(EventHandler eventHandler) EventHandler SetEventHandler(EventHandler eventHandler)

2
Source/init.h

@ -34,7 +34,7 @@ void LoadCoreArchives();
void LoadLanguageArchive(); void LoadLanguageArchive();
void LoadGameArchives(); void LoadGameArchives();
void init_create_window(); void init_create_window();
void MainWndProc(uint32_t Msg); void MainWndProc(const SDL_Event &event);
EventHandler SetEventHandler(EventHandler NewProc); EventHandler SetEventHandler(EventHandler NewProc);
} // namespace devilution } // namespace devilution

35
Source/interfac.cpp

@ -44,6 +44,9 @@ const int BarPos[3][2] = { { 53, 37 }, { 53, 421 }, { 53, 37 } };
OptionalOwnedClxSpriteList ArtCutsceneWidescreen; OptionalOwnedClxSpriteList ArtCutsceneWidescreen;
uint32_t CustomEventsBegin = SDL_USEREVENT;
constexpr uint32_t NumCustomEvents = WM_LAST - WM_FIRST + 1;
Cutscenes PickCutscene(interface_mode uMsg) Cutscenes PickCutscene(interface_mode uMsg)
{ {
switch (uMsg) { switch (uMsg) {
@ -204,13 +207,35 @@ void DrawCutsceneForeground()
} // namespace } // namespace
void interface_msg_pump() void RegisterCustomEvents()
{
#ifndef USE_SDL1
CustomEventsBegin = SDL_RegisterEvents(NumCustomEvents);
#endif
}
bool IsCustomEvent(uint32_t eventType)
{
return eventType >= CustomEventsBegin && eventType < CustomEventsBegin + NumCustomEvents;
}
interface_mode GetCustomEvent(uint32_t eventType)
{ {
tagMSG msg; return static_cast<interface_mode>(eventType - CustomEventsBegin);
}
while (FetchMessage(&msg)) { uint32_t CustomEventToSdlEvent(interface_mode eventType)
if (msg.message != DVL_WM_QUIT) { {
PushMessage(&msg); return CustomEventsBegin + eventType;
}
void interface_msg_pump()
{
SDL_Event event;
uint16_t modState;
while (FetchMessage(&event, &modState)) {
if (event.type != SDL_QUIT) {
HandleMessage(event, modState);
} }
} }
} }

33
Source/interfac.h

@ -11,24 +11,33 @@
namespace devilution { namespace devilution {
/**
* @brief Custom events.
*/
enum interface_mode : uint16_t { enum interface_mode : uint16_t {
// clang-format off WM_DIABNEXTLVL = 0,
WM_DIABNEXTLVL = 0x402, // WM_USER+2 WM_DIABPREVLVL,
WM_DIABPREVLVL = 0x403, WM_DIABRTNLVL,
WM_DIABRTNLVL = 0x404, WM_DIABSETLVL,
WM_DIABSETLVL = 0x405, WM_DIABWARPLVL,
WM_DIABWARPLVL = 0x406, WM_DIABTOWNWARP,
WM_DIABTOWNWARP = 0x407, WM_DIABTWARPUP,
WM_DIABTWARPUP = 0x408, WM_DIABRETOWN,
WM_DIABRETOWN = 0x409, WM_DIABNEWGAME,
WM_DIABNEWGAME = 0x40A, WM_DIABLOADGAME,
WM_DIABLOADGAME = 0x40B,
// clang-format on
WM_FIRST = WM_DIABNEXTLVL, WM_FIRST = WM_DIABNEXTLVL,
WM_LAST = WM_DIABLOADGAME, WM_LAST = WM_DIABLOADGAME,
}; };
void RegisterCustomEvents();
bool IsCustomEvent(uint32_t eventType);
interface_mode GetCustomEvent(uint32_t eventType);
uint32_t CustomEventToSdlEvent(interface_mode eventType);
enum Cutscenes : uint8_t { enum Cutscenes : uint8_t {
CutStart, CutStart,
CutTown, CutTown,

180
Source/miniwin/misc_msg.cpp

@ -47,8 +47,6 @@
namespace devilution { namespace devilution {
static std::deque<tagMSG> message_queue;
void SetMouseButtonEvent(SDL_Event &event, uint32_t type, uint8_t button, Point position) void SetMouseButtonEvent(SDL_Event &event, uint32_t type, uint8_t button, Point position)
{ {
event.type = type; event.type = type;
@ -97,11 +95,6 @@ void FocusOnCharInfo()
namespace { namespace {
uint32_t PositionForMouse(int16_t x, int16_t y)
{
return (static_cast<uint16_t>(y) << 16) | static_cast<uint16_t>(x);
}
bool FalseAvail(const char *name, int value) bool FalseAvail(const char *name, int value)
{ {
LogVerbose("Unhandled SDL event: {} {}", name, value); LogVerbose("Unhandled SDL event: {} {}", name, value);
@ -217,26 +210,19 @@ void ProcessGamepadEvents(GameAction &action)
} // namespace } // namespace
bool FetchMessage_Real(tagMSG *lpMsg) bool FetchMessage_Real(SDL_Event *event, uint16_t *modState)
{ {
#ifdef __SWITCH__ #ifdef __SWITCH__
HandleDocking(); HandleDocking();
#endif #endif
if (!message_queue.empty()) {
*lpMsg = message_queue.front();
message_queue.pop_front();
return true;
}
SDL_Event e; SDL_Event e;
if (PollEvent(&e) == 0) { if (PollEvent(&e) == 0) {
return false; return false;
} }
lpMsg->message = 0; event->type = static_cast<SDL_EventType>(0);
lpMsg->wParam = 0; *modState = SDL_GetModState();
lpMsg->lParam = 0;
#ifdef __vita__ #ifdef __vita__
HandleTouchEvent(&e, MousePosition); HandleTouchEvent(&e, MousePosition);
@ -244,8 +230,8 @@ bool FetchMessage_Real(tagMSG *lpMsg)
HandleTouchEvent(e); HandleTouchEvent(e);
#endif #endif
if (e.type == SDL_QUIT) { if (e.type == SDL_QUIT || IsCustomEvent(e.type)) {
lpMsg->message = DVL_WM_QUIT; *event = e;
return true; return true;
} }
@ -292,21 +278,18 @@ bool FetchMessage_Real(tagMSG *lpMsg)
if (GetGameAction(e, ctrlEvent, &action)) { if (GetGameAction(e, ctrlEvent, &action)) {
if (movie_playing) { if (movie_playing) {
if (action.type != GameActionType_NONE) { if (action.type != GameActionType_NONE) {
lpMsg->message = DVL_WM_KEYDOWN; event->type = SDL_KEYDOWN;
if (action.type == GameActionType_SEND_KEY) if (action.type == GameActionType_SEND_KEY)
lpMsg->wParam = action.send_key.vk_code; event->key.keysym.sym = static_cast<SDL_Keycode>(action.send_key.vk_code);
} }
} else if (action.type == GameActionType_SEND_KEY) { } else if (action.type == GameActionType_SEND_KEY) {
if ((action.send_key.vk_code & KeymapperMouseButtonMask) != 0) { if ((action.send_key.vk_code & KeymapperMouseButtonMask) != 0) {
const unsigned button = action.send_key.vk_code & ~KeymapperMouseButtonMask; const unsigned button = action.send_key.vk_code & ~KeymapperMouseButtonMask;
lpMsg->message = action.send_key.up SetMouseButtonEvent(*event, action.send_key.up ? SDL_MOUSEBUTTONUP : SDL_MOUSEBUTTONDOWN, static_cast<uint8_t>(button), MousePosition);
? (button == SDL_BUTTON_LEFT ? DVL_WM_LBUTTONUP : DVL_WM_RBUTTONUP)
: (button == SDL_BUTTON_RIGHT ? DVL_WM_LBUTTONDOWN : DVL_WM_RBUTTONDOWN);
lpMsg->wParam = (static_cast<int16_t>(MousePosition.y) << 16) | static_cast<int16_t>(MousePosition.x);
lpMsg->lParam = 0;
} else { } else {
lpMsg->message = action.send_key.up ? DVL_WM_KEYUP : DVL_WM_KEYDOWN; event->type = action.send_key.up ? SDL_KEYUP : SDL_KEYDOWN;
lpMsg->wParam = action.send_key.vk_code; event->key.state = action.send_key.up ? SDL_PRESSED : SDL_RELEASED;
event->key.keysym.sym = static_cast<SDL_Keycode>(action.send_key.vk_code);
} }
} else { } else {
ProcessGamepadEvents(action); ProcessGamepadEvents(action);
@ -318,9 +301,6 @@ bool FetchMessage_Real(tagMSG *lpMsg)
return true; return true;
switch (e.type) { switch (e.type) {
case SDL_QUIT:
lpMsg->message = DVL_WM_QUIT;
break;
case SDL_KEYDOWN: case SDL_KEYDOWN:
case SDL_KEYUP: { case SDL_KEYUP: {
#ifdef USE_SDL1 #ifdef USE_SDL1
@ -340,72 +320,31 @@ bool FetchMessage_Real(tagMSG *lpMsg)
remap_keyboard_key(&key); remap_keyboard_key(&key);
if (key == -1) if (key == -1)
return FalseAvail(e.type == SDL_KEYDOWN ? "SDL_KEYDOWN" : "SDL_KEYUP", e.key.keysym.sym); return FalseAvail(e.type == SDL_KEYDOWN ? "SDL_KEYDOWN" : "SDL_KEYUP", e.key.keysym.sym);
lpMsg->message = e.type == SDL_KEYDOWN ? DVL_WM_KEYDOWN : DVL_WM_KEYUP; event->type = e.type;
lpMsg->wParam = static_cast<uint32_t>(key); event->key.state = e.key.state;
lpMsg->lParam = e.key.keysym.mod; event->key.keysym.sym = key;
event->key.keysym.mod = e.key.keysym.mod;
} break; } break;
case SDL_MOUSEMOTION: case SDL_MOUSEMOTION:
lpMsg->message = DVL_WM_MOUSEMOVE; *event = e;
lpMsg->wParam = PositionForMouse(e.motion.x, e.motion.y);
lpMsg->lParam = SDL_GetModState();
if (ControlMode == ControlTypes::KeyboardAndMouse && invflag) if (ControlMode == ControlTypes::KeyboardAndMouse && invflag)
InvalidateInventorySlot(); InvalidateInventorySlot();
break; break;
case SDL_MOUSEBUTTONDOWN: { case SDL_MOUSEBUTTONDOWN:
lpMsg->wParam = PositionForMouse(e.button.x, e.button.y); case SDL_MOUSEBUTTONUP:
lpMsg->lParam = SDL_GetModState(); *event = e;
const int button = e.button.button; break;
switch (button) {
case SDL_BUTTON_LEFT:
lpMsg->message = DVL_WM_LBUTTONDOWN;
break;
case SDL_BUTTON_RIGHT:
lpMsg->message = DVL_WM_RBUTTONDOWN;
break;
case SDL_BUTTON_MIDDLE:
lpMsg->message = DVL_WM_MBUTTONDOWN;
break;
case SDL_BUTTON_X1:
lpMsg->message = DVL_WM_X1BUTTONDOWN;
break;
case SDL_BUTTON_X2:
lpMsg->message = DVL_WM_X2BUTTONDOWN;
break;
}
} break;
case SDL_MOUSEBUTTONUP: {
lpMsg->wParam = PositionForMouse(e.button.x, e.button.y);
lpMsg->lParam = SDL_GetModState();
const int button = e.button.button;
switch (button) {
case SDL_BUTTON_LEFT:
lpMsg->message = DVL_WM_LBUTTONUP;
break;
case SDL_BUTTON_RIGHT:
lpMsg->message = DVL_WM_RBUTTONUP;
break;
case SDL_BUTTON_MIDDLE:
lpMsg->message = DVL_WM_MBUTTONUP;
break;
case SDL_BUTTON_X1:
lpMsg->message = DVL_WM_X1BUTTONUP;
break;
case SDL_BUTTON_X2:
lpMsg->message = DVL_WM_X2BUTTONUP;
break;
}
} break;
#ifndef USE_SDL1 #ifndef USE_SDL1
case SDL_MOUSEWHEEL: case SDL_MOUSEWHEEL:
lpMsg->message = DVL_WM_KEYDOWN; event->type = SDL_KEYDOWN;
if (e.wheel.y > 0) { if (e.wheel.y > 0) {
lpMsg->wParam = (SDL_GetModState() & KMOD_CTRL) != 0 ? SDLK_KP_PLUS : SDLK_UP; event->key.keysym.sym = (SDL_GetModState() & KMOD_CTRL) != 0 ? SDLK_KP_PLUS : SDLK_UP;
} else if (e.wheel.y < 0) { } else if (e.wheel.y < 0) {
lpMsg->wParam = (SDL_GetModState() & KMOD_CTRL) != 0 ? SDLK_KP_MINUS : SDLK_DOWN; event->key.keysym.sym = (SDL_GetModState() & KMOD_CTRL) != 0 ? SDLK_KP_MINUS : SDLK_DOWN;
} else if (e.wheel.x > 0) { } else if (e.wheel.x > 0) {
lpMsg->wParam = SDLK_LEFT; event->key.keysym.sym = SDLK_LEFT;
} else if (e.wheel.x < 0) { } else if (e.wheel.x < 0) {
lpMsg->wParam = SDLK_RIGHT; event->key.keysym.sym = SDLK_RIGHT;
} }
break; break;
#if SDL_VERSION_ATLEAST(2, 0, 4) #if SDL_VERSION_ATLEAST(2, 0, 4)
@ -435,56 +374,11 @@ bool FetchMessage_Real(tagMSG *lpMsg)
} }
return FalseAvail("SDL_TEXTINPUT", e.text.windowID); return FalseAvail("SDL_TEXTINPUT", e.text.windowID);
case SDL_WINDOWEVENT: case SDL_WINDOWEVENT:
switch (e.window.event) { *event = e;
case SDL_WINDOWEVENT_SHOWN:
gbActive = true;
lpMsg->message = DVL_WM_PAINT;
break;
case SDL_WINDOWEVENT_HIDDEN:
gbActive = false;
break;
case SDL_WINDOWEVENT_EXPOSED:
lpMsg->message = DVL_WM_PAINT;
break;
case SDL_WINDOWEVENT_LEAVE:
lpMsg->message = DVL_WM_CAPTURECHANGED;
break;
case SDL_WINDOWEVENT_SIZE_CHANGED:
ReinitializeHardwareCursor();
break;
case SDL_WINDOWEVENT_MOVED:
case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_MINIMIZED:
case SDL_WINDOWEVENT_MAXIMIZED:
case SDL_WINDOWEVENT_RESTORED:
#if SDL_VERSION_ATLEAST(2, 0, 5)
case SDL_WINDOWEVENT_TAKE_FOCUS:
#endif
break;
case SDL_WINDOWEVENT_CLOSE:
lpMsg->message = DVL_WM_QUERYENDSESSION;
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
diablo_focus_pause();
break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
diablo_focus_unpause();
break;
default:
return FalseAvail("SDL_WINDOWEVENT", e.window.event);
}
break; break;
#else #else
case SDL_ACTIVEEVENT: case SDL_ACTIVEEVENT:
if ((e.active.state & SDL_APPINPUTFOCUS) != 0) { *event = e;
if (e.active.gain == 0)
diablo_focus_pause();
else
diablo_focus_unpause();
}
break; break;
#endif #endif
default: default:
@ -493,31 +387,21 @@ bool FetchMessage_Real(tagMSG *lpMsg)
return true; return true;
} }
bool FetchMessage(tagMSG *lpMsg) bool FetchMessage(SDL_Event *event, uint16_t *modState)
{ {
bool available = demo::IsRunning() ? demo::FetchMessage(lpMsg) : FetchMessage_Real(lpMsg); const bool available = demo::IsRunning() ? demo::FetchMessage(event, modState) : FetchMessage_Real(event, modState);
if (available && demo::IsRecording()) if (available && demo::IsRecording())
demo::RecordMessage(lpMsg); demo::RecordMessage(*event, *modState);
return available; return available;
} }
void PushMessage(const tagMSG *lpMsg) void HandleMessage(const SDL_Event &event, uint16_t modState)
{ {
assert(CurrentEventHandler != nullptr); assert(CurrentEventHandler != nullptr);
CurrentEventHandler(lpMsg->message, lpMsg->wParam, lpMsg->lParam); CurrentEventHandler(event, modState);
}
void PostMessage(uint32_t type, uint32_t wParam, uint16_t lParam)
{
message_queue.push_back({ type, wParam, lParam });
}
void ClearMessageQueue()
{
message_queue.clear();
} }
} // namespace devilution } // namespace devilution

41
Source/miniwin/misc_msg.h

@ -16,47 +16,14 @@
namespace devilution { namespace devilution {
struct tagMSG { using EventHandler = void (*)(const SDL_Event &event, uint16_t modState);
uint32_t message;
uint32_t wParam;
uint16_t lParam;
};
typedef void (*EventHandler)(uint32_t, uint32_t, uint16_t);
void SetCursorPos(Point position); void SetCursorPos(Point position);
void FocusOnCharInfo(); void FocusOnCharInfo();
void SetMouseButtonEvent(SDL_Event &event, uint32_t type, uint8_t button, Point position); void SetMouseButtonEvent(SDL_Event &event, uint32_t type, uint8_t button, Point position);
bool FetchMessage(tagMSG *lpMsg); bool FetchMessage(SDL_Event *event, uint16_t *modState);
void PushMessage(const tagMSG *lpMsg); void HandleMessage(const SDL_Event &event, uint16_t modState);
void PostMessage(uint32_t type, uint32_t wParam, uint16_t lParam);
void ClearMessageQueue();
//
// Events
//
#define DVL_WM_QUIT 0x0012
#define DVL_WM_MOUSEMOVE 0x0200
#define DVL_WM_LBUTTONDOWN 0x0201
#define DVL_WM_LBUTTONUP 0x0202
#define DVL_WM_RBUTTONDOWN 0x0204
#define DVL_WM_RBUTTONUP 0x0205
#define DVL_WM_MBUTTONDOWN 0x0206
#define DVL_WM_MBUTTONUP 0x0207
#define DVL_WM_X1BUTTONDOWN 0x0208
#define DVL_WM_X1BUTTONUP 0x0209
#define DVL_WM_X2BUTTONDOWN 0x020A
#define DVL_WM_X2BUTTONUP 0x020B
#define DVL_WM_KEYDOWN 0x0100
#define DVL_WM_KEYUP 0x0101
#define DVL_WM_CAPTURECHANGED 0x0215
#define DVL_WM_PAINT 0x000F
#define DVL_WM_QUERYENDSESSION 0x0011
} // namespace devilution } // namespace devilution

16
Source/movie.cpp

@ -37,17 +37,17 @@ void play_movie(const char *pszMovie, bool userCanClose)
} }
if (SVidPlayBegin(pszMovie, loop_movie ? 0x100C0808 : 0x10280808)) { if (SVidPlayBegin(pszMovie, loop_movie ? 0x100C0808 : 0x10280808)) {
tagMSG msg; SDL_Event event;
uint16_t modState;
while (movie_playing) { while (movie_playing) {
while (movie_playing && FetchMessage(&msg)) { while (movie_playing && FetchMessage(&event, &modState)) {
switch (msg.message) { switch (event.type) {
case DVL_WM_KEYDOWN: case SDL_KEYDOWN:
case DVL_WM_LBUTTONUP: case SDL_MOUSEBUTTONUP:
case DVL_WM_RBUTTONUP: if (userCanClose || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE))
if (userCanClose || (msg.message == DVL_WM_KEYDOWN && msg.wParam == SDLK_ESCAPE))
movie_playing = false; movie_playing = false;
break; break;
case DVL_WM_QUIT: case SDL_QUIT:
SVidPlayEnd(); SVidPlayEnd();
diablo_quit(0); diablo_quit(0);
} }

12
Source/player.cpp

@ -3191,7 +3191,9 @@ StartNewLvl(Player &player, interface_mode fom, int lvl)
if (&player == MyPlayer) { if (&player == MyPlayer) {
player._pmode = PM_NEWLVL; player._pmode = PM_NEWLVL;
player._pInvincible = true; player._pInvincible = true;
PostMessage(fom, 0, 0); SDL_Event event;
event.type = CustomEventToSdlEvent(fom);
SDL_PushEvent(&event);
if (gbIsMultiplayer) { if (gbIsMultiplayer) {
NetSendCmdParam2(true, CMD_NEWLVL, fom, lvl); NetSendCmdParam2(true, CMD_NEWLVL, fom, lvl);
} }
@ -3215,7 +3217,9 @@ void RestartTownLvl(Player &player)
if (&player == MyPlayer) { if (&player == MyPlayer) {
player._pmode = PM_NEWLVL; player._pmode = PM_NEWLVL;
player._pInvincible = true; player._pInvincible = true;
PostMessage(WM_DIABRETOWN, 0, 0); SDL_Event event;
event.type = CustomEventToSdlEvent(WM_DIABRETOWN);
SDL_PushEvent(&event);
} }
} }
@ -3238,7 +3242,9 @@ void StartWarpLvl(Player &player, int pidx)
SetCurrentPortal(pidx); SetCurrentPortal(pidx);
player._pmode = PM_NEWLVL; player._pmode = PM_NEWLVL;
player._pInvincible = true; player._pInvincible = true;
PostMessage(WM_DIABWARPLVL, 0, 0); SDL_Event event;
event.type = CustomEventToSdlEvent(WM_DIABWARPLVL);
SDL_PushEvent(&event);
} }
} }

1
Source/utils/display.cpp

@ -275,6 +275,7 @@ bool SpawnWindow(const char *lpWindowName)
if (SDL_Init(initFlags) <= -1) { if (SDL_Init(initFlags) <= -1) {
ErrSdl(); ErrSdl();
} }
RegisterCustomEvents();
#ifndef USE_SDL1 #ifndef USE_SDL1
if (sgOptions.Controller.szMapping[0] != '\0') { if (sgOptions.Controller.szMapping[0] != '\0') {

BIN
test/fixtures/timedemo/WarriorLevel1to2/demo_0.dmo vendored

Binary file not shown.
Loading…
Cancel
Save