diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/Keyboard.h b/GeneralsMD/Code/GameEngine/Include/GameClient/Keyboard.h index 527af260552..a0eb0b42ca8 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/Keyboard.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/Keyboard.h @@ -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 }; @@ -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: diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index 1c6c5e8e9d1..086ae7ae7f2 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -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 ); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Input/Keyboard.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Input/Keyboard.cpp index a4e087fb752..22cdfab05b8 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Input/Keyboard.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Input/Keyboard.cpp @@ -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(KEY_REPEAT_OFFSET_DELAY_STEP_MSEC) + m_keyStatus[ key ].keyRepeatTimeMsecOffset, + static_cast(KEY_REPEAT_OFFSET_DELAY_MIN_MSEC), + static_cast(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; - } //------------------------------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/HotKey.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/HotKey.cpp index 651512e4436..cd607a55d41 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/HotKey.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/HotKey.cpp @@ -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; } //-----------------------------------------------------------------------------