diff options
Diffstat (limited to 'vguimatsurface/Input.cpp')
| -rw-r--r-- | vguimatsurface/Input.cpp | 524 |
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; +} + + + |