scummvm/engines/ags/engine/ac/sys_events.cpp
Walter Agazzi 76579deff2 AGS: Remove unused OSX right mouseclick hack
Partially from upstream 3fd5531f79044f58c261d9af0c7401ab1edf4ca7
2023-01-20 17:25:14 +01:00

304 lines
8.3 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/events.h"
#include "ags/engine/ac/sys_events.h"
#include "ags/shared/core/platform.h"
#include "ags/shared/ac/common.h"
#include "ags/shared/ac/game_setup_struct.h"
#include "ags/shared/ac/keycode.h"
#include "ags/engine/ac/mouse.h"
#include "ags/engine/ac/timer.h"
#include "ags/engine/device/mouse_w32.h"
#include "ags/engine/platform/base/ags_platform_driver.h"
#include "ags/engine/main/engine.h"
#include "ags/ags.h"
#include "ags/events.h"
#include "ags/globals.h"
// TODO: Replace me
typedef int SDL_Scancode;
namespace AGS3 {
// TODO: check later, if this may be useful in other places (then move to header)
enum eAGSMouseButtonMask {
MouseBitLeft = 0x01,
MouseBitRight = 0x02,
MouseBitMiddle = 0x04,
MouseBitX1 = 0x08,
MouseBitX2 = 0x10
};
using namespace AGS::Shared;
using namespace AGS::Engine;
extern void domouse(int str);
// Convert mouse button id to flags
const int MouseButton2Bits[kNumMouseButtons] =
{ 0, MouseBitLeft, MouseBitRight, MouseBitMiddle };
static void(*_on_quit_callback)(void) = nullptr;
static void(*_on_switchin_callback)(void) = nullptr;
static void(*_on_switchout_callback)(void) = nullptr;
// ----------------------------------------------------------------------------
// KEYBOARD INPUT
// ----------------------------------------------------------------------------
KeyInput ags_keycode_from_scummvm(const Common::Event &event, bool old_keyhandle) {
KeyInput ki;
ki.UChar = event.kbd.ascii;
ki.Key = ::AGS::g_events->scummvm_key_to_ags_key(event, ki.Mod, old_keyhandle);
ki.CompatKey = ::AGS::g_events->scummvm_key_to_ags_key(event, ki.Mod, true);
if (ki.CompatKey == eAGSKeyCodeNone)
ki.CompatKey = ki.Key;
return ki;
}
bool ags_keyevent_ready() {
return ::AGS::g_events->keyEventPending();
}
Common::Event ags_get_next_keyevent() {
return ::AGS::g_events->getPendingKeyEvent();
}
int ags_iskeydown(eAGSKeyCode ags_key) {
return ::AGS::g_events->isKeyPressed(ags_key, _GP(game).options[OPT_KEYHANDLEAPI] == 0);
}
void ags_simulate_keypress(eAGSKeyCode ags_key) {
Common::KeyCode keycode[3];
if (!::AGS::EventsManager::ags_key_to_scancode(ags_key, keycode))
return;
// Push a key event to the event queue; note that this won't affect the key states array
Common::Event e;
e.type = Common::EVENT_KEYDOWN;
e.kbd.keycode = keycode[0];
e.kbd.ascii = (e.kbd.keycode >= 32 && e.kbd.keycode <= 127) ? e.kbd.keycode : 0;
::AGS::g_events->pushKeyboardEvent(e);
}
// ----------------------------------------------------------------------------
// MOUSE INPUT
// ----------------------------------------------------------------------------
static int scummvm_button_to_mask(Common::EventType type) {
switch (type) {
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
return MouseBitLeft;
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_RBUTTONUP:
return MouseBitRight;
case Common::EVENT_MBUTTONDOWN:
case Common::EVENT_MBUTTONUP:
return MouseBitMiddle;
default:
return 0;
}
}
// Returns accumulated mouse button state and clears internal cache by timer
static int mouse_button_poll() {
auto now = AGS_Clock::now();
int result = _G(mouse_button_state) | _G(mouse_accum_button_state);
if (now >= _G(mouse_clear_at_time)) {
_G(mouse_accum_button_state) = 0;
_G(mouse_clear_at_time) = now + std::chrono::milliseconds(50);
}
return result;
}
static void on_mouse_motion(const Common::Event &event) {
_G(sys_mouse_x) = event.mouse.x;
_G(sys_mouse_y) = event.mouse.y;
_G(mouse_accum_relx) += event.relMouse.x;
_G(mouse_accum_rely) += event.relMouse.y;
}
static void on_mouse_button(const Common::Event &event) {
_G(sys_mouse_x) = event.mouse.x;
_G(sys_mouse_y) = event.mouse.y;
if (event.type == Common::EVENT_LBUTTONDOWN ||
event.type == Common::EVENT_RBUTTONDOWN ||
event.type == Common::EVENT_MBUTTONDOWN) {
_G(mouse_button_state) |= scummvm_button_to_mask(event.type);
_G(mouse_accum_button_state) |= scummvm_button_to_mask(event.type);
} else {
_G(mouse_button_state) &= ~scummvm_button_to_mask(event.type);
}
}
static void on_mouse_wheel(const Common::Event &event) {
if (event.type == Common::EVENT_WHEELDOWN)
_G(sys_mouse_z)++;
else
_G(sys_mouse_z)--;
}
static eAGSMouseButton mgetbutton() {
const int butis = mouse_button_poll();
if ((butis > 0) & (_G(butwas) > 0))
return kMouseNone; // don't allow holding button down
_G(butwas) = butis;
if (butis & MouseBitLeft)
return kMouseLeft;
else if (butis & MouseBitRight)
return kMouseRight;
else if (butis & MouseBitMiddle)
return kMouseMiddle;
return kMouseNone;
}
bool ags_misbuttondown(eAGSMouseButton but) {
return (mouse_button_poll() & MouseButton2Bits[but]) != 0;
}
eAGSMouseButton ags_mgetbutton() {
if (_G(pluginSimulatedClick) > kMouseNone) {
eAGSMouseButton mbut = _G(pluginSimulatedClick);
_G(pluginSimulatedClick) = kMouseNone;
return mbut;
}
return mgetbutton();;
}
void ags_mouse_get_relxy(int &x, int &y) {
x = _G(mouse_accum_relx);
y = _G(mouse_accum_rely);
_G(mouse_accum_relx) = 0;
_G(mouse_accum_rely) = 0;
}
void ags_domouse() {
mgetgraphpos();
}
int ags_check_mouse_wheel() {
if (_GP(game).options[OPT_MOUSEWHEEL] == 0) {
return 0;
}
if (_G(sys_mouse_z) == _G(mouse_z_was)) {
return 0;
}
int result = 0;
if (_G(sys_mouse_z) > _G(mouse_z_was))
result = 1; // eMouseWheelNorth
else
result = -1; // eMouseWheelSouth
_G(mouse_z_was) = _G(sys_mouse_z);
return result;
}
void ags_clear_input_state() {
// Clear everything related to the input field
::AGS::g_events->clearEvents();
_G(mouse_accum_relx) = 0;
_G(mouse_accum_rely) = 0;
_G(mouse_button_state) = 0;
_G(mouse_accum_button_state) = 0;
_G(mouse_clear_at_time) = AGS_Clock::now();
}
void ags_clear_input_buffer() {
::AGS::g_events->clearEvents();
// accumulated state only helps to not miss clicks
_G(mouse_accum_button_state) = 0;
// forget about recent mouse relative movement too
_G(mouse_accum_relx) = 0;
_G(mouse_accum_rely) = 0;
}
void ags_clear_mouse_movement() {
_G(mouse_accum_relx) = 0;
_G(mouse_accum_rely) = 0;
}
// TODO: this is an awful function that should be removed eventually.
// Must replace with proper updateable game state.
void ags_wait_until_keypress() {
do {
sys_evt_process_pending();
_G(platform)->YieldCPU();
} while (!SHOULD_QUIT && !ags_keyevent_ready());
ags_clear_input_buffer();
}
// ----------------------------------------------------------------------------
// EVENTS
// ----------------------------------------------------------------------------
void sys_evt_set_quit_callback(void(*proc)(void)) {
_on_quit_callback = proc;
}
void sys_evt_set_focus_callbacks(void(*switch_in)(void), void(*switch_out)(void)) {
_on_switchin_callback = switch_in;
_on_switchout_callback = switch_out;
}
static void sys_process_event(const Common::Event &event) {
switch (event.type) {
case Common::EVENT_MOUSEMOVE:
on_mouse_motion(event);
break;
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_MBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONUP:
case Common::EVENT_MBUTTONUP:
on_mouse_button(event);
break;
case Common::EVENT_WHEELDOWN:
case Common::EVENT_WHEELUP:
on_mouse_wheel(event);
break;
default:
break;
}
}
void sys_evt_process_pending(void) {
::AGS::g_events->pollEvents();
Common::Event e;
while ((e = ::AGS::g_events->readEvent()).type != Common::EVENT_INVALID)
sys_process_event(e);
}
void sys_flush_events(void) {
::AGS::g_events->clearEvents();
ags_clear_input_state();
}
} // namespace AGS3