Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions code/command.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ class CommandClass
virtual char const * Get_Category(void) const = 0;
virtual char const * Get_Description(void) const = 0;
virtual void Execute(void) const = 0;

// Repeatable commands re-execute every frame their bound key is held down, since
// Windows key-repeat events never reach the game's keyboard buffer.
virtual bool Is_Repeatable(void) const { return(false); }
};
40 changes: 32 additions & 8 deletions code/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4268,9 +4268,12 @@ class ScrollNCommandClass : public CommandClass
}

virtual void Execute(void) const {
int distance = 34;
int distance = Map.Get_Keyboard_Scroll_Distance();
Map.Scroll_Map(FACING_N, distance, true);
}
virtual bool Is_Repeatable(void) const {
return(true);
}
};


Expand All @@ -4291,9 +4294,12 @@ class ScrollSCommandClass : public CommandClass
}

virtual void Execute(void) const {
int distance = 34;
int distance = Map.Get_Keyboard_Scroll_Distance();
Map.Scroll_Map(FACING_S, distance, true);
}
virtual bool Is_Repeatable(void) const {
return(true);
}
};


Expand All @@ -4314,9 +4320,12 @@ class ScrollECommandClass : public CommandClass
}

virtual void Execute(void) const {
int distance = 34;
int distance = Map.Get_Keyboard_Scroll_Distance();
Map.Scroll_Map(FACING_E, distance, true);
}
virtual bool Is_Repeatable(void) const {
return(true);
}
};


Expand All @@ -4337,9 +4346,12 @@ class ScrollWCommandClass : public CommandClass
}

virtual void Execute(void) const {
int distance = 34;
int distance = Map.Get_Keyboard_Scroll_Distance();
Map.Scroll_Map(FACING_W, distance, true);
}
virtual bool Is_Repeatable(void) const {
return(true);
}
};


Expand All @@ -4360,9 +4372,12 @@ class ScrollNECommandClass : public CommandClass
}

virtual void Execute(void) const {
int distance = 34;
int distance = Map.Get_Keyboard_Scroll_Distance();
Map.Scroll_Map(FACING_NE, distance, true);
}
virtual bool Is_Repeatable(void) const {
return(true);
}
};


Expand All @@ -4383,9 +4398,12 @@ class ScrollSECommandClass : public CommandClass
}

virtual void Execute(void) const {
int distance = 34;
int distance = Map.Get_Keyboard_Scroll_Distance();
Map.Scroll_Map(FACING_SE, distance, true);
}
virtual bool Is_Repeatable(void) const {
return(true);
}
};


Expand All @@ -4406,9 +4424,12 @@ class ScrollSWCommandClass : public CommandClass
}

virtual void Execute(void) const {
int distance = 34;
int distance = Map.Get_Keyboard_Scroll_Distance();
Map.Scroll_Map(FACING_SW, distance, true);
}
virtual bool Is_Repeatable(void) const {
return(true);
}
};


Expand All @@ -4429,9 +4450,12 @@ class ScrollNWCommandClass : public CommandClass
}

virtual void Execute(void) const {
int distance = 34;
int distance = Map.Get_Keyboard_Scroll_Distance();
Map.Scroll_Map(FACING_NW, distance, true);
}
virtual bool Is_Repeatable(void) const {
return(true);
}
};


Expand Down
33 changes: 32 additions & 1 deletion code/mainloop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "_bench.h"
#include "_command.h"
#include "_keyboar.h"
#include "_logic.h"
#include "_map.h"
#include "_palette.h"
Expand Down Expand Up @@ -457,6 +458,24 @@ bool Main_Loop(void)

void Ingame_Menu_Dialog(void);

// Keyboard->Down() only checks a key's virtual-key code, so a repeatable command bound with
// Shift/Ctrl/Alt needs those modifiers checked separately against live key state.
static bool Is_Repeat_Key_Held(int key)
{
if (!Keyboard->Down(KeyNumType(key))) {
return(false);
}

bool shift = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
bool ctrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
bool alt = (GetKeyState(VK_MENU) & 0x8000) != 0;

return shift == ((key & WWKEY_SHIFT_BIT) != 0)
&& ctrl == ((key & WWKEY_CTRL_BIT) != 0)
&& alt == ((key & WWKEY_ALT_BIT) != 0);
}


/***********************************************************************************************
* Keyboard_Process -- Processes the tactical map input codes. *
* *
Expand All @@ -476,6 +495,15 @@ void Ingame_Menu_Dialog(void);
*=============================================================================================*/
void Keyboard_Process(KeyNumType & input)
{
// Windows key-repeat events never reach the keyboard buffer, so a repeatable command
// (e.g. map scrolling) has to be re-triggered here by polling its bound key every frame.
for (int index = 0; index < HotkeyCommands.Count(); index++) {
CommandClass const * repeatcmd = HotkeyCommands.Fetch_By_Position(index);
if (repeatcmd->Is_Repeatable() && Is_Repeat_Key_Held(HotkeyCommands.Fetch_ID_By_Position(index))) {
repeatcmd->Execute();
}
}

/*
** Don't do anything if there is not keyboard event.
*/
Expand All @@ -498,7 +526,10 @@ void Keyboard_Process(KeyNumType & input)

if (cmd != NULL) {

cmd->Execute();
// Repeatable commands are driven by the per-frame poll above instead.
if (!cmd->Is_Repeatable()) {
cmd->Execute();
}

} else {

Expand Down
48 changes: 34 additions & 14 deletions code/scroll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,21 @@ static double _ScrollFraction = 0.0;
static double _EdgeScrollRemainder = 0.0;
static double _CoastRemainderX = 0.0;
static double _CoastRemainderY = 0.0;
static double _KeyScrollRemainder = 0.0;

// Indexed by an inertia-derived rate; a lower index is a faster step. Shared by edge scroll and
// keyboard scroll so both settle at the same top speed for a given Options.ScrollRate.
static int const _ScrollRateTable[9] = {
0x00E0*2,
0x00C0*2,
0x00A0*2,
0x0080*2,
0x0060*2,
0x0040*2,
0x0020*2,
0x0010*2,
0x0008*2
};


/***********************************************************************************************
Expand Down Expand Up @@ -472,18 +487,6 @@ void ScrollClass::Scroll_Edge(Point2D const & point)
** The mouse is over a scroll region so set the mouse shape accordingly if the map
** can be scrolled in the direction indicated.
*/
static int _rate[9] = {
0x00E0*2,
0x00C0*2,
0x00A0*2,
0x0080*2,
0x0060*2,
0x0040*2,
0x0020*2,
0x0010*2,
0x0008*2
};

int rate = 8-Inertia;

if (rate < Options.ScrollRate+1) {
Expand All @@ -495,7 +498,7 @@ void ScrollClass::Scroll_Edge(Point2D const & point)
** Increase the scroll rate if the mouse button is held down.
*/
if (Keyboard->Down(KN_RMOUSE)) {
rate = std::clamp(rate+1, 4, (int)(sizeof(_rate)/sizeof(_rate[0]))-1);
rate = std::clamp(rate+1, 4, (int)(sizeof(_ScrollRateTable)/sizeof(_ScrollRateTable[0]))-1);
}

/*
Expand All @@ -512,7 +515,7 @@ void ScrollClass::Scroll_Edge(Point2D const & point)
} else {
Override_Mouse_Shape((MouseType)(MOUSE_N+control), false);

int step = int(_rate[rate] * Rule->ScrollMultiplier);
int step = int(_ScrollRateTable[rate] * Rule->ScrollMultiplier);
double scaled = step * _ScrollFraction + _EdgeScrollRemainder;
distance = int(scaled);
_EdgeScrollRemainder = scaled - distance;
Expand Down Expand Up @@ -581,6 +584,23 @@ void ScrollClass::Scroll_AI(void)
}


/// <summary>
/// Gives the distance a keyboard scroll command should move the map this poll, at the sustained
/// top speed edge scrolling reaches once its inertia ramp is fully wound up for the current
/// Options.ScrollRate. Call once per poll; it paces itself off Scroll_AI's timing.
/// </summary>
/// <returns>int; The distance to scroll this poll, in leptons.</returns>
int ScrollClass::Get_Keyboard_Scroll_Distance(void)
{
int rate = Options.ScrollRate+1;
int step = int(_ScrollRateTable[rate] * Rule->ScrollMultiplier);
double scaled = step * _ScrollFraction + _KeyScrollRemainder;
int distance = int(scaled);
_KeyScrollRemainder = scaled - distance;
return(distance);
}


/// <summary>
/// Is the tactical map currently in motion?
/// This routine is used to hold off work that would fight with a scroll already under way. A
Expand Down
2 changes: 2 additions & 0 deletions code/scroll.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ class ScrollClass: public TabClass

void Set_Scroll_Coasting_Allowed(bool coasting) { IsCoastScrollAllowed = coasting; }

int Get_Keyboard_Scroll_Distance(void);

virtual void AI(KeyNumType &input, Point2D const & xy) override;
virtual void Init_IO(void) override {/*Counter = 0;*/BASECLASS::Init_IO();};
virtual bool Is_Scrolling(void) const override;
Expand Down
26 changes: 26 additions & 0 deletions manual/changes/keyboard-scroll-continuous.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: Continuous keyboard map scrolling
category: feature
release: 0.2.0
targets:
- type: command
id: ScrollNorth
effect: changed
- type: command
id: ScrollSouth
effect: changed
- type: command
id: ScrollEast
effect: changed
- type: command
id: ScrollWest
effect: changed
credit:
- torradmin
---

Binding "Scroll East/West/North/South" to a key now scrolls the map continuously while the key
is held, the way edge scrolling and mouse-drag scrolling already do; before, each press moved
the map a single fixed step and repeating it required releasing and pressing the key again,
because Windows key-repeat events never reach the game's keyboard buffer. Held keyboard scroll
ramps up to the same top speed as edge scrolling and honors the "Scroll speed" option.
30 changes: 30 additions & 0 deletions manual/changes/keyboard-scroll-diagonals-and-modifiers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
title: Fix diagonal keyboard scrolling and modifier-bound scroll keys
category: fix
release: 0.2.0
targets:
- type: command
id: ScrollNorthEast
effect: changed
- type: command
id: ScrollSouthEast
effect: changed
- type: command
id: ScrollSouthWest
effect: changed
- type: command
id: ScrollNorthWest
effect: changed
credit:
- torradmin
---

Binding "Scroll Northeast/Southeast/Southwest/Northwest" to a key now scrolls the map
continuously while the key is held and honors the "Scroll speed" option, matching the cardinal
scroll commands and edge scrolling; before, each diagonal command moved the map a single fixed
step regardless of how long the key was held.

A repeatable scroll command bound with a Shift, Ctrl, or Alt modifier (for example Shift+Up) no
longer keeps scrolling once the modifier is released, and no longer fires alongside an unrelated
command bound to the same base key with a different modifier. The per-frame poll that re-triggers
held scroll keys was checking only the base key, ignoring any modifier the binding required.