added mouse support for scripted player controls

stable-5.2
Sven Eberhardt 2009-10-17 17:53:26 +02:00
parent 6ee52433b2
commit 9be7a2724a
9 changed files with 305 additions and 64 deletions

View File

@ -1369,7 +1369,7 @@ C4Object *C4Game::FindVisObject(float tx, float ty, int32_t iPlr, const C4Facet
{
// Scan all objects in list
C4ObjectLink *cLnk; C4Object *cObj;
for (cLnk=Objects.First; cLnk && (cObj=cLnk->Obj); cLnk=cLnk->Next)
for (cLnk=pLst->First; cLnk && (cObj=cLnk->Obj); cLnk=cLnk->Next)
{
// Status
if (cObj->Status == C4OS_NORMAL)

View File

@ -29,6 +29,7 @@
#include <C4Record.h>
#include <C4Log.h>
#include <C4Network2Stats.h>
#include <C4MouseControl.h>
#endif
#ifdef _MSC_VER
@ -235,6 +236,7 @@ bool C4GameControl::Prepare()
assert(fInitComplete);
// Prepare control, return true if everything is ready for GameGo.
bool is_input_prepared = false;
switch(eMode)
{
@ -246,13 +248,19 @@ bool C4GameControl::Prepare()
Network.Execute();
// deactivated and got control: request activate
if(Input.firstPkt() && !Game.Clients.getLocal()->isActivated())
::Network.RequestActivate();
// deactivated and got control: request activate
if(Input.firstPkt() && !Game.Clients.getLocal()->isActivated())
::Network.RequestActivate();
// needs input?
while(Network.CtrlNeeded(Game.FrameCounter))
{
if (!is_input_prepared && Game.Clients.getLocal()->isActivated())
{
// add per-controlframe input
PrepareInput();
is_input_prepared = true;
}
Network.DoInput(Input);
Input.Clear();
}
@ -283,6 +291,7 @@ void C4GameControl::Execute()
if(eMode == CM_Local)
{
// control = input
PrepareInput(); // add per-controlframe input
Control.Take(Input);
}
if(eMode == CM_Network)
@ -519,4 +528,10 @@ void C4GameControl::RemoveOldSyncChecks()
}
}
void C4GameControl::PrepareInput()
{
// add per-controlframe input
::MouseControl.DoMoveInput();
}
C4GameControl Control;

View File

@ -165,6 +165,9 @@ protected:
C4ControlSyncCheck *GetSyncCheck(int32_t iTick);
void RemoveOldSyncChecks();
// add per-controlframe input
void PrepareInput();
};
extern C4GameControl Control;

View File

@ -27,6 +27,7 @@
#include <C4Game.h>
#include <C4Log.h>
#include <C4GraphicsResource.h>
#include <C4MouseControl.h>
#endif
/* C4PlayerControlDef */
@ -433,6 +434,12 @@ C4Facet C4PlayerControlAssignmentSet::GetPicture() const
return C4Facet();
}
bool C4PlayerControlAssignmentSet::IsMouseControlAssigned(int32_t mouseevent) const
{
// TODO
return true;
}
/* C4PlayerControlAssignmentSets */
@ -687,25 +694,33 @@ bool C4PlayerControl::ProcessKeyEvent(const C4KeyCodeEx &pressed_key, const C4Ke
}
bool C4PlayerControl::ProcessKeyDown(const C4KeyCodeEx &pressed_key, const C4KeyCodeEx &matched_key)
{
{
// add key to local "down" list if it's not already in there
// except for some mouse events for which a down state does not make sense
C4PlayerControlRecentKey RKey(pressed_key,matched_key,timeGetTime());
if (std::find(DownKeys.begin(), DownKeys.end(), pressed_key) == DownKeys.end()) DownKeys.push_back(RKey);
if (!Key_IsMouse(pressed_key.Key) || Inside<uint8_t>(Key_GetMouseEvent(pressed_key.Key), KEY_MOUSE_Button1, KEY_MOUSE_ButtonMax))
{
if (std::find(DownKeys.begin(), DownKeys.end(), pressed_key) == DownKeys.end()) DownKeys.push_back(RKey);
}
// process!
bool fResult = ProcessKeyEvent(pressed_key, matched_key, false, Game.KeyboardInput.GetLastKeyExtraData());
// add to recent list unless repeated
if (!pressed_key.IsRepeated()) RecentKeys.push_back(RKey);
return fResult;
}
}
bool C4PlayerControl::ProcessKeyUp(const C4KeyCodeEx &pressed_key, const C4KeyCodeEx &matched_key)
{
{
// remove key from "down" list
C4PlayerControlRecentKeyList::iterator i = find(DownKeys.begin(), DownKeys.end(), pressed_key);
if (i != DownKeys.end()) DownKeys.erase(i);
// except for some mouse events for which a down state does not make sense
if (!Key_IsMouse(pressed_key.Key) || Inside<uint8_t>(Key_GetMouseEvent(pressed_key.Key), KEY_MOUSE_Button1, KEY_MOUSE_ButtonMax))
{
C4PlayerControlRecentKeyList::iterator i = find(DownKeys.begin(), DownKeys.end(), pressed_key);
if (i != DownKeys.end()) DownKeys.erase(i);
}
// process!
return ProcessKeyEvent(pressed_key, matched_key, true, Game.KeyboardInput.GetLastKeyExtraData());
}
}
void C4PlayerControl::ExecuteControlPacket(const class C4ControlPlayerControl *pCtrl)
{
@ -853,48 +868,48 @@ bool C4PlayerControl::ExecuteControlScript(int32_t iControl, C4ID idControlExtra
void C4PlayerControl::Execute()
{
{
// sync execution: Do keyrepeat
for (int32_t i=0; i<ControlDefs.GetCount(); ++i)
{
{
const CSync::ControlDownState *pControlDownState = Sync.GetControlDownState(i);
if (pControlDownState && pControlDownState->IsDown())
{
{
const C4PlayerControlDef *pCtrlDef = ControlDefs.GetControlByIndex(i);
assert(pCtrlDef);
int32_t iCtrlRepeatDelay = pCtrlDef->GetRepeatDelay();
if (iCtrlRepeatDelay)
{
{
int32_t iFrameDiff = Game.FrameCounter - pControlDownState->iDownFrame;
int32_t iCtrlInitialRepeatDelay = pCtrlDef->GetInitialRepeatDelay();
if (iFrameDiff && iFrameDiff >= iCtrlInitialRepeatDelay)
{
{
if (!((iFrameDiff-iCtrlInitialRepeatDelay) % iCtrlRepeatDelay))
{
{
// it's RepeatTime for this key!
ExecuteControlAction(i, pCtrlDef->GetAction(), pCtrlDef->GetExtraData(), false, pControlDownState->DownState, true);
}
}
}
}
}
}
// cleanup old recent keys
C4PlayerControlRecentKeyList::iterator irk;
DWORD tNow = timeGetTime();
for (irk = RecentKeys.begin(); irk != RecentKeys.end(); ++irk)
{
{
C4PlayerControlRecentKey &rk = *irk;
if (rk.tTime + MaxRecentKeyLookback > tNow) break;
}
if (irk != RecentKeys.begin()) RecentKeys.erase(RecentKeys.begin(), irk);
}
if (irk != RecentKeys.begin()) RecentKeys.erase(RecentKeys.begin(), irk);
}
C4PlayerControl::C4PlayerControl() : ControlDefs(Game.PlayerControlDefs), iPlr(-1), pControlSet(NULL)
{
}
{
}
void C4PlayerControl::Clear()
{
{
iPlr = NO_OWNER;
pControlSet = NULL;
for (KeyBindingList::iterator i = KeyBindings.begin(); i != KeyBindings.end(); ++i) delete *i;
@ -902,10 +917,10 @@ void C4PlayerControl::Clear()
RecentKeys.clear();
DownKeys.clear();
Sync.Clear();
}
}
void C4PlayerControl::RegisterKeyset(int32_t iPlr, C4PlayerControlAssignmentSet *pKeyset)
{
{
// clear any previous settings
Clear();
// setup
@ -913,19 +928,73 @@ void C4PlayerControl::RegisterKeyset(int32_t iPlr, C4PlayerControlAssignmentSet
this->iPlr = iPlr;
// register all keys into Game.KeyboardInput creating KeyBindings
if (pControlSet)
{
{
C4KeyCodeExVec RegularKeys, HoldKeys;
pControlSet->GetTriggerKeys(ControlDefs, &RegularKeys, &HoldKeys);
int32_t idx=0;
for (C4KeyCodeExVec::const_iterator i = RegularKeys.begin(); i != RegularKeys.end(); ++i) AddKeyBinding(*i, false, idx++);
for (C4KeyCodeExVec::const_iterator i = HoldKeys.begin(); i != HoldKeys.end(); ++i) AddKeyBinding(*i, true, idx++);
}
}
}
void C4PlayerControl::AddKeyBinding(const C4KeyCodeEx &key, bool fHoldKey, int32_t idx)
{
{
KeyBindings.push_back(new C4KeyBinding(
key, FormatString("PlrKey%02d", idx).getData(), KEYSCOPE_Control,
new C4KeyCBExPassKey<C4PlayerControl, C4KeyCodeEx>(*this, key, &C4PlayerControl::ProcessKeyDown, fHoldKey ? &C4PlayerControl::ProcessKeyUp : NULL),
C4CustomKey::PRIO_PlrControl));
}
bool C4PlayerControl::DoMouseInput(uint8_t mouse_id, int32_t mouseevent, float game_x, float game_y, float gui_x, float gui_y, bool is_ctrl_down, bool is_shift_down, bool is_alt_down)
{
// convert moueevent to key code
uint8_t mouseevent_code;
C4KeyCodeEx mouseevent_keycode;
bool is_down = false;
switch (mouseevent)
{
case C4MC_Button_None: mouseevent_code = KEY_MOUSE_Move; break;
case C4MC_Button_LeftDown: is_down = true; // nobreak
case C4MC_Button_LeftUp: mouseevent_code = KEY_MOUSE_ButtonLeft; break;
case C4MC_Button_RightDown: is_down = true; // nobreak
case C4MC_Button_RightUp: mouseevent_code = KEY_MOUSE_ButtonLeft; break;
case C4MC_Button_LeftDouble: mouseevent_code = KEY_MOUSE_ButtonLeftDouble; break;
case C4MC_Button_RightDouble: mouseevent_code = KEY_MOUSE_ButtonRightDouble; break;
case C4MC_Button_Wheel: mouseevent_code = KEY_MOUSE_ButtonMiddleDouble; break;
case C4MC_Button_MiddleDown: is_down = true; // nobreak
case C4MC_Button_MiddleUp: mouseevent_code = KEY_MOUSE_ButtonMiddle; break;
default: assert(false); return false;
}
// compose keycode
if (is_ctrl_down) mouseevent_keycode.dwShift |= KEYS_Control;
if (is_shift_down) mouseevent_keycode.dwShift |= KEYS_Shift;
if (is_alt_down) mouseevent_keycode.dwShift |= KEYS_Alt;
mouseevent_keycode.Key = KEY_Mouse(mouse_id, mouseevent_code, false);
// first, try processing it as GUI mouse event. if not assigned, process as Game mous event
// TODO: May route this through Game.DoKeyboardInput instead - would allow assignment of mouse events in CustomConfig
// and would get rid of the Game.KeyboardInput.SetLastKeyExtraData-hack
C4KeyEventData mouseevent_data;
mouseevent_data.iStrength = 100; // TODO: May get pressure from tablet here
mouseevent_data.x = uint32_t(gui_x);
mouseevent_data.y = uint32_t(gui_y);
Game.KeyboardInput.SetLastKeyExtraData(mouseevent_data); // ProcessKeyDown/Up queries it from there...
bool result;
if (is_down)
result = ProcessKeyDown(mouseevent_keycode, mouseevent_keycode);
else
result = ProcessKeyUp(mouseevent_keycode, mouseevent_keycode);
if (result)
{
// mouse event processed in GUI coordinates
return true;
}
// try processing in Game coordinates instead
mouseevent_data.x = uint32_t(game_x);
mouseevent_data.y = uint32_t(game_y);
mouseevent_keycode.Key |= KEY_MOUSE_GameMask;
if (is_down)
result = ProcessKeyDown(mouseevent_keycode, mouseevent_keycode);
else
result = ProcessKeyUp(mouseevent_keycode, mouseevent_keycode);
return result;
}

View File

@ -220,6 +220,7 @@ class C4PlayerControlAssignmentSet
bool HasGamepad() const { return has_gamepad; }
int32_t GetLayoutOrder() const { return 0; } // returns position on keyboard (increasing from left to right) for viewport sorting
int32_t GetGamepadIndex() const { return 0; }
bool IsMouseControlAssigned(int32_t mouseevent) const;
};
// list of C4PlayerControlAssignmentSet
@ -348,6 +349,9 @@ class C4PlayerControl
// sync execution: Do keyrepeat, etc.
void Execute();
// mouse input
bool DoMouseInput(uint8_t mouse_id, int32_t mouseevent, float game_x, float game_y, float gui_x, float gui_y, bool is_ctrl_down, bool is_shift_down, bool is_alt_down);
};

View File

@ -366,6 +366,56 @@ C4KeyCode C4KeyCodeEx::String2KeyCode(const StdStrBuf &sName)
}
}
}
bool is_mouse_key, is_gamemouse_key;
#ifdef _WIN32
is_mouse_key = !strnicmp(sName.getData(), "Mouse", 5);
is_gamemouse_key = !strnicmp(sName.getData(), "GameMouse", 9);
#else
is_mouse_key = !strncasecmp(sName.getData(), "Mouse", 5);
is_gamemouse_key = !strncasecmp(sName.getData(), "GameMouse", 9);
#endif
if (is_mouse_key || is_gamemouse_key)
{
// skip Mouse/GameMouse
const char *key_str = sName.getData()+5;
if (is_gamemouse_key) key_str += 4;
int mouse_id;
if (sscanf(key_str, "%d", &mouse_id) == 1)
{
// skip number
while (isdigit(*key_str)) ++key_str;
// check for known mouse events (e.g. Mouse1Move or GameMouse1Wheel)
if (!stricmp(key_str, "Move")) return KEY_Mouse(mouse_id-1, KEY_MOUSE_Move, is_gamemouse_key);
if (!stricmp(key_str, "Wheel1")) return KEY_Mouse(mouse_id-1, KEY_MOUSE_Wheel1, is_gamemouse_key);
if (!strnicmp(key_str, "Button", 6)) // e.g. Mouse1ButtonLeft or GameMouse1ButtonRightDouble
{
// check for known mouse button events
uint8_t mouseevent_id = 0;
key_str += 6;
if (!strnicmp(key_str, "Left",4)) { mouseevent_id=KEY_MOUSE_ButtonLeft; key_str += 4; }
else if (!strnicmp(key_str, "Right",5)) { mouseevent_id=KEY_MOUSE_ButtonRight; key_str += 5; }
else if (!strnicmp(key_str, "Middle",6)) { mouseevent_id=KEY_MOUSE_ButtonMiddle; key_str += 6; }
else if (isdigit(*key_str))
{
// indexed mouse button (e.g. Mouse1Button4 or Mouse1Button4Double)
int button_index;
if (sscanf(key_str, "%d", &button_index) == 1)
{
mouseevent_id=static_cast<uint8_t>(KEY_MOUSE_Button1+button_index-1);
while (isdigit(*key_str)) ++key_str;
}
}
if (mouseevent_id)
{
// valid event if finished or followed by "Double"
if (!*key_str) return KEY_Mouse(mouse_id-1, mouseevent_id, is_gamemouse_key);
if (!stricmp(key_str, "Double")) return KEY_Mouse(mouse_id-1, mouseevent_id+(KEY_MOUSE_Button1Double-KEY_MOUSE_Button1), is_gamemouse_key);
// invalid mouse key...
}
}
}
}
}
#ifdef _WIN32
// query map
@ -395,38 +445,67 @@ C4KeyCode C4KeyCodeEx::String2KeyCode(const StdStrBuf &sName)
}
StdStrBuf C4KeyCodeEx::KeyCode2String(C4KeyCode wCode, bool fHumanReadable, bool fShort)
{
{
// Gamepad keys
if (Key_IsGamepad(wCode))
{
{
int iGamepad = Key_GetGamepad(wCode);
int iGamepadButton = Key_GetGamepadButton(wCode);
switch (iGamepadButton)
{
int gamepad_event = Key_GetGamepadEvent(wCode);
switch (gamepad_event)
{
case KEY_JOY_Left: return FormatString("Joy%dLeft", iGamepad+1);
case KEY_JOY_Up: return FormatString("Joy%dUp", iGamepad+1);
case KEY_JOY_Down: return FormatString("Joy%dDown", iGamepad+1);
case KEY_JOY_Right: return FormatString("Joy%dRight", iGamepad+1);
default:
if (Key_IsGamepadAxis(wCode))
{
{
if (fHumanReadable)
// This is still not great, but it is not really possible to assign unknown axes to "left/right" "up/down"...
return FormatString("[%d] %s", int(1 + Key_GetGamepadAxisIndex(wCode)), Key_IsGamepadAxisHigh(wCode) ? "Max" : "Min");
else
return FormatString("Joy%dAxis%d%s", iGamepad+1, static_cast<int>(Key_GetGamepadAxisIndex(wCode)+1), Key_IsGamepadAxisHigh(wCode) ? "Max" : "Min");
}
}
else
{
{
// button
if (fHumanReadable)
// If there should be gamepads around with A B C D... on the buttons, we might create a display option to show letters instead...
return FormatString("< %d >", int(1 + Key_GetGamepadButtonIndex(wCode)));
else
return FormatString("Joy%d%c", iGamepad+1, static_cast<char>(Key_GetGamepadButtonIndex(wCode) + 'A'));
}
}
}
}
}
// Mouse keys
if (Key_IsMouse(wCode))
{
int mouse_id = Key_GetMouse(wCode);
int mouse_event = Key_GetMouseEvent(wCode);
bool mouse_is_game = Key_GetMouseIsGameCoordinate(wCode);
const char *mouse_is_game_str = mouse_is_game ? "GameMouse" : "Mouse";
switch (mouse_event)
{
case KEY_MOUSE_Move: return FormatString("%s%dMove", mouse_is_game_str, mouse_id);
case KEY_MOUSE_Wheel1: return FormatString("%s%dWheel1", mouse_is_game_str, mouse_id);
case KEY_MOUSE_ButtonLeft: return FormatString("%s%dLeft", mouse_is_game_str, mouse_id);
case KEY_MOUSE_ButtonRight: return FormatString("%s%dRight", mouse_is_game_str, mouse_id);
case KEY_MOUSE_ButtonMiddle: return FormatString("%s%dMiddle", mouse_is_game_str, mouse_id);
case KEY_MOUSE_ButtonLeftDouble: return FormatString("%s%dLeftDouble", mouse_is_game_str, mouse_id);
case KEY_MOUSE_ButtonRightDouble: return FormatString("%s%dRightDouble", mouse_is_game_str, mouse_id);
case KEY_MOUSE_ButtonMiddleDouble:return FormatString("%s%dMiddleDouble", mouse_is_game_str, mouse_id);
default:
// extended mouse button
{
uint8_t btn = Key_GetMouseEvent(wCode);
if (btn >= KEY_MOUSE_Button1Double)
return FormatString("%s%dButton%dDouble", mouse_is_game_str, mouse_id, int(btn-KEY_MOUSE_Button1Double));
else
return FormatString("%s%dButton%d", mouse_is_game_str, mouse_id, int(btn-KEY_MOUSE_Button1));
}
}
}
#ifdef _WIN32
// TODO: Works?
@ -452,7 +531,7 @@ StdStrBuf C4KeyCodeEx::KeyCode2String(C4KeyCode wCode, bool fHumanReadable, bool
#else
return StdStrBuf("unknown");
#endif
}
}
StdStrBuf C4KeyCodeEx::ToString(bool fHumanReadable, bool fShort)
{

View File

@ -52,36 +52,55 @@ enum C4KeyEventType
// keyboard code
typedef unsigned long C4KeyCode;
// Gamepad codes (KEY_JOY_*): Masked as 0x420000; bit 8-15 used for gamepad index
const C4KeyCode KEY_JOY_Mask = 0x420000;
// Mouse codes (KEY_MOUSE_*): Masked as 0x430000; bit 8-15 used for mouse index
const C4KeyCode KEY_MOUSE_Mask = 0x430000;
const C4KeyCode KEY_Default = 0, // no key
KEY_Any = ~0, // used for default key processing
KEY_Undefined = (~0)^1, // used to indicate an unknown key
KEY_JOY_Left = 1, // joypad axis control: Any x axis min
KEY_JOY_Left = 1, // joypad axis control: Any x axis min
KEY_JOY_Up = 2, // joypad axis control: Any y axis min
KEY_JOY_Right = 3, // joypad axis control: Any x axis max
KEY_JOY_Right = 3, // joypad axis control: Any x axis max
KEY_JOY_Down = 4, // joypad axis control: Any y axis max
KEY_JOY_Button1 = 10, // key index of joypad buttons + button index for more buttons
KEY_JOY_ButtonMax = KEY_JOY_Button1+31, // maximum number of supported buttons on a gamepad
KEY_JOY_Axis1Min = 0x30,
KEY_JOY_Axis1Max = 0x31,
KEY_JOY_AxisMax = KEY_JOY_Axis1Min + 0x20,
KEY_JOY_AnyButton = 0xff, // any joypad button (not axis)
KEY_JOY_AnyOddButton = 0xfe, // joypad buttons 1, 3, 5, etc.
KEY_JOY_AnyEvenButton = 0xfd, // joypad buttons 2, 4, 6, etc.
KEY_JOY_AnyLowButton = 0xfc, // joypad buttons 1 - 4
KEY_JOY_AnyHighButton = 0xfb; // joypad buttons > 4
KEY_JOY_Button1 = 0x10, // key index of joypad buttons + button index for more buttons
KEY_JOY_ButtonMax = KEY_JOY_Button1+0x1f, // maximum number of supported buttons on a gamepad
KEY_JOY_Axis1Min = 0x30,
KEY_JOY_Axis1Max = 0x31,
KEY_JOY_AxisMax = KEY_JOY_Axis1Min + 0x20,
KEY_JOY_AnyButton = 0xff, // any joypad button (not axis)
KEY_JOY_AnyOddButton = 0xfe, // joypad buttons 1, 3, 5, etc.
KEY_JOY_AnyEvenButton = 0xfd, // joypad buttons 2, 4, 6, etc.
KEY_JOY_AnyLowButton = 0xfc, // joypad buttons 1 - 4
KEY_JOY_AnyHighButton = 0xfb, // joypad buttons > 4
KEY_MOUSE_Move = 1, // mouse control: mouse movement
KEY_MOUSE_Button1 = 0x10, // key index of mouse buttons + button index for more buttons
KEY_MOUSE_ButtonLeft = KEY_MOUSE_Button1 + 0,
KEY_MOUSE_ButtonRight = KEY_MOUSE_Button1 + 1,
KEY_MOUSE_ButtonMiddle= KEY_MOUSE_Button1 + 2,
KEY_MOUSE_ButtonMax = KEY_MOUSE_Button1 + 0x1f, // max number of supported mouse buttons
KEY_MOUSE_Button1Double = 0x30, // double clicks have special events because double click speed is issued by OS
KEY_MOUSE_ButtonLeftDouble = KEY_MOUSE_Button1Double + 0,
KEY_MOUSE_ButtonRightDouble = KEY_MOUSE_Button1Double + 1,
KEY_MOUSE_ButtonMiddleDouble= KEY_MOUSE_Button1Double + 2,
KEY_MOUSE_ButtonMaxDouble = KEY_MOUSE_Button1Double + 0x1f, // max number of supported mouse buttons
KEY_MOUSE_Wheel1 = 0x40, // mouse control: wheel up/down
KEY_MOUSE_GameMask = 0x80; // if set, contorl is sent in game coordinates
inline uint8_t KEY_JOY_Button(uint8_t idx) { return KEY_JOY_Button1+idx; }
inline uint8_t KEY_JOY_Axis(uint8_t idx, bool fMax) { return KEY_JOY_Axis1Min+2*idx+fMax; }
inline C4KeyCode KEY_Gamepad(uint8_t idGamepad, uint8_t idButton) // convert gamepad key to Clonk-gamepad-keycode
{
{
// mask key as 0x0042ggbb, where gg is gamepad ID and bb is button ID.
return 0x00420000 + (idGamepad<<8) + idButton;
}
return KEY_JOY_Mask + (idGamepad<<8) + idButton;
}
inline bool Key_IsGamepad(C4KeyCode key)
{
return (0xff0000 & key) == 0x420000;
return (0xff0000 & key) == KEY_JOY_Mask;
}
inline uint8_t Key_GetGamepad(C4KeyCode key)
@ -89,7 +108,7 @@ inline uint8_t Key_GetGamepad(C4KeyCode key)
return ((uint32_t)key >> 8) & 0xff;
}
inline uint8_t Key_GetGamepadButton(C4KeyCode key)
inline uint8_t Key_GetGamepadEvent(C4KeyCode key)
{
return ((uint32_t)key) & 0xff;
}
@ -97,25 +116,25 @@ inline uint8_t Key_GetGamepadButton(C4KeyCode key)
inline bool Key_IsGamepadButton(C4KeyCode key)
{
// whether this is a unique button event (AnyButton not included)
return Key_IsGamepad(key) && Inside<uint8_t>(Key_GetGamepadButton(key), KEY_JOY_Button1, KEY_JOY_ButtonMax);
return Key_IsGamepad(key) && Inside<uint8_t>(Key_GetGamepadEvent(key), KEY_JOY_Button1, KEY_JOY_ButtonMax);
}
inline bool Key_IsGamepadAxis(C4KeyCode key)
{
// whether this is a unique button event (AnyButton not included)
return Key_IsGamepad(key) && Inside<uint8_t>(Key_GetGamepadButton(key), KEY_JOY_Axis1Min, KEY_JOY_AxisMax);
return Key_IsGamepad(key) && Inside<uint8_t>(Key_GetGamepadEvent(key), KEY_JOY_Axis1Min, KEY_JOY_AxisMax);
}
inline uint8_t Key_GetGamepadButtonIndex(C4KeyCode key)
{
// get zero-based button index
return Key_GetGamepadButton(key) - KEY_JOY_Button1;
return Key_GetGamepadEvent(key) - KEY_JOY_Button1;
}
inline uint8_t Key_GetGamepadAxisIndex(C4KeyCode key)
{
// get zero-based axis index
return (Key_GetGamepadButton(key) - KEY_JOY_Axis1Min) / 2;
return (Key_GetGamepadEvent(key) - KEY_JOY_Axis1Min) / 2;
}
inline bool Key_IsGamepadAxisHigh(C4KeyCode key)
@ -123,6 +142,33 @@ inline bool Key_IsGamepadAxisHigh(C4KeyCode key)
return !!(key & 1);
}
inline C4KeyCode KEY_Mouse(uint8_t mouse_id, uint8_t mouseevent, bool is_game_coordinates)
{
// mask key as 0x0043ggbb, where mm is mouse ID and bb is mouse event ID.
return KEY_MOUSE_Mask + (mouse_id<<8) + mouseevent + is_game_coordinates*KEY_MOUSE_GameMask;
}
inline bool Key_IsMouse(C4KeyCode key)
{
return (0xff0000 & key) == KEY_MOUSE_Mask;
}
inline uint8_t Key_GetMouse(C4KeyCode key)
{
return ((uint32_t)key >> 8) & 0xff;
}
inline uint8_t Key_GetMouseEvent(C4KeyCode key)
{
return ((uint32_t)key) & uint8_t(0xff | ~KEY_MOUSE_GameMask);
}
inline bool Key_GetMouseIsGameCoordinate(C4KeyCode key)
{
return !!(key & KEY_MOUSE_GameMask);
}
#ifdef _WIN32
#define TOUPPERIFX11(key) (key)
#else
@ -436,6 +482,7 @@ class C4KeyboardInput
C4CustomKey *GetKeyByName(const char *szKeyName);
StdStrBuf GetKeyCodeNameByKeyName(const char *szKeyName, bool fShort = false, int32_t iIndex = 0);
const C4KeyEventData &GetLastKeyExtraData() const { return LastKeyExtraData; }
void SetLastKeyExtraData(const C4KeyEventData &data) { LastKeyExtraData=data; }
};
// keyboardinput-initializer-helper

View File

@ -343,6 +343,30 @@ void C4MouseControl::Move(int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyFl
//------------------------------------------------------------------------------------------
case C4MC_Button_Wheel: Wheel(dwKeyFlags); break;
}
// script handling of mouse control for everything but regular movement (which is sent at control frame intervals only)
if (iButton != C4MC_Button_None)
// not if blocked by selection object
if (!TargetRegion && !TargetObject)
// safety (can't really happen in !IsPassive, but w/e
if (pPlayer && pPlayer->ControlSet)
{
if (pPlayer->ControlSet->IsMouseControlAssigned(iButton))
{
pPlayer->Control.DoMouseInput(0 /* only 1 mouse supported so far */, iButton, GameX, GameY, GuiX, GuiY, ControlDown, ShiftDown, Application.IsAltDown());
}
}
}
void C4MouseControl::DoMoveInput()
{
// current mouse move to input queue
// do sanity checks
if (!Active || !fMouseOwned) return;
if (!(pPlayer=::Players.Get(Player))) return;
if (!pPlayer->ControlSet) return;
if (!pPlayer->ControlSet->IsMouseControlAssigned(C4MC_Button_None)) return;
pPlayer->Control.DoMouseInput(0 /* only 1 mouse supported so far */, C4MC_Button_None, GameX, GameY, GuiX, GuiY, ControlDown, ShiftDown, Application.IsAltDown());
}
void C4MouseControl::Draw(C4TargetFacet &cgo, const ZoomData &GameZoom)
@ -914,10 +938,9 @@ void C4MouseControl::LeftUpDragNone()
// Nothing
case C4MC_Cursor_Nothing:
break;
// Movement
// Movement?
default:
// MoveTo command to control queue
SendCommand(C4CMD_MoveTo,int32_t(GameX),int32_t(GameY),NULL);
// done in script
break;
}
// Clear selection

View File

@ -96,6 +96,7 @@ class C4MouseControl
void ShowCursor();
void Draw(C4TargetFacet &cgo, const ZoomData &GameZoom);
void Move(int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyFlags, bool fCenter = false);
void DoMoveInput();
bool IsViewport(C4Viewport *pViewport);
void ClearPointers(C4Object *pObj);
void UpdateClip(); // update clipping region for mouse cursor