From 136b5e2c700680d3aee05d4f2827342ae3de37a5 Mon Sep 17 00:00:00 2001 From: Ben Lankamp Date: Tue, 23 Jun 2020 23:40:53 +0200 Subject: [PATCH] Start with EventQueue --- code/CMakeLists.txt | 2 + code/REDALERT/EXTERNS.H | 1 + code/REDALERT/FUNCTION.H | 1 + code/REDALERT/GADGET.CPP | 91 ++++----------------- code/REDALERT/GLOBALS.CPP | 1 + code/REDALERT/KEY.CPP | 7 +- code/REDALERT/KEY.H | 1 + code/REDALERT/SCENARIO.CPP | 2 + code/REDALERT/io/EventQueue.cpp | 140 ++++++++++++++++++++++++++++++++ code/REDALERT/io/EventQueue.h | 92 +++++++++++++++++++++ code/REDALERT/io/UserInput.cpp | 73 ++++++++++++++++- code/REDALERT/io/UserInput.h | 43 ++++++---- 12 files changed, 353 insertions(+), 101 deletions(-) create mode 100644 code/REDALERT/io/EventQueue.cpp create mode 100644 code/REDALERT/io/EventQueue.h diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index ee219fd..e470dad 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -11,6 +11,8 @@ set(CMAKE_VERBOSE_MAKEFILE ON) set(src_io ./REDALERT/io/UserInput.cpp ./REDALERT/io/UserInput.h + ./REDALERT/io/EventQueue.h + ./REDALERT/io/EventQueue.cpp ) set(src_win32lib diff --git a/code/REDALERT/EXTERNS.H b/code/REDALERT/EXTERNS.H index 4b91e44..2a26b6b 100644 --- a/code/REDALERT/EXTERNS.H +++ b/code/REDALERT/EXTERNS.H @@ -161,6 +161,7 @@ extern PKey SlowKey; extern RulesClass Rule; extern KeyboardClass * Keyboard; extern UserInputClass UserInput; +extern EventQueueClass EventQueue; extern RandomStraw CryptRandom; extern RandomClass NonCriticalRandomNumber; extern CarryoverClass * Carryover; diff --git a/code/REDALERT/FUNCTION.H b/code/REDALERT/FUNCTION.H index b226903..e00d0d6 100644 --- a/code/REDALERT/FUNCTION.H +++ b/code/REDALERT/FUNCTION.H @@ -201,6 +201,7 @@ struct NoInitClass { #include "key.h" #include "io/UserInput.h" +#include "io/EventQueue.h" #include #include "mpu.h" diff --git a/code/REDALERT/GADGET.CPP b/code/REDALERT/GADGET.CPP index adfaabd..eb2ce84 100644 --- a/code/REDALERT/GADGET.CPP +++ b/code/REDALERT/GADGET.CPP @@ -471,7 +471,9 @@ void GadgetClass::Draw_All(bool forced) *=========================================================================*/ KeyNumType GadgetClass::Input(void) { - KeyNumType key; + EventMessage* eventMessage = NULL; + KeyNumType key = KN_NONE; + int flags = 0; int forced = false; /* @@ -488,78 +490,13 @@ KeyNumType GadgetClass::Input(void) /* ** Fetch any pending keyboard input. */ - key = Keyboard->Check(); - if (key != 0) { - key = Keyboard->Get(); + UserInput.Process_Input(); // key, flags); + + if ( EventQueue.Check() ) { + eventMessage = EventQueue.Get(); + eventMessage->Key_Flags( key, flags ); } - /* - ** For mouse button clicks, the mouse position is actually held in the MouseQ... - ** globals rather than their normal Mouse... globals. This is because we need to - ** know the position of the mouse at the exact instant when the click occurred - ** rather the the mouse position at the time we get around to this function. - */ -// jmarshall - int flags = g_globalKeyFlags; - UserInput.Process_Input( g_globalKeyNumType, flags ); - -// jmarshall end - - /* - ** Set the mouse button state flags. These will be passed to the individual - ** buttons so that they can determine what action to perform (if any). - */ - //if (key) { - // if (key == KN_LMOUSE) { - // flags |= LEFTPRESS; - // } - // if (key == KN_RMOUSE) { - // flags |= RIGHTPRESS; - // } - // if (key == (KN_LMOUSE | KN_RLSE_BIT)) { - // flags |= LEFTRELEASE; - // } - // if (key == (KN_RMOUSE | KN_RLSE_BIT)) { - // flags |= RIGHTRELEASE; - // } - //} - - /* - ** If the mouse wasn't responsible for this key code, then it must be from - ** the keyboard. Flag this fact. - */ - if (key && !flags) { - flags |= KEYBOARD; - } - - /* - ** Mouse button up or down action is ignored if there is a keyboard event. This - ** allows keyboard events to fall through normally even if the mouse is over a - ** gadget that is flagged for LEFTUP or RIGHTUP. - */ -// jmarshall - //if (!key) { - // - // /* - // ** Check for the mouse being held down. We can't use the normal input system - // ** for this, so we must examine the actual current state of the mouse - // ** buttons. As a side note, if we determine that the mouse button isn't being - // ** held down, then we automatically know that it must be up -- set the flag - // ** accordingly. - // */ - // if (Keyboard->Down(KN_LMOUSE)) { - // flags |= LEFTHELD; - // } else { - // flags |= LEFTUP; - // } - // if (Keyboard->Down(KN_RMOUSE)) { - // flags |= RIGHTHELD; - // } else { - // flags |= RIGHTUP; - // } - //} -// jmarshall end - /* ** If "sticky" processing is active, then only process the stuck gadget. */ @@ -567,18 +504,21 @@ KeyNumType GadgetClass::Input(void) StuckOn->Draw_Me(false); GadgetClass * oldstuck = StuckOn; StuckOn->Clicked_On(key, flags, UserInput.Mouse.X, UserInput.Mouse.Y); - if (StuckOn) { + + if (StuckOn) + { StuckOn->Draw_Me(false); } else { oldstuck->Draw_Me(false); } - } else { - + } + else + { /* ** If there is a gadget that has the keyboard focus, then route all keyboard ** events to it. */ - if (Focused && (flags & KEYBOARD)) { + if ( Focused && eventMessage != NULL && eventMessage->EventType == EventMessageType::EVENT_KEYBOARD ) { Focused->Draw_Me(false); Focused->Clicked_On(key, flags, UserInput.Mouse.X, UserInput.Mouse.Y); if (Focused) { @@ -622,6 +562,7 @@ KeyNumType GadgetClass::Input(void) } } } + return(key); } diff --git a/code/REDALERT/GLOBALS.CPP b/code/REDALERT/GLOBALS.CPP index 2e9c522..83acebf 100644 --- a/code/REDALERT/GLOBALS.CPP +++ b/code/REDALERT/GLOBALS.CPP @@ -257,6 +257,7 @@ RulesClass Rule; ** user input class pointer. */ UserInputClass UserInput; +EventQueueClass EventQueue; /*************************************************************************** ** All keyboard input is routed through the object pointed to by this diff --git a/code/REDALERT/KEY.CPP b/code/REDALERT/KEY.CPP index 5424cc2..9ff74b4 100644 --- a/code/REDALERT/KEY.CPP +++ b/code/REDALERT/KEY.CPP @@ -103,12 +103,7 @@ unsigned short WWKeyboardClass::Buff_Get(void) while (!Check()) {} // wait for key in buffer unsigned short temp = Fetch_Element(); - /* - if (Is_Mouse_Key(temp)) { - MouseQX = Fetch_Element(); - MouseQY = Fetch_Element(); - } - */ + return(temp); } diff --git a/code/REDALERT/KEY.H b/code/REDALERT/KEY.H index 3a09594..194d86e 100644 --- a/code/REDALERT/KEY.H +++ b/code/REDALERT/KEY.H @@ -638,6 +638,7 @@ typedef enum KeyNumType { KN_ALT_BIT = WWKEY_ALT_BIT, KN_RLSE_BIT = WWKEY_RLS_BIT, KN_BUTTON = WWKEY_BTN_BIT, + KN_CAPSLOCK_BIT = WWKEY_SHIFT_BIT, } KeyNumType; diff --git a/code/REDALERT/SCENARIO.CPP b/code/REDALERT/SCENARIO.CPP index 79d37cd..f6943e9 100644 --- a/code/REDALERT/SCENARIO.CPP +++ b/code/REDALERT/SCENARIO.CPP @@ -1056,6 +1056,8 @@ void Do_Win(void) } Keyboard->Clear(); + + UserInput.Process_Input(); } Scen.CarryOverMoney = PlayerPtr->Credits; diff --git a/code/REDALERT/io/EventQueue.cpp b/code/REDALERT/io/EventQueue.cpp new file mode 100644 index 0000000..94919a1 --- /dev/null +++ b/code/REDALERT/io/EventQueue.cpp @@ -0,0 +1,140 @@ +#include "../FUNCTION.H" +#include "EventQueue.h" + +/* + Clears the event queue +*/ +void EventQueueClass::Clear() +{ + while (this->eventQueue.size() > 0) this->eventQueue.pop(); +} + +/* + Inserts a new KeyNumType event into the FIFO buffer. KeyNumType represents a key press or mouse button + Input: KeyNumType + optional flag bits for SHIFT/CTRL/etc. cast as unsigned short +*/ +void EventQueueClass::Put(EventMessage* input) +{ + this->eventQueue.push(input); +} + +/* + Check if the buffer contains an element +*/ +bool EventQueueClass::Check() const +{ + return !this->Is_Buffer_Empty(); +} + +/* + Get the first (unprocessed) element in the event queue +*/ +EventMessage* EventQueueClass::Get() +{ + // wait for buffer + while( !this->Check() ) { } + + EventMessage* returnVal = this->eventQueue.front(); + this->eventQueue.pop(); + + return returnVal; +} + +/* + Returns ASCII value of the key in the buffer +*/ +char EventQueueClass::Get_ASCII() +{ + // get the last key from the buffer + KeyboardEventMessage* keyMessage = dynamic_cast( this->Get() ); + unsigned short key = keyMessage->Key; + + // check if it is a keyboard + if (key == KN_LMOUSE || key == KN_RMOUSE) return 0x0; + + // convert to ascii + char ascii; + unsigned short key_raw = (UINT)(key & 0xFF); + + // find the SDL keycode + auto sdl_Key = sdl_keyMapping_reverse.find( (KeyNumType)key_raw ); + if (sdl_Key != sdl_keyMapping_reverse.end()) + { + // convert to ascii + ascii = SDL_GetKeyName( sdl_Key->first )[0]; + + // convert to uppercase + if (keyMessage->Shift || keyMessage->CapsLock) ascii = toupper(ascii); + } + + return 0x0; +} + +KeyboardEventMessage::KeyboardEventMessage(KeyNumType key, bool shift, bool alt, bool control, bool capsLock) { + this->EventType = EventMessageType::EVENT_KEYBOARD; + this->Key = key; + this->Shift = shift; + this->Alt = alt; + this->Control = control; + this->CapsLock = capsLock; + + this->Flags = 0; + if (this->Shift) this->Flags |= KN_SHIFT_BIT; + if (this->Alt) this->Flags |= KN_ALT_BIT; + if (this->Control) this->Flags |= KN_CTRL_BIT; +} + +void KeyboardEventMessage::Key_Flags(KeyNumType& key, int& flags) +{ + flags = this->Flags; + flags |= GadgetClass::KEYBOARD; + + key = (KeyNumType)this->Key; +} + +MouseEventMessage::MouseEventMessage(int x, int y, unsigned short button, UserInputClass::MouseButtonState buttonState) +{ + this->EventType = EventMessageType::EVENT_MOUSE; + this->x = x; + this->y = y; + + this->Button = button; + this->ButtonState = buttonState; + + this->Flags = 0; +} + +void MouseEventMessage::Key_Flags(KeyNumType& key, int& flags) +{ + key = (KeyNumType)this->Button; + + if (key == KN_LMOUSE) { + switch (this->ButtonState) + { + case UserInputClass::MouseButtonState::MOUSE_BUTTON_DOWN: + flags = GadgetClass::LEFTPRESS; + break; + case UserInputClass::MouseButtonState::MOUSE_BUTTON_RELEASE: + flags = GadgetClass::LEFTRELEASE; + break; + case UserInputClass::MouseButtonState::MOUSE_BUTTON_HOLD: + flags = GadgetClass::LEFTHELD; + break; + } + } + + if (key == KN_RMOUSE) { + switch (this->ButtonState) + { + case UserInputClass::MouseButtonState::MOUSE_BUTTON_DOWN: + flags = GadgetClass::RIGHTPRESS; + break; + case UserInputClass::MouseButtonState::MOUSE_BUTTON_RELEASE: + flags = GadgetClass::RIGHTRELEASE; + break; + case UserInputClass::MouseButtonState::MOUSE_BUTTON_HOLD: + flags = GadgetClass::RIGHTHELD; + break; + } + } +} \ No newline at end of file diff --git a/code/REDALERT/io/EventQueue.h b/code/REDALERT/io/EventQueue.h new file mode 100644 index 0000000..0767b4a --- /dev/null +++ b/code/REDALERT/io/EventQueue.h @@ -0,0 +1,92 @@ +#pragma once + +/* +* WWKeyboardClass::Buff_Get -- Lowlevel function to get a key from key buffer* +* WWKeyboardClass::Check -- Checks to see if a key is in the buffer* +* WWKeyboardClass::Down -- Checks to see if the specified key is being held down.* +* WWKeyboardClass::Fetch_Element -- Extract the next element in the keyboard buffer.* +* WWKeyboardClass::Get -- Logic to get a metakey from the buffer* +* WWKeyboardClass::Message_Handler -- Process a windows message as it relates to the keyboar* +* WWKeyboardClass::Peek_Element -- Fetches the next element in the keyboard buffer.* +* WWKeyboardClass::To_ASCII -- Convert the key value into an ASCII representation.* +* WWKeyboardClass::Available_Buffer_Room -- Fetch the quantity of free elements in the keybo* +* ----------------------------------------------*/ + +/** +* EVENT QUEUE class +* Supports pumping of event messages using a FIFO buffer. +*/ + +extern UserInputClass UserInput; + +/* + Event type definitions +*/ +typedef enum { + EVENT_KEYBOARD, + EVENT_MOUSE +} EventMessageType; + +/* + Event types +*/ +class EventMessage { + public: + EventMessageType EventType; + + virtual void Key_Flags(KeyNumType& key, int& flags) = 0; + virtual ~EventMessage() = default; +}; + +class KeyboardEventMessage : public EventMessage { + public: + KeyNumType Key; + bool Shift; + bool Alt; + bool Control; + bool CapsLock; + + // for cascading functions + unsigned short Flags; + + KeyboardEventMessage(KeyNumType key, bool shift = false, bool alt = false, bool control = false, bool capsLock = false); + virtual void Key_Flags(KeyNumType& key, int& flags); + + virtual ~KeyboardEventMessage() = default; +}; + +class MouseEventMessage : public EventMessage { + public: + int x; + int y; + unsigned short Button; + UserInputClass::MouseButtonState ButtonState; + + // for cascading functions + unsigned short Flags; + + MouseEventMessage(int x, int y, unsigned short button = KN_LMOUSE, UserInputClass::MouseButtonState buttonState = UserInputClass::MouseButtonState::MOUSE_BUTTON_DOWN); + virtual void Key_Flags(KeyNumType& key, int& flags); + + virtual ~MouseEventMessage() = default; +}; + +class EventQueueClass { + public: + int Get_Mouse_X() const { return UserInput.Mouse.X; } + int Get_Mouse_Y() const { return UserInput.Mouse.Y; } + + void Clear(); + void Put(EventMessage* input); + bool Check() const; + EventMessage* Get(); + char EventQueueClass::Get_ASCII(); + + private: + const int MaxCapacity = 100; + + std::queue eventQueue; + + bool Is_Buffer_Full() const { return this->eventQueue.size() == MaxCapacity; } + bool Is_Buffer_Empty() const { return this->eventQueue.size() == 0; } +}; diff --git a/code/REDALERT/io/UserInput.cpp b/code/REDALERT/io/UserInput.cpp index 7c602f3..818f64d 100644 --- a/code/REDALERT/io/UserInput.cpp +++ b/code/REDALERT/io/UserInput.cpp @@ -3,10 +3,51 @@ extern KeyboardClass * Keyboard; +std::map sdl_keyMapping_reverse; + +UserInputClass::UserInputClass() +{ + LastAction = InputAction::INPUT_ACTION_NONE; + + // generate reverse keymapping + for ( auto it = sdl_keyMapping.begin(); it != sdl_keyMapping.end(); it++ ) + { + sdl_keyMapping_reverse[it->second] = it->first; + } +} + +bool UserInputClass::KeyboardState::Key_Down(KeyNumType key) const +{ + auto sdl_Key = sdl_keyMapping_reverse.find( key ); + if ( sdl_Key != sdl_keyMapping_reverse.end() ) + { + const Uint8* keyState = SDL_GetKeyboardState(NULL); + return keyState[ sdl_Key->second ]; + } + return false; +} + +bool UserInputClass::MouseState::Mouse_Down(KeyNumType key) const +{ + // get mouse state, we are only interested in the buttons + const Uint32 MouseState = SDL_GetMouseState(NULL,NULL); + + switch (key) + { + case KN_LMOUSE: + return MouseState & SDL_BUTTON(SDL_BUTTON_LEFT); + break; + case KN_RMOUSE: + return MouseState & SDL_BUTTON(SDL_BUTTON_RIGHT); + break; + } +} + void UserInputClass::Process_Input(KeyNumType& key, int& flags) { bool leftMouseProcessed = false; - SDL_GetMouseState(&Mouse.X, &Mouse.Y); + + const Uint32 MouseState = SDL_GetMouseState(&Mouse.X, &Mouse.Y); Keyboard->MouseQX = Mouse.X; Keyboard->MouseQY = Mouse.Y; @@ -42,8 +83,12 @@ void UserInputClass::Process_Input(KeyNumType& key, int& flags) break; + /* Mouse is moving */ case SDL_MOUSEMOTION: - flags = GadgetClass::LEFTUP; + if ( !( MouseState & SDL_BUTTON(SDL_BUTTON_LEFT) ) ) + { + flags = GadgetClass::LEFTUP; + } break; case SDL_MOUSEBUTTONDOWN: @@ -52,15 +97,23 @@ void UserInputClass::Process_Input(KeyNumType& key, int& flags) key = KN_LMOUSE; flags = GadgetClass::LEFTPRESS; + + EventQueue.Put( new MouseEventMessage(Mouse.X, Mouse.Y, KN_LMOUSE) ); Keyboard->Put_Element(KN_LMOUSE); leftMouseProcessed = true; numFramesLMouse++; + + // after first left-mouse down, abort handling any other SDL events + // because game might first need to switch into rubber band mode + if (numFramesLMouse == 1) return; } else if (event.button.button == SDL_BUTTON_RIGHT) { Mouse.Button_Right == MouseButtonState::MOUSE_BUTTON_DOWN; + EventQueue.Put( new MouseEventMessage(Mouse.X, Mouse.Y, KN_RMOUSE) ); + Keyboard->Put_Element(KN_RMOUSE); key = KN_RMOUSE; @@ -74,12 +127,16 @@ void UserInputClass::Process_Input(KeyNumType& key, int& flags) if (event.button.button == SDL_BUTTON_LEFT) { Mouse.Button_Left == MouseButtonState::MOUSE_BUTTON_RELEASE; + EventQueue.Put(new MouseEventMessage(Mouse.X, Mouse.Y, KN_LMOUSE, UserInputClass::MouseButtonState::MOUSE_BUTTON_RELEASE)); + flags = GadgetClass::LEFTRELEASE; numFramesLMouse = 0; } else if (event.button.button == SDL_BUTTON_RIGHT) { Mouse.Button_Right == MouseButtonState::MOUSE_BUTTON_RELEASE; + EventQueue.Put( new MouseEventMessage(Mouse.X, Mouse.Y, KN_RMOUSE, UserInputClass::MouseButtonState::MOUSE_BUTTON_RELEASE) ); + flags = GadgetClass::RIGHTRELEASE; numFramesLMouse = 0; } @@ -114,12 +171,20 @@ void UserInputClass::Process_Input(KeyNumType& key, int& flags) keyFlags |= KN_CTRL_BIT; KeyB.Control = true; } + if (state[SDL_SCANCODE_CAPSLOCK]) { + keyFlags |= KN_CAPSLOCK_BIT; + KeyB.CapsLock = true; + } // handle match between SDL and internals (non-text keys) auto element = sdl_keyMapping.find((SDL_KeyCode)event.key.keysym.sym); if (element != sdl_keyMapping.end()) { - Keyboard->Put_Element(element->second | keyFlags); + //EventQueue.Put( element->second | keyFlags ); + EventQueue.Put( new KeyboardEventMessage( (KeyNumType)element->second, KeyB.Shift, KeyB.Alt, KeyB.Control, KeyB.CapsLock ) ); + + Keyboard->Put_Element( element->second | keyFlags); + KeyB.ASCII = element->second; } @@ -143,5 +208,7 @@ void UserInputClass::Process_Input(KeyNumType& key, int& flags) { Mouse.Button_Left == MouseButtonState::MOUSE_BUTTON_HOLD; flags = GadgetClass::LEFTHELD; + + EventQueue.Put(new MouseEventMessage(Mouse.X, Mouse.Y, KN_LMOUSE, UserInputClass::MouseButtonState::MOUSE_BUTTON_HOLD)); } } \ No newline at end of file diff --git a/code/REDALERT/io/UserInput.h b/code/REDALERT/io/UserInput.h index 2ef72f3..41f37c9 100644 --- a/code/REDALERT/io/UserInput.h +++ b/code/REDALERT/io/UserInput.h @@ -1,9 +1,9 @@ -#ifndef USERINPUT_H -#define USERINPUT_H +#pragma once #include #include #include +#include #include "examples/imgui_impl_sdl.h" @@ -87,6 +87,11 @@ std::map const sdl_keyMapping = { { SDLK_LEFT, KN_LEFT }, { SDLK_RIGHT, KN_RIGHT }, }; +extern std::map sdl_keyMapping_reverse; + +const int USERINPUT_SHIFT_BIT = 0x100; +const int USERINPUT_CTRL_BIT = 0x200; +const int USERINPUT_ALT_BIT = 0x400; class UserInputClass { @@ -104,24 +109,28 @@ class UserInputClass INPUT_ACTION_MOUSE, } InputAction; - void UserInputClass::Process_Input(KeyNumType& key = g_globalKeyNumType, int& flags = g_globalKeyFlags); + UserInputClass(); + void UserInputClass::Process_Input( KeyNumType& key = g_globalKeyNumType, int& flags = g_globalKeyFlags ); InputAction LastAction; class KeyboardState { - public: - SDL_KeyCode LastKey; - char ASCII; + public: + SDL_KeyCode LastKey; + char ASCII; - bool Shift; - bool Control; - bool Alt; + bool Shift; + bool Control; + bool Alt; + bool CapsLock; - void ResetState() { - this->Shift = false; - this->Control = false; - this->Alt = false; - } + bool Key_Down(KeyNumType key) const; + + void ResetState() { + this->Shift = false; + this->Control = false; + this->Alt = false; + } }; KeyboardState KeyB; @@ -135,6 +144,8 @@ class UserInputClass MouseButtonState Button_Middle; MouseButtonState Button_Right; + bool UserInputClass::MouseState::Mouse_Down(KeyNumType key) const; + void ResetState() { this->Button_Left = MouseButtonState::MOUSE_BUTTON_UP; this->Button_Middle = MouseButtonState::MOUSE_BUTTON_UP; @@ -145,6 +156,4 @@ class UserInputClass MouseState Mouse; private: int numFramesLMouse = 0; -}; - -#endif \ No newline at end of file +}; \ No newline at end of file