AGS: rewrote eAGSMouseButton enum to sync with the script API

* Changed from -1 - based constants to 0 - based constants;
* These were purely internal values, therefore no API would be harmed;
* Removed necessity of converting from internal mouse button code to script and back all the time;
* On a side note, this fixes a bug where WaitMouse etc were returning incorrect values on mouse skip, because we forgot to convert from internal to script code.

From upstream 471098d239b076c494beb2d554572ccb69372667
This commit is contained in:
Thierry Crozat 2022-10-09 22:26:36 +01:00
parent 06620b6e9f
commit 5987bc5e6e
16 changed files with 87 additions and 91 deletions

View File

@ -915,14 +915,14 @@ bool DialogOptions::Run() {
parserActivated = 1; parserActivated = 1;
} }
int mouseButtonPressed = MouseNone; eAGSMouseButton mbut;
int mouseWheelTurn = 0; int mwheelz;
if (run_service_mb_controls(mouseButtonPressed, mouseWheelTurn) && mouseButtonPressed >= 0 && if (run_service_mb_controls(mbut, mwheelz) && mbut > kMouseNone &&
!_GP(play).IsIgnoringInput()) { !_GP(play).IsIgnoringInput()) {
if (mouseison < 0 && !new_custom_render) { if (mouseison < 0 && !new_custom_render) {
if (usingCustomRendering) { if (usingCustomRendering) {
_GP(runDialogOptionMouseClickHandlerFunc).params[0].SetDynamicObject(&_GP(ccDialogOptionsRendering), &_GP(ccDialogOptionsRendering)); _GP(runDialogOptionMouseClickHandlerFunc).params[0].SetDynamicObject(&_GP(ccDialogOptionsRendering), &_GP(ccDialogOptionsRendering));
_GP(runDialogOptionMouseClickHandlerFunc).params[1].SetInt32(mouseButtonPressed + 1); _GP(runDialogOptionMouseClickHandlerFunc).params[1].SetInt32(mbut);
run_function_on_non_blocking_thread(&_GP(runDialogOptionMouseClickHandlerFunc)); run_function_on_non_blocking_thread(&_GP(runDialogOptionMouseClickHandlerFunc));
if (_GP(runDialogOptionMouseClickHandlerFunc).atLeastOneImplementationExists) { if (_GP(runDialogOptionMouseClickHandlerFunc).atLeastOneImplementationExists) {
@ -937,7 +937,7 @@ bool DialogOptions::Run() {
parserActivated = 1; parserActivated = 1;
} else if (new_custom_render) { } else if (new_custom_render) {
_GP(runDialogOptionMouseClickHandlerFunc).params[0].SetDynamicObject(&_GP(ccDialogOptionsRendering), &_GP(ccDialogOptionsRendering)); _GP(runDialogOptionMouseClickHandlerFunc).params[0].SetDynamicObject(&_GP(ccDialogOptionsRendering), &_GP(ccDialogOptionsRendering));
_GP(runDialogOptionMouseClickHandlerFunc).params[1].SetInt32(mouseButtonPressed + 1); _GP(runDialogOptionMouseClickHandlerFunc).params[1].SetInt32(mbut);
run_function_on_non_blocking_thread(&_GP(runDialogOptionMouseClickHandlerFunc)); run_function_on_non_blocking_thread(&_GP(runDialogOptionMouseClickHandlerFunc));
} else if (usingCustomRendering) { } else if (usingCustomRendering) {
chose = mouseison; chose = mouseison;
@ -949,9 +949,9 @@ bool DialogOptions::Run() {
} }
if (usingCustomRendering) { if (usingCustomRendering) {
if (mouseWheelTurn != 0) { if (mwheelz != 0) {
_GP(runDialogOptionMouseClickHandlerFunc).params[0].SetDynamicObject(&_GP(ccDialogOptionsRendering), &_GP(ccDialogOptionsRendering)); _GP(runDialogOptionMouseClickHandlerFunc).params[0].SetDynamicObject(&_GP(ccDialogOptionsRendering), &_GP(ccDialogOptionsRendering));
_GP(runDialogOptionMouseClickHandlerFunc).params[1].SetInt32((mouseWheelTurn < 0) ? 9 : 8); _GP(runDialogOptionMouseClickHandlerFunc).params[1].SetInt32((mwheelz < 0) ? 9 : 8);
run_function_on_non_blocking_thread(&_GP(runDialogOptionMouseClickHandlerFunc)); run_function_on_non_blocking_thread(&_GP(runDialogOptionMouseClickHandlerFunc));
if (!new_custom_render) { if (!new_custom_render) {

View File

@ -283,8 +283,9 @@ ScreenOverlay *_display_main(int xx, int yy, int wii, const char *text, int disp
update_audio_system_on_game_loop(); update_audio_system_on_game_loop();
render_graphics(); render_graphics();
int mbut, mwheelz; eAGSMouseButton mbut;
if (run_service_mb_controls(mbut, mwheelz) && mbut >= 0) { int mwheelz;
if (run_service_mb_controls(mbut, mwheelz) && mbut > kMouseNone) {
check_skip_cutscene_mclick(mbut); check_skip_cutscene_mclick(mbut);
if (_GP(play).fast_forward) if (_GP(play).fast_forward)
break; break;

View File

@ -1081,7 +1081,7 @@ bool check_skip_cutscene_keypress(int kgn) {
bool check_skip_cutscene_mclick(int mbut) { bool check_skip_cutscene_mclick(int mbut) {
CutsceneSkipStyle skip = get_cutscene_skipstyle(); CutsceneSkipStyle skip = get_cutscene_skipstyle();
if (skip == eSkipSceneMouse || skip == eSkipSceneKeyMouse || if (skip == eSkipSceneMouse || skip == eSkipSceneKeyMouse ||
(mbut == MouseRight && skip == eSkipSceneEscOrRMB)) { (mbut == kMouseRight && skip == eSkipSceneEscOrRMB)) {
start_skipping_cutscene(); start_skipping_cutscene();
return true; return true;
} }

View File

@ -364,12 +364,13 @@ bool InventoryScreen::Run() {
if ((isonitem < 0) | (isonitem >= numitems) | (isonitem >= top_item + num_visible_items)) if ((isonitem < 0) | (isonitem >= numitems) | (isonitem >= top_item + num_visible_items))
isonitem = -1; isonitem = -1;
int mclick, mwheelz; eAGSMouseButton mbut;
if (!run_service_mb_controls(mclick, mwheelz) || _GP(play).IsIgnoringInput()) { int mwheelz;
mclick = MouseNone; if (!run_service_mb_controls(mbut, mwheelz) || _GP(play).IsIgnoringInput()) {
mbut = kMouseNone;
} }
if (mclick == MouseLeft) { if (mbut == kMouseLeft) {
if ((my < 0) | (my > windowhit) | (mx < 0) | (mx > windowwid)) if ((my < 0) | (my > windowhit) | (mx < 0) | (mx > windowwid))
return true; // continue inventory screen loop return true; // continue inventory screen loop
if (my < buttonyp) { if (my < buttonyp) {
@ -455,7 +456,7 @@ bool InventoryScreen::Run() {
} }
set_mouse_cursor(cmode); set_mouse_cursor(cmode);
} }
} else if (mclick == MouseRight) { } else if (mbut == kMouseRight) {
if (cmode == CURS_ARROW) if (cmode == CURS_ARROW)
cmode = MODE_LOOK; cmode = MODE_LOOK;
else else

View File

@ -297,11 +297,9 @@ int GetCursorMode() {
} }
int IsButtonDown(int which) { int IsButtonDown(int which) {
if ((which < 1) || (which > 3)) if ((which < kMouseLeft) || (which > kMouseMiddle))
quit("!IsButtonDown: only works with eMouseLeft, eMouseRight, eMouseMiddle"); quit("!IsButtonDown: only works with eMouseLeft, eMouseRight, eMouseMiddle");
if (ags_misbuttondown(which - 1)) return ags_misbuttondown(static_cast<eAGSMouseButton>(which)) ? 1 : 0;
return 1;
return 0;
} }
int IsModeEnabled(int which) { int IsModeEnabled(int which) {

View File

@ -53,7 +53,9 @@ using namespace AGS::Shared;
using namespace AGS::Engine; using namespace AGS::Engine;
extern void domouse(int str); extern void domouse(int str);
const int MB_ARRAY[3] = { MouseBitLeft, MouseBitRight, MouseBitMiddle }; // Convert mouse button id to flags
const int MouseButton2Bits[kNumMouseButtons] =
{ MouseBitLeft, MouseBitRight, MouseBitMiddle };
static void(*_on_quit_callback)(void) = nullptr; static void(*_on_quit_callback)(void) = nullptr;
static void(*_on_switchin_callback)(void) = nullptr; static void(*_on_switchin_callback)(void) = nullptr;
static void(*_on_switchout_callback)(void) = nullptr; static void(*_on_switchout_callback)(void) = nullptr;
@ -157,22 +159,19 @@ static void on_mouse_wheel(const Common::Event &event) {
_G(sys_mouse_z)--; _G(sys_mouse_z)--;
} }
int mgetbutton() { static eAGSMouseButton mgetbutton() {
int toret = MouseNone; const int butis = mouse_button_poll();
int butis = mouse_button_poll();
if ((butis > 0) & (_G(butwas) > 0)) if ((butis > 0) & (_G(butwas) > 0))
return MouseNone; // don't allow holding button down return kMouseNone; // don't allow holding button down
if (butis & MouseBitLeft) if (butis & MouseBitLeft)
toret = MouseLeft; return kMouseLeft;
else if (butis & MouseBitRight) else if (butis & MouseBitRight)
toret = MouseRight; return kMouseRight;
else if (butis & MouseBitMiddle) else if (butis & MouseBitMiddle)
toret = MouseMiddle; return kMouseMiddle;
return kMouseNone;
_G(butwas) = butis;
return toret;
// TODO: presumably this was a hack for 1-button Mac mouse; // TODO: presumably this was a hack for 1-button Mac mouse;
// is this still necessary? // is this still necessary?
@ -184,23 +183,19 @@ int mgetbutton() {
toret = RIGHT; toret = RIGHT;
} }
#endif #endif
return 0;
} }
bool ags_misbuttondown(int but) { bool ags_misbuttondown(eAGSMouseButton but) {
return (mouse_button_poll() & MB_ARRAY[but]) != 0; return (mouse_button_poll() & MouseButton2Bits[but]) != 0;
} }
int ags_mgetbutton() { eAGSMouseButton ags_mgetbutton() {
int result; if (_G(pluginSimulatedClick) > kMouseNone) {
eAGSMouseButton mbut = _G(pluginSimulatedClick);
if (_G(pluginSimulatedClick) > MouseNone) { _G(pluginSimulatedClick) = kMouseNone;
result = _G(pluginSimulatedClick); return mbut;
_G(pluginSimulatedClick) = MouseNone;
} else {
result = mgetbutton();
} }
return result; return mgetbutton();;
} }
void ags_mouse_get_relxy(int &x, int &y) { void ags_mouse_get_relxy(int &x, int &y) {

View File

@ -27,21 +27,6 @@
namespace AGS3 { namespace AGS3 {
// AGS own mouse button codes
// TODO: these were internal button codes, but AGS script uses different ones,
// which start with Left=1, and make more sense (0 is easier to use as "no value").
// Must research if there are any dependencies to these internal values, and if not,
// then just replace these matching script ones!
// UPD: even plugin API seem to match script codes and require remap to internals.
// UPD: or use SDL constants in the engine, but make conversion more visible by using a function.
enum eAGSMouseButton {
MouseNone = -1,
MouseLeft = 0,
MouseRight = 1,
MouseMiddle = 2
};
// Keyboard input handling // Keyboard input handling
// //
// avoid including SDL.h here, at least for now, because that leads to conflicts with allegro // avoid including SDL.h here, at least for now, because that leads to conflicts with allegro
@ -85,9 +70,9 @@ extern void ags_simulate_keypress(eAGSKeyCode ags_key);
// Mouse input handling // Mouse input handling
// //
// Tells if the mouse button is currently down // Tells if the mouse button is currently down
extern bool ags_misbuttondown(int but); extern bool ags_misbuttondown(eAGSMouseButton but);
// Returns mouse button code // Returns mouse button code
extern int ags_mgetbutton(); extern eAGSMouseButton ags_mgetbutton();
// Returns recent relative mouse movement // Returns recent relative mouse movement
extern void ags_mouse_get_relxy(int &x, int &y); extern void ags_mouse_get_relxy(int &x, int &y);
// Updates mouse cursor position in game // Updates mouse cursor position in game

View File

@ -156,8 +156,9 @@ int CSCIWaitMessage(CSCIMessage *cscim) {
} }
} }
int mbut, mwheelz; eAGSMouseButton mbut;
if (run_service_mb_controls(mbut, mwheelz) && mbut >= 0 && !_GP(play).IsIgnoringInput()) { int mwheelz;
if (run_service_mb_controls(mbut, mwheelz) && (mbut > kMouseNone) && !_GP(play).IsIgnoringInput()) {
if (checkcontrols()) { if (checkcontrols()) {
cscim->id = _G(controlid); cscim->id = _G(controlid);
cscim->code = CM_COMMAND; cscim->code = CM_COMMAND;

View File

@ -30,7 +30,6 @@
#undef WINAPI #undef WINAPI
#endif #endif
#define WINAPI #define WINAPI
#define mbutrelease(X) (!ags_misbuttondown(X))
#define TEXT_HT _GP(usetup).textheight #define TEXT_HT _GP(usetup).textheight
#endif #endif

View File

@ -72,7 +72,7 @@ void MyPushButton::draw(Bitmap *ds) {
int MyPushButton::pressedon(int mx, int my) { int MyPushButton::pressedon(int mx, int my) {
int wasstat; int wasstat;
while (mbutrelease(MouseLeft) == 0) { while (!ags_misbuttondown(kMouseLeft) == 0) {
wasstat = state; wasstat = state;
state = mouseisinarea(mx, my); state = mouseisinarea(mx, my);

View File

@ -192,16 +192,16 @@ static void check_mouse_controls() {
remove_popup_interface(_G(ifacepopped)); remove_popup_interface(_G(ifacepopped));
// check mouse clicks on GUIs // check mouse clicks on GUIs
if ((_G(wasbutdown) > 0) && (ags_misbuttondown(_G(wasbutdown) - 1))) { if ((_G(wasbutdown) > kMouseNone) && (ags_misbuttondown(_G(wasbutdown)))) {
gui_on_mouse_hold(_G(wasongui), _G(wasbutdown)); gui_on_mouse_hold(_G(wasongui), _G(wasbutdown));
} else if ((_G(wasbutdown) > 0) && (!ags_misbuttondown(_G(wasbutdown) - 1))) { } else if ((_G(wasbutdown) > kMouseNone) && (!ags_misbuttondown(_G(wasbutdown)))) {
gui_on_mouse_up(_G(wasongui), _G(wasbutdown)); gui_on_mouse_up(_G(wasongui), _G(wasbutdown));
_G(wasbutdown) = 0; _G(wasbutdown) = kMouseNone;
} }
int mbut = MouseNone; eAGSMouseButton mbut;
int mwheelz = 0; int mwheelz;
if (run_service_mb_controls(mbut, mwheelz) && mbut >= 0) { if (run_service_mb_controls(mbut, mwheelz) && mbut > kMouseNone) {
check_skip_cutscene_mclick(mbut); check_skip_cutscene_mclick(mbut);
@ -214,17 +214,17 @@ static void check_mouse_controls() {
_GP(play).SetWaitSkipResult(SKIP_MOUSECLICK, mbut); _GP(play).SetWaitSkipResult(SKIP_MOUSECLICK, mbut);
} }
} else if (!IsInterfaceEnabled()); // blocking cutscene, ignore mouse } else if (!IsInterfaceEnabled()); // blocking cutscene, ignore mouse
else if (pl_run_plugin_hooks(AGSE_MOUSECLICK, mbut + 1)) { else if (pl_run_plugin_hooks(AGSE_MOUSECLICK, mbut)) {
// plugin took the click // plugin took the click
debug_script_log("Plugin handled mouse button %d", mbut + 1); debug_script_log("Plugin handled mouse button %d", mbut);
} else if (mongu >= 0) { } else if (mongu >= 0) {
if (_G(wasbutdown) == 0) { if (_G(wasbutdown) == kMouseNone) {
gui_on_mouse_down(mongu, mbut + 1); gui_on_mouse_down(mongu, mbut);
} }
_G(wasongui) = mongu; _G(wasongui) = mongu;
_G(wasbutdown) = mbut + 1; _G(wasbutdown) = mbut;
} else } else
setevent(EV_TEXTSCRIPT, TS_MCLICK, mbut + 1); setevent(EV_TEXTSCRIPT, TS_MCLICK, mbut);
} }
if (mwheelz < 0) if (mwheelz < 0)
@ -256,6 +256,8 @@ bool run_service_key_controls(KeyInput &out_key) {
const bool is_only_mod_key = key_evt.type == Common::EVENT_KEYDOWN ? const bool is_only_mod_key = key_evt.type == Common::EVENT_KEYDOWN ?
is_mod_key(key_evt.kbd.keycode) : false; is_mod_key(key_evt.kbd.keycode) : false;
out_key = KeyInput(); // reset to default
// Following section is for testing for pushed and released mod-keys. // Following section is for testing for pushed and released mod-keys.
// A bit of explanation: some service actions may require combination of // A bit of explanation: some service actions may require combination of
// mod-keys, for example [Ctrl + Alt] toggles mouse lock in window. // mod-keys, for example [Ctrl + Alt] toggles mouse lock in window.
@ -398,14 +400,12 @@ bool run_service_key_controls(KeyInput &out_key) {
return true; return true;
} }
bool run_service_mb_controls(int &mbut, int &mwheelz) { bool run_service_mb_controls(eAGSMouseButton &mbut, int &mwheelz) {
int mb = ags_mgetbutton(); mbut = ags_mgetbutton();
int mz = ags_check_mouse_wheel(); mwheelz = ags_check_mouse_wheel();
if (mb == MouseNone && mz == 0) if (mbut == kMouseNone && mwheelz == 0)
return false; return false;
lock_mouse_on_click(); // do not claim lock_mouse_on_click();
mbut = mb;
mwheelz = mz;
return true; return true;
} }

View File

@ -22,6 +22,8 @@
#ifndef AGS_ENGINE_MAIN_GAME_RUN_H #ifndef AGS_ENGINE_MAIN_GAME_RUN_H
#define AGS_ENGINE_MAIN_GAME_RUN_H #define AGS_ENGINE_MAIN_GAME_RUN_H
#include "ags/shared/ac/keycode.h"
namespace AGS3 { namespace AGS3 {
namespace AGS { namespace AGS {
@ -51,13 +53,12 @@ void UpdateGameAudioOnly();
// Gets current logical game FPS, this is normally a fixed number set in script; // Gets current logical game FPS, this is normally a fixed number set in script;
// in case of "maxed fps" mode this function returns real measured FPS. // in case of "maxed fps" mode this function returns real measured FPS.
float get_current_fps(); float get_current_fps();
struct KeyInput;
// Runs service key controls, returns false if no key was pressed or key input was claimed by the engine, // Runs service key controls, returns false if no key was pressed or key input was claimed by the engine,
// otherwise returns true and provides a keycode. // otherwise returns true and provides a keycode.
bool run_service_key_controls(KeyInput &kgn); bool run_service_key_controls(KeyInput &kgn);
// Runs service mouse controls, returns false if mouse input was claimed by the engine, // Runs service mouse controls, returns false if mouse input was claimed by the engine,
// otherwise returns true and provides mouse button code. // otherwise returns true and provides mouse button code.
bool run_service_mb_controls(int &mbut, int &mwheelz); bool run_service_mb_controls(eAGSMouseButton &mbut, int &mwheelz);
} // namespace AGS3 } // namespace AGS3

View File

@ -111,7 +111,8 @@ static bool play_video(Video::VideoDecoder *decoder, const char *name, int flags
if (skip != VideoSkipNone) { if (skip != VideoSkipNone) {
// Check for whether user aborted video // Check for whether user aborted video
KeyInput key; KeyInput key;
int mbut, mwheelz; eAGSMouseButton mbut;
int mwheelz;
if (run_service_key_controls(key)) { if (run_service_key_controls(key)) {
if (key.Key == 27 && skip >= VideoSkipEscape) if (key.Key == 27 && skip >= VideoSkipEscape)
return true; return true;
@ -119,7 +120,7 @@ static bool play_video(Video::VideoDecoder *decoder, const char *name, int flags
return true; // skip on any key return true; // skip on any key
} }
if (run_service_mb_controls(mbut, mwheelz) && mbut >= 0 && skip == VideoSkipKeyOrMouse) { if (run_service_mb_controls(mbut, mwheelz) && mbut >= kMouseNone && skip == VideoSkipKeyOrMouse) {
return true; // skip on mouse click return true; // skip on mouse click
} }
} }

View File

@ -27,6 +27,7 @@
#include "ags/lib/std/queue.h" #include "ags/lib/std/queue.h"
#include "ags/shared/ac/game_version.h" #include "ags/shared/ac/game_version.h"
#include "ags/shared/ac/keycode.h"
#include "ags/shared/util/stdio_compat.h" #include "ags/shared/util/stdio_compat.h"
#include "ags/shared/util/string.h" #include "ags/shared/util/string.h"
#include "ags/shared/util/string_types.h" #include "ags/shared/util/string_types.h"
@ -242,7 +243,8 @@ public:
int _mouse_accum_button_state = 0; int _mouse_accum_button_state = 0;
uint32 _mouse_clear_at_time = 0; uint32 _mouse_clear_at_time = 0;
int _mouse_accum_relx = 0, _mouse_accum_rely = 0; int _mouse_accum_relx = 0, _mouse_accum_rely = 0;
int _wasbutdown = 0, _wasongui = 0; eAGSMouseButton _wasbutdown = kMouseNone;
int _wasongui = 0;
/**@}*/ /**@}*/
@ -1324,7 +1326,7 @@ public:
long _pl_file_handle = -1; long _pl_file_handle = -1;
AGS::Shared::Stream *_pl_file_stream = nullptr; AGS::Shared::Stream *_pl_file_stream = nullptr;
int _pluginSimulatedClick = -1; eAGSMouseButton _pluginSimulatedClick = kMouseNone;
int _mouse_z_was = 0; int _mouse_z_was = 0;
/**@}*/ /**@}*/

View File

@ -86,7 +86,7 @@ const int PLUGIN_API_VERSION = 25;
// we can reuse the same handle. // we can reuse the same handle.
void PluginSimulateMouseClick(int pluginButtonID) { void PluginSimulateMouseClick(int pluginButtonID) {
_G(pluginSimulatedClick) = pluginButtonID - 1; _G(pluginSimulatedClick) = static_cast<eAGSMouseButton>(pluginButtonID);
} }
void IAGSEngine::AbortGame(const char *reason) { void IAGSEngine::AbortGame(const char *reason) {
@ -342,8 +342,9 @@ void IAGSEngine::BlitSpriteRotated(int32 x, int32 y, BITMAP *bmp, int32 angle) {
void IAGSEngine::PollSystem() { void IAGSEngine::PollSystem() {
ags_domouse(); ags_domouse();
update_polled_stuff_if_runtime(); update_polled_stuff_if_runtime();
int mbut, mwheelz; eAGSMouseButton mbut;
if (run_service_mb_controls(mbut, mwheelz) && mbut >= 0 && !_GP(play).IsIgnoringInput()) int mwheelz;
if (run_service_mb_controls(mbut, mwheelz) && mbut > kMouseNone && !_GP(play).IsIgnoringInput())
pl_run_plugin_hooks(AGSE_MOUSECLICK, mbut); pl_run_plugin_hooks(AGSE_MOUSECLICK, mbut);
KeyInput kp; KeyInput kp;
if (run_service_key_controls(kp) && !_GP(play).IsIgnoringInput()) { if (run_service_key_controls(kp) && !_GP(play).IsIgnoringInput()) {

View File

@ -276,6 +276,17 @@ struct KeyInput {
KeyInput() = default; KeyInput() = default;
}; };
// AGS own mouse button codes;
// These correspond to MouseButton enum in script API (sans special values)
enum eAGSMouseButton
{
kMouseNone = 0,
kMouseLeft = 1,
kMouseRight = 2,
kMouseMiddle = 3,
kNumMouseButtons
};
// Converts eAGSKeyCode to script API code, for "on_key_press" and similar callbacks // Converts eAGSKeyCode to script API code, for "on_key_press" and similar callbacks
int AGSKeyToScriptKey(int keycode); int AGSKeyToScriptKey(int keycode);
// Converts eAGSKeyCode to ASCII text representation with the range check; returns 0 on failure // Converts eAGSKeyCode to ASCII text representation with the range check; returns 0 on failure