329 lines
7.6 KiB
C++
329 lines
7.6 KiB
C++
#include "main/references.h"
|
|
#include "main/input_handling.h"
|
|
#include "main/initialization.h"
|
|
#include "main/tick.h"
|
|
#include "main/console.h"
|
|
#include "os/driver.h"
|
|
#include <set>
|
|
|
|
#include "processing.h"
|
|
|
|
#define func(x) std::function<decltype(x)>(x)
|
|
|
|
enum InputCall {
|
|
IC_MouseWheel,
|
|
IC_MouseDrag,
|
|
IC_MouseDragEnd,
|
|
IC_MouseMove,
|
|
IC_MouseClick,
|
|
IC_MouseButton,
|
|
IC_CharTyped,
|
|
IC_KeyEvent,
|
|
IC_DoubleClick,
|
|
IC_Overlay,
|
|
|
|
IC_COUNT
|
|
};
|
|
|
|
const char* InputCallDecls[IC_COUNT] = {
|
|
"void onMouseWheel(double,double)",
|
|
"void onMouseDragged(int, int, int, int, int)",
|
|
"bool onMouseDragEnd(int)",
|
|
"void onMouseMoved(int, int)",
|
|
"void onMouseClicked(int)",
|
|
"bool onMouseButton(int, bool)",
|
|
"bool onCharTyped(int)",
|
|
"bool onKeyEvent(int, int)",
|
|
"void onMouseDoubleClicked(int)",
|
|
"void onOverlayChanged(bool)",
|
|
};
|
|
|
|
asIScriptFunction* inputCalls[GS_COUNT][IC_COUNT];
|
|
scripts::Manager* manager[GS_COUNT];
|
|
|
|
INIT_FUNC(clear_input) {
|
|
memset(inputCalls, 0, IC_COUNT * GS_COUNT * sizeof(asIScriptFunction*));
|
|
memset(manager, 0, GS_COUNT * sizeof(scripts::Manager*));
|
|
} INIT_FUNC_END;
|
|
|
|
void clearInputScripts(GameState state) {
|
|
memset(inputCalls[state], 0, IC_COUNT * sizeof(asIScriptFunction*));
|
|
manager[state] = 0;
|
|
}
|
|
|
|
void bindInputScripts(GameState state, scripts::Manager* Manager) {
|
|
if(Manager)
|
|
manager[state] = Manager;
|
|
|
|
if(!Manager) {
|
|
clearInputScripts(state);
|
|
return;
|
|
}
|
|
|
|
for(unsigned i = 0; i < IC_COUNT; ++i)
|
|
inputCalls[state][i] = manager[state]->getFunction("input", InputCallDecls[i]);
|
|
}
|
|
|
|
void onOverlayToggle(bool state) {
|
|
if(manager[game_state] && inputCalls[game_state][IC_Overlay]) {
|
|
auto call = manager[game_state]->call(inputCalls[game_state][IC_Overlay]);
|
|
call.push(state);
|
|
call.call();
|
|
}
|
|
}
|
|
|
|
bool onWindowClose() {
|
|
game_state = GS_Quit;
|
|
return true;
|
|
}
|
|
|
|
bool onCharTyped(int key) {
|
|
if(console.character(key))
|
|
return true;
|
|
//Inform the script
|
|
bool ret = true;
|
|
if(manager[game_state] && inputCalls[game_state][IC_CharTyped]) {
|
|
auto call = manager[game_state]->call(inputCalls[game_state][IC_CharTyped]);
|
|
call.push(key);
|
|
call.call(ret);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
std::set<profile::Keybind*> pressedKeys;
|
|
void onModifiersChanged() {
|
|
foreach(key, pressedKeys)
|
|
(*key)->call(false);
|
|
pressedKeys.clear();
|
|
}
|
|
|
|
void clearPressedKeys() {
|
|
pressedKeys.clear();
|
|
}
|
|
|
|
bool onKeyEvent(int key, int keyaction) {
|
|
bool pressed = keyaction & os::KA_Pressed;
|
|
|
|
//Figure out if the modifier mask was changed
|
|
switch(key) {
|
|
case os::KEY_LCTRL:
|
|
case os::KEY_RCTRL:
|
|
case os::KEY_LALT:
|
|
case os::KEY_RALT:
|
|
case os::KEY_LSHIFT:
|
|
case os::KEY_RSHIFT:
|
|
onModifiersChanged();
|
|
break;
|
|
}
|
|
|
|
//Build key with modifiers
|
|
int mod_key = key;
|
|
if(mod_key >= 'A' && mod_key <= 'Z')
|
|
mod_key += 'a'-'A';
|
|
profile::Keybind* bind = devices.keybinds.global.getBind(mod_key);
|
|
|
|
if(devices.driver->ctrlKey)
|
|
mod_key |= profile::Mod_Ctrl;
|
|
if(devices.driver->altKey)
|
|
mod_key |= profile::Mod_Alt;
|
|
if(devices.driver->shiftKey)
|
|
mod_key |= profile::Mod_Shift;
|
|
profile::Keybind* mod_bind = devices.keybinds.global.getBind(mod_key);
|
|
if(mod_bind)
|
|
bind = mod_bind;
|
|
|
|
if(bind != console.keybind && console.key(key, pressed))
|
|
return true;
|
|
|
|
//Inform the script
|
|
if(manager[game_state] && inputCalls[game_state][IC_KeyEvent]) {
|
|
bool ret = false;
|
|
auto call = manager[game_state]->call(inputCalls[game_state][IC_KeyEvent]);
|
|
call.push(key);
|
|
call.push(keyaction);
|
|
call.call(ret);
|
|
if(ret)
|
|
return true;
|
|
}
|
|
|
|
if(console.globalKey(key, pressed))
|
|
return true;
|
|
|
|
//Trigger Keybinds
|
|
if(bind) {
|
|
bind->call(pressed);
|
|
if(pressed)
|
|
pressedKeys.insert(bind);
|
|
else
|
|
pressedKeys.erase(bind);
|
|
return true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
struct MouseKey {
|
|
bool pressed;
|
|
int pressed_time;
|
|
|
|
MouseKey() : pressed(false), pressed_time(0) {}
|
|
} mouseButtons[3];
|
|
|
|
int dragging = 0;
|
|
int pressed_x = 0, pressed_y = 0;
|
|
int cur_x = 0, cur_y = 0;
|
|
int tot_drag = 0;
|
|
const int dblClickTimeout = 200;
|
|
|
|
bool onMouseButton(int button, int pressed) {
|
|
//When the mouse is being dragged at the system level, don't pass it to the GUI
|
|
if(dragging) {
|
|
if(pressed) {
|
|
dragging |= (0x1 << button);
|
|
mouseButtons[button].pressed = true;
|
|
}
|
|
else {
|
|
dragging &= ~(0x1 << button);
|
|
mouseButtons[button].pressed = false;
|
|
}
|
|
|
|
if(!dragging) {
|
|
devices.driver->setCursorVisible(true);
|
|
|
|
if(tot_drag > 4) {
|
|
tot_drag = 0;
|
|
bool resetMouse = true;
|
|
|
|
if(manager[game_state] && inputCalls[game_state][IC_MouseDragEnd]) {
|
|
auto call = manager[game_state]->call(inputCalls[game_state][IC_MouseDragEnd]);
|
|
call.push(button);
|
|
call.call(resetMouse);
|
|
}
|
|
|
|
if(resetMouse)
|
|
devices.driver->setMousePos(pressed_x, pressed_y);
|
|
return true;
|
|
}
|
|
|
|
tot_drag = 0;
|
|
}
|
|
}
|
|
|
|
if(pressed == 0)
|
|
mouseButtons[button].pressed = false;
|
|
|
|
bool eventAbsorbed = false;
|
|
if(manager[game_state]) {
|
|
//Pass button event to scripts
|
|
if(inputCalls[game_state][IC_MouseButton]) {
|
|
auto call = manager[game_state]->call(inputCalls[game_state][IC_MouseButton]);
|
|
call.push(button);
|
|
call.push(pressed == 1);
|
|
call.call(eventAbsorbed);
|
|
}
|
|
|
|
//Pass click events to scripts
|
|
if(!pressed) {
|
|
int time = devices.driver->getTime();
|
|
if(mouseButtons[button].pressed_time > time - dblClickTimeout) {
|
|
mouseButtons[button].pressed_time = 0;
|
|
|
|
if(inputCalls[game_state][IC_DoubleClick]) {
|
|
auto call = manager[game_state]->call(inputCalls[game_state][IC_DoubleClick]);
|
|
call.push(button);
|
|
call.call();
|
|
}
|
|
}
|
|
else {
|
|
mouseButtons[button].pressed_time = time;
|
|
|
|
if(inputCalls[game_state][IC_MouseClick]) {
|
|
auto call = manager[game_state]->call(inputCalls[game_state][IC_MouseClick]);
|
|
call.push(button);
|
|
call.call();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pressed != 0 && !eventAbsorbed) {
|
|
mouseButtons[button].pressed = true;
|
|
|
|
if(!dragging) {
|
|
devices.driver->getMousePos(pressed_x, pressed_y);
|
|
cur_x = pressed_x;
|
|
cur_y = pressed_y;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool onMouseMoved(int x, int y) {
|
|
int prevDragging = dragging;
|
|
dragging = (mouseButtons[0].pressed ? 0x1 : 0)
|
|
| (mouseButtons[1].pressed ? 0x2 : 0)
|
|
| (mouseButtons[2].pressed ? 0x4 : 0);
|
|
|
|
if(dragging) {
|
|
if(!prevDragging)
|
|
devices.driver->setCursorVisible(false);
|
|
|
|
if(manager[game_state] && inputCalls[game_state][IC_MouseDrag]) {
|
|
int dx = x-cur_x, dy = cur_y-y;
|
|
tot_drag += abs(dx) + abs(dy);
|
|
|
|
if(dx || dy) {
|
|
auto call = manager[game_state]->call(inputCalls[game_state][IC_MouseDrag]);
|
|
call.push(dragging);
|
|
call.push((int)(pressed_x / ui_scale));
|
|
call.push((int)(pressed_y / ui_scale));
|
|
call.push(dx);
|
|
call.push(dy);
|
|
call.call();
|
|
|
|
cur_y = y;
|
|
cur_x = x;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if(manager[game_state] && inputCalls[game_state][IC_MouseMove]) {
|
|
//Pass move event to scripts
|
|
auto call = manager[game_state]->call(inputCalls[game_state][IC_MouseMove]);
|
|
call.push((int)(x / ui_scale));
|
|
call.push((int)(y / ui_scale));
|
|
call.call();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool onMouseWheel(double x, double y) {
|
|
if(manager[game_state] && inputCalls[game_state][IC_MouseWheel]) {
|
|
auto call = manager[game_state]->call(inputCalls[game_state][IC_MouseWheel]);
|
|
call.push(x);
|
|
call.push(y);
|
|
call.call();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
void registerInput() {
|
|
//Add base callbacks for os driver
|
|
devices.driver->onWindowClose.add(onWindowClose);
|
|
//devices.driver->onResize.add(onWindowClose);
|
|
devices.driver->onScroll.add(onMouseWheel);
|
|
devices.driver->onMouseButton.add(onMouseButton);
|
|
devices.driver->onMouseMoved.add(onMouseMoved);
|
|
devices.driver->onCharTyped.add(onCharTyped);
|
|
devices.driver->onKeyEvent.add(onKeyEvent);
|
|
}
|
|
|
|
void inputTick() {
|
|
if(dragging) {
|
|
cur_x = pressed_x;
|
|
cur_y = pressed_y;
|
|
devices.driver->setMousePos(pressed_x, pressed_y);
|
|
}
|
|
}
|