summaryrefslogtreecommitdiff
path: root/vguimatsurface/Input.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /vguimatsurface/Input.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'vguimatsurface/Input.cpp')
-rw-r--r--vguimatsurface/Input.cpp524
1 files changed, 524 insertions, 0 deletions
diff --git a/vguimatsurface/Input.cpp b/vguimatsurface/Input.cpp
new file mode 100644
index 0000000..cafacce
--- /dev/null
+++ b/vguimatsurface/Input.cpp
@@ -0,0 +1,524 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Implementation of the VGUI ISurface interface using the
+// material system to implement it
+//
+//===========================================================================//
+
+#if defined( WIN32 ) && !defined( _X360 )
+#include <windows.h>
+#include <zmouse.h>
+#endif
+#include "inputsystem/iinputsystem.h"
+#include "tier2/tier2.h"
+#include "Input.h"
+#include "vguimatsurface.h"
+#include "../vgui2/src/VPanel.h"
+#include <vgui/KeyCode.h>
+#include <vgui/MouseCode.h>
+#include <vgui/IVGui.h>
+#include <vgui/IPanel.h>
+#include <vgui/ISurface.h>
+#include <vgui/IClientPanel.h>
+#include "inputsystem/ButtonCode.h"
+#include "Cursor.h"
+#include "tier0/dbg.h"
+#include "../vgui2/src/vgui_key_translation.h"
+#include <vgui/IInputInternal.h>
+#include "tier0/icommandline.h"
+#ifdef _X360
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Vgui input events
+//-----------------------------------------------------------------------------
+enum VguiInputEventType_t
+{
+ IE_Close = IE_FirstVguiEvent,
+ IE_LocateMouseClick,
+ IE_SetCursor,
+ IE_KeyTyped,
+ IE_KeyCodeTyped,
+ IE_InputLanguageChanged,
+ IE_IMESetWindow,
+ IE_IMEStartComposition,
+ IE_IMEComposition,
+ IE_IMEEndComposition,
+ IE_IMEShowCandidates,
+ IE_IMEChangeCandidates,
+ IE_IMECloseCandidates,
+ IE_IMERecomputeModes,
+};
+
+void InitInput()
+{
+ EnableInput( true );
+}
+
+
+static bool s_bInputEnabled = true;
+#ifdef WIN32
+//-----------------------------------------------------------------------------
+// Translates actual keys into VGUI ids
+//-----------------------------------------------------------------------------
+static WNDPROC s_ChainedWindowProc = NULL;
+extern HWND thisWindow;
+
+
+//-----------------------------------------------------------------------------
+// Initializes the input system
+//-----------------------------------------------------------------------------
+
+static bool s_bIMEComposing = false;
+static HWND s_hLastHWnd = 0;
+
+
+//-----------------------------------------------------------------------------
+// Handles input messages
+//-----------------------------------------------------------------------------
+static LRESULT CALLBACK MatSurfaceWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ if ( !s_bInputEnabled )
+ goto chainWndProc;
+
+ InputEvent_t event;
+ memset( &event, 0, sizeof(event) );
+ event.m_nTick = g_pInputSystem->GetPollTick();
+
+ if ( hwnd != s_hLastHWnd )
+ {
+ s_hLastHWnd = hwnd;
+ event.m_nType = IE_IMESetWindow;
+ event.m_nData = (int)s_hLastHWnd;
+ g_pInputSystem->PostUserEvent( event );
+ }
+
+ switch(uMsg)
+ {
+ case WM_QUIT:
+ // According to windows docs, WM_QUIT should never be passed to wndprocs
+ Assert( 0 );
+ break;
+
+ case WM_CLOSE:
+ // Handle close messages
+ {
+ LONG_PTR wndProc = GetWindowLongPtrW( hwnd, GWLP_WNDPROC );
+ if ( wndProc == (LONG_PTR)MatSurfaceWindowProc )
+ {
+ event.m_nType = IE_Close;
+ g_pInputSystem->PostUserEvent( event );
+ }
+ }
+ return 0;
+
+ // All mouse messages need to mark where the click occurred before chaining down
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case MS_WM_XBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_MBUTTONUP:
+ case MS_WM_XBUTTONUP:
+ case WM_LBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case MS_WM_XBUTTONDBLCLK:
+ event.m_nType = IE_LocateMouseClick;
+ event.m_nData = (short)LOWORD(lParam);
+ event.m_nData2 = (short)HIWORD(lParam);
+ g_pInputSystem->PostUserEvent( event );
+ break;
+
+ case WM_SETCURSOR:
+ event.m_nType = IE_SetCursor;
+ g_pInputSystem->PostUserEvent( event );
+ break;
+
+ case WM_XCONTROLLER_KEY:
+ if ( IsX360() )
+ {
+ // First have to insert the edge case event
+ int nRetVal = 0;
+ if ( s_ChainedWindowProc )
+ {
+ nRetVal = CallWindowProcW( s_ChainedWindowProc, hwnd, uMsg, wParam, lParam );
+ }
+
+ // xboxissue - as yet HL2 input hasn't been made aware of analog inputs or ports
+ // so just digital step on the sample range
+ int sample = LOWORD( lParam );
+ if ( sample )
+ {
+ event.m_nType = IE_KeyCodeTyped;
+ event.m_nData = (vgui::KeyCode)wParam;
+ g_pInputSystem->PostUserEvent( event );
+ }
+ }
+ break;
+
+ // Need to deal with key repeat for keydown since inputsystem doesn't
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ {
+ // First have to insert the edge case event
+ int nRetVal = 0;
+ if ( s_ChainedWindowProc )
+ {
+ nRetVal = CallWindowProcW( s_ChainedWindowProc, hwnd, uMsg, wParam, lParam );
+ }
+
+ int nKeyRepeat = LOWORD( lParam );
+ for ( int i = 0; i < nKeyRepeat; ++i )
+ {
+ event.m_nType = IE_KeyCodeTyped;
+ event.m_nData = KeyCode_VirtualKeyToVGUI( wParam );
+ g_pInputSystem->PostUserEvent( event );
+ }
+
+ return nRetVal;
+ }
+
+ case WM_SYSCHAR:
+ case WM_CHAR:
+ if ( !s_bIMEComposing )
+ {
+ event.m_nType = IE_KeyTyped;
+ event.m_nData = (int)wParam;
+ g_pInputSystem->PostUserEvent( event );
+ }
+ break;
+
+ case WM_INPUTLANGCHANGE:
+ event.m_nType = IE_InputLanguageChanged;
+ g_pInputSystem->PostUserEvent( event );
+ break;
+
+ case WM_IME_STARTCOMPOSITION:
+ s_bIMEComposing = true;
+ event.m_nType = IE_IMEStartComposition;
+ g_pInputSystem->PostUserEvent( event );
+ return TRUE;
+
+ case WM_IME_COMPOSITION:
+ event.m_nType = IE_IMEComposition;
+ event.m_nData = (int)lParam;
+ g_pInputSystem->PostUserEvent( event );
+ return TRUE;
+
+ case WM_IME_ENDCOMPOSITION:
+ s_bIMEComposing = false;
+ event.m_nType = IE_IMEEndComposition;
+ g_pInputSystem->PostUserEvent( event );
+ return TRUE;
+
+ case WM_IME_NOTIFY:
+ {
+ switch (wParam)
+ {
+ default:
+ break;
+
+ case 14: // Chinese Traditional IMN_PRIVATE...
+ break;
+
+ case IMN_OPENCANDIDATE:
+ event.m_nType = IE_IMEShowCandidates;
+ g_pInputSystem->PostUserEvent( event );
+ return 1;
+
+ case IMN_CHANGECANDIDATE:
+ event.m_nType = IE_IMEChangeCandidates;
+ g_pInputSystem->PostUserEvent( event );
+ return 0;
+
+ case IMN_CLOSECANDIDATE:
+ event.m_nType = IE_IMECloseCandidates;
+ g_pInputSystem->PostUserEvent( event );
+ break;
+
+ // To detect the change of IME mode, or the toggling of Japanese IME
+ case IMN_SETCONVERSIONMODE:
+ case IMN_SETSENTENCEMODE:
+ case IMN_SETOPENSTATUS:
+ event.m_nType = IE_IMERecomputeModes;
+ g_pInputSystem->PostUserEvent( event );
+ if ( wParam == IMN_SETOPENSTATUS )
+ return 0;
+ break;
+
+ case IMN_CLOSESTATUSWINDOW:
+ case IMN_GUIDELINE:
+ case IMN_OPENSTATUSWINDOW:
+ case IMN_SETCANDIDATEPOS:
+ case IMN_SETCOMPOSITIONFONT:
+ case IMN_SETCOMPOSITIONWINDOW:
+ case IMN_SETSTATUSWINDOWPOS:
+ break;
+ }
+ }
+
+ case WM_IME_SETCONTEXT:
+ // We draw all IME windows ourselves
+ lParam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
+ lParam &= ~ISC_SHOWUIGUIDELINE;
+ lParam &= ~ISC_SHOWUIALLCANDIDATEWINDOW;
+ break;
+
+ case WM_IME_CHAR:
+ // We need to process this message so that the IME doesn't double convert the unicode IME characters into garbage characters and post
+ // them to our window... (get ? marks after text entry ).
+ return 0;
+ }
+
+chainWndProc:
+ if ( s_ChainedWindowProc )
+ return CallWindowProcW( s_ChainedWindowProc, hwnd, uMsg, wParam, lParam );
+
+ // This means the application is driving the messages (calling our window procedure manually)
+ // rather than us hooking their window procedure. The engine needs to do this in order for VCR
+ // mode to play back properly.
+ return 0;
+}
+
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Enables/disables input (enabled by default)
+//-----------------------------------------------------------------------------
+void EnableInput( bool bEnable )
+{
+#if 0 // #ifdef BENCHMARK
+ s_bInputEnabled = false;
+#else
+ s_bInputEnabled = bEnable;
+#endif
+}
+
+
+#ifdef WIN32
+//-----------------------------------------------------------------------------
+// Hooks input listening up to a window
+//-----------------------------------------------------------------------------
+void InputAttachToWindow(void *hwnd)
+{
+#if !defined( USE_SDL )
+ s_ChainedWindowProc = (WNDPROC)GetWindowLongPtrW( (HWND)hwnd, GWLP_WNDPROC );
+ SetWindowLongPtrW( (HWND)hwnd, GWLP_WNDPROC, (LONG_PTR)MatSurfaceWindowProc );
+#endif
+}
+
+void InputDetachFromWindow(void *hwnd)
+{
+ if (!hwnd)
+ return;
+ if ( s_ChainedWindowProc )
+ {
+ SetWindowLongPtrW( (HWND)hwnd, GWLP_WNDPROC, (LONG_PTR) s_ChainedWindowProc );
+ s_ChainedWindowProc = NULL;
+ }
+}
+#else
+void InputAttachToWindow(void *hwnd)
+{
+#if !defined( OSX ) && !defined( LINUX )
+ if ( hwnd && !HushAsserts() )
+ {
+ // under OSX we use the Cocoa mgr to route events rather than hooking winprocs
+ // and under Linux we use SDL
+ Assert( !"Implement me" );
+ }
+#endif
+}
+
+void InputDetachFromWindow(void *hwnd)
+{
+#if !defined( OSX ) && !defined( LINUX )
+ if ( hwnd && !HushAsserts() )
+ {
+ // under OSX we use the Cocoa mgr to route events rather than hooking winprocs
+ // and under Linux we use SDL
+ Assert( !"Implement me" );
+ }
+#endif
+}
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Converts an input system button code to a vgui key code
+// FIXME: Remove notion of vgui::KeyCode + vgui::MouseCode altogether
+//-----------------------------------------------------------------------------
+static vgui::KeyCode ButtonCodeToKeyCode( ButtonCode_t buttonCode )
+{
+ return ( vgui::KeyCode )buttonCode;
+}
+
+static vgui::MouseCode ButtonCodeToMouseCode( ButtonCode_t buttonCode )
+{
+ return ( vgui::MouseCode )buttonCode;
+}
+
+
+//-----------------------------------------------------------------------------
+// Handles an input event, returns true if the event should be filtered
+// from the rest of the game
+//-----------------------------------------------------------------------------
+bool InputHandleInputEvent( const InputEvent_t &event )
+{
+ switch( event.m_nType )
+ {
+ case IE_ButtonPressed:
+ {
+ // NOTE: data2 is the virtual key code (data1 contains the scan-code one)
+ ButtonCode_t code = (ButtonCode_t)event.m_nData2;
+ if ( IsKeyCode( code ) || IsJoystickCode( code ) )
+ {
+ vgui::KeyCode keyCode = ButtonCodeToKeyCode( code );
+ return g_pIInput->InternalKeyCodePressed( keyCode );
+ }
+
+ if ( IsJoystickCode( code ) )
+ {
+ vgui::KeyCode keyCode = ButtonCodeToKeyCode( code );
+ return g_pIInput->InternalKeyCodePressed( keyCode );
+ }
+
+ if ( IsMouseCode( code ) )
+ {
+ vgui::MouseCode mouseCode = ButtonCodeToMouseCode( code );
+ return g_pIInput->InternalMousePressed( mouseCode );
+ }
+ }
+ break;
+
+ case IE_ButtonReleased:
+ {
+ // NOTE: data2 is the virtual key code (data1 contains the scan-code one)
+ ButtonCode_t code = (ButtonCode_t)event.m_nData2;
+ if ( IsKeyCode( code ) || IsJoystickCode( code ) )
+ {
+ vgui::KeyCode keyCode = ButtonCodeToKeyCode( code );
+ return g_pIInput->InternalKeyCodeReleased( keyCode );
+ }
+
+ if ( IsJoystickCode( code ) )
+ {
+ vgui::KeyCode keyCode = ButtonCodeToKeyCode( code );
+ return g_pIInput->InternalKeyCodeReleased( keyCode );
+ }
+
+ if ( IsMouseCode( code ) )
+ {
+ vgui::MouseCode mouseCode = ButtonCodeToMouseCode( code );
+ return g_pIInput->InternalMouseReleased( mouseCode );
+ }
+ }
+ break;
+
+ case IE_ButtonDoubleClicked:
+ {
+ // NOTE: data2 is the virtual key code (data1 contains the scan-code one)
+ ButtonCode_t code = (ButtonCode_t)event.m_nData2;
+ if ( IsMouseCode( code ) )
+ {
+ vgui::MouseCode mouseCode = ButtonCodeToMouseCode( code );
+ return g_pIInput->InternalMouseDoublePressed( mouseCode );
+ }
+ }
+ break;
+
+ case IE_AnalogValueChanged:
+ {
+ if ( event.m_nData == MOUSE_WHEEL )
+ return g_pIInput->InternalMouseWheeled( event.m_nData3 );
+ if ( event.m_nData == MOUSE_XY )
+ return g_pIInput->InternalCursorMoved( event.m_nData2, event.m_nData3 );
+ }
+ break;
+
+ case IE_KeyCodeTyped:
+ {
+ vgui::KeyCode code = (vgui::KeyCode)event.m_nData;
+ g_pIInput->InternalKeyCodeTyped( code );
+ }
+ return true;
+
+ case IE_KeyTyped:
+ {
+ vgui::KeyCode code = (vgui::KeyCode)event.m_nData;
+ g_pIInput->InternalKeyTyped( code );
+ }
+ return true;
+
+ case IE_Quit:
+ g_pVGui->Stop();
+#if defined( USE_SDL )
+ return false; // also let higher layers consume it
+#else
+ return true;
+#endif
+
+ case IE_Close:
+ // FIXME: Change this so we don't stop until 'save' occurs, etc.
+ g_pVGui->Stop();
+ return true;
+
+ case IE_SetCursor:
+ ActivateCurrentCursor();
+ return true;
+
+ case IE_IMESetWindow:
+ g_pIInput->SetIMEWindow( (void *)event.m_nData );
+ return true;
+
+ case IE_LocateMouseClick:
+ g_pIInput->InternalCursorMoved( event.m_nData, event.m_nData2 );
+ return true;
+
+ case IE_InputLanguageChanged:
+ g_pIInput->OnInputLanguageChanged();
+ return true;
+
+ case IE_IMEStartComposition:
+ g_pIInput->OnIMEStartComposition();
+ return true;
+
+ case IE_IMEComposition:
+ g_pIInput->OnIMEComposition( event.m_nData );
+ return true;
+
+ case IE_IMEEndComposition:
+ g_pIInput->OnIMEEndComposition();
+ return true;
+
+ case IE_IMEShowCandidates:
+ g_pIInput->OnIMEShowCandidates();
+ return true;
+
+ case IE_IMEChangeCandidates:
+ g_pIInput->OnIMEChangeCandidates();
+ return true;
+
+ case IE_IMECloseCandidates:
+ g_pIInput->OnIMECloseCandidates();
+ return true;
+
+ case IE_IMERecomputeModes:
+ g_pIInput->OnIMERecomputeModes();
+ return true;
+ }
+
+ return false;
+}
+
+
+