Skip to content
Draft
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
9 changes: 7 additions & 2 deletions GeneralsMD/Code/GameEngine/Include/GameClient/Keyboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ struct KeyboardIO
UnsignedByte status; // StatusType, above
UnsignedShort state; // KEY_STATE_* in KeyDefs.h
UnsignedInt keyDownTimeMsec; // real-time in milliseconds when key went down
UnsignedInt keyRepeatTimeMsecOffset; // shorten key repeat delay by offset

};

Expand All @@ -88,8 +89,12 @@ class Keyboard : public SubsystemInterface

enum
{
KEY_REPEAT_DELAY_MSEC = 333, // 10 frames at 30 FPS
KEY_REPEAT_INTERVAL_MSEC = 67 // ~2 frames at 30 FPS
// TheSuperHackers @info Holding a button down requires 200 msec to register as a repeated key for the first time.
// After that the delay gets shorter and shorter, between 140 (200 - 60) and 15 (200 - 185) msec, with a decrease step of 15 msec.
KEY_REPEAT_DELAY_MSEC = 200,
KEY_REPEAT_OFFSET_DELAY_MIN_MSEC = 60,
KEY_REPEAT_OFFSET_DELAY_MAX_MSEC = 185,
KEY_REPEAT_OFFSET_DELAY_STEP_MSEC = 15
};

public:
Expand Down
4 changes: 2 additions & 2 deletions GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,8 @@ void GameClient::init( void )

// since we only allocate one of each, don't bother pooling 'em
m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") WindowTranslator, 10 );
m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") MetaEventTranslator, 20 );
m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") HotKeyTranslator, 25 );
m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") HotKeyTranslator, 20 );
m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") MetaEventTranslator, 25 );
m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") PlaceEventTranslator, 30 );
m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") GUICommandTranslator, 40 );
m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") SelectionTranslator, 50 );
Expand Down
66 changes: 33 additions & 33 deletions GeneralsMD/Code/GameEngine/Source/GameClient/Input/Keyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,59 +204,59 @@ void Keyboard::updateKeys( void )
//-------------------------------------------------------------------------------------------------
Bool Keyboard::checkKeyRepeat( void )
{
Bool retVal = FALSE;
Int index = 0;
Int key;
// @todo we shouldn't think about repeating any keys while we don't have the focus

/** @todo we shouldn't think about repeating any keys while we
don't have the focus */
// if( currentFocus == FOCUS_OUT )
// return FALSE;
Bool retVal = FALSE;
size_t index = 0;

// Find end of real keys for this frame
while( m_keys[ index ].key != KEY_NONE )
index++;

// Scan Keyboard status array for first key down
// long enough to repeat
for( key = 0; key < ARRAY_SIZE(m_keyStatus); key++ )
for (size_t i = 0; i < ARRAY_SIZE(m_keys) && m_keys[i].key != KEY_NONE; ++i)
{
++index;
}

// Scan keyboard status array for first key down long enough to repeat
for( size_t key = 0; key < ARRAY_SIZE(m_keyStatus); ++key )
{
if( BitIsSet( m_keyStatus[ key ].state, KEY_STATE_DOWN ) )
{

const UnsignedInt now = timeGetTime();
const UnsignedInt keyDownTime = m_keyStatus[ key ].keyDownTimeMsec;
const UnsignedInt elapsedMsec = now - keyDownTime;

if( elapsedMsec > Keyboard::KEY_REPEAT_DELAY_MSEC )
if( m_keyStatus[ key ].keyDownTimeMsec > 0 && now - m_keyStatus[ key ].keyDownTimeMsec > Keyboard::KEY_REPEAT_DELAY_MSEC )
{
// Add key to this frame
m_keys[ index ].key = (UnsignedByte)key;
m_keys[ index ].state = KEY_STATE_DOWN | KEY_STATE_AUTOREPEAT; // note: not a bitset; this is an assignment
m_keys[ index ].status = KeyboardIO::STATUS_UNUSED;

// Set End Flag
m_keys[ ++index ].key = KEY_NONE;
if (index < ARRAY_SIZE(m_keys) - 1)
{
// Add key to this frame
m_keys[index].key = (UnsignedByte)key;
m_keys[index].state = KEY_STATE_DOWN | KEY_STATE_AUTOREPEAT;
m_keys[index].status = KeyboardIO::STATUS_UNUSED;
++index;

// Set end flag
m_keys[index].key = KEY_NONE;
}

// Set all keys as new to prevent multiple keys repeating
for( index = 0; index< NUM_KEYS; index++ )
m_keyStatus[ index ].keyDownTimeMsec = now;
// Decrease the delay between registered key strokes the longer a key is held down
const UnsignedInt keyRepeatTimeMsecOffset = clamp(
static_cast<UnsignedInt>(KEY_REPEAT_OFFSET_DELAY_STEP_MSEC) + m_keyStatus[ key ].keyRepeatTimeMsecOffset,
static_cast<UnsignedInt>(KEY_REPEAT_OFFSET_DELAY_MIN_MSEC),
static_cast<UnsignedInt>(KEY_REPEAT_OFFSET_DELAY_MAX_MSEC));

// Set repeated key so it will repeat again after the interval
m_keyStatus[ key ].keyDownTimeMsec = now - (Keyboard::KEY_REPEAT_DELAY_MSEC + Keyboard::KEY_REPEAT_INTERVAL_MSEC);
m_keyStatus[ key ].keyRepeatTimeMsecOffset = keyRepeatTimeMsecOffset;
m_keyStatus[ key ].keyDownTimeMsec = now - m_keyStatus[ key ].keyRepeatTimeMsecOffset;

retVal = TRUE;
break; // exit for key

}

}

else
{
m_keyStatus[ key ].keyDownTimeMsec = 0;
m_keyStatus[ key ].keyRepeatTimeMsecOffset = 0;
}
}

return retVal;

}

//-------------------------------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,44 +69,33 @@
//-----------------------------------------------------------------------------
GameMessageDisposition HotKeyTranslator::translateGameMessage(const GameMessage *msg)
{
GameMessageDisposition disp = KEEP_MESSAGE;
GameMessage::Type t = msg->getType();

if ( t == GameMessage::MSG_RAW_KEY_UP)
switch (msg->getType())
{
case GameMessage::MSG_RAW_KEY_DOWN:
if ((msg->getArgument(1)->integer & KEY_STATE_AUTOREPEAT) == 0)
return KEEP_MESSAGE;

//char key = msg->getArgument(0)->integer;
Int keyState = msg->getArgument(1)->integer;

// for our purposes here, we don't care to distinguish between right and left keys,
// so just fudge a little to simplify things.
Int newModState = 0;
FALLTHROUGH;
case GameMessage::MSG_RAW_KEY_UP:
if (msg->getArgument(1)->integer & (KEY_STATE_CONTROL | KEY_STATE_SHIFT | KEY_STATE_ALT))
return KEEP_MESSAGE;

if( keyState & KEY_STATE_CONTROL )
if (TheHotKeyManager)
{
newModState |= CTRL;
WideChar key = TheKeyboard->getPrintableKey((KeyDefType)msg->getArgument(0)->integer, 0);
UnicodeString uKey;
uKey.concat(key);
AsciiString aKey;
aKey.translate(uKey);

if (TheHotKeyManager->executeHotKey(aKey))
return DESTROY_MESSAGE;
}

if( keyState & KEY_STATE_SHIFT )
{
newModState |= SHIFT;
}

if( keyState & KEY_STATE_ALT )
{
newModState |= ALT;
}
if(newModState != 0)
return disp;
WideChar key = TheKeyboard->getPrintableKey((KeyDefType)msg->getArgument(0)->integer, 0);
UnicodeString uKey;
uKey.concat(key);
AsciiString aKey;
aKey.translate(uKey);
if(TheHotKeyManager && TheHotKeyManager->executeHotKey(aKey))
disp = DESTROY_MESSAGE;
return KEEP_MESSAGE;
default:
return KEEP_MESSAGE;
}
return disp;
}

//-----------------------------------------------------------------------------
Expand Down
Loading