mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-05 04:48:19 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
371 lines
9.4 KiB
C#
371 lines
9.4 KiB
C#
using NativeEngine;
|
|
|
|
namespace Sandbox.Engine;
|
|
|
|
internal static partial class InputRouter
|
|
{
|
|
static RealTimeSince timeSinceWindowActive;
|
|
|
|
internal static void OnMouseButton( ButtonCode button, bool down, int ikeymods )
|
|
{
|
|
SetButtonState( button, down );
|
|
|
|
var mouse = Contexts.FirstOrDefault( x => x.MouseState != InputContext.InputState.Ignore );
|
|
|
|
// if this was likely the click that made the window active - and we're not in UI mode
|
|
// then ignore it.. because we don't want people shooting guns every time they re-activate
|
|
// the window
|
|
if ( down && timeSinceWindowActive < 0.1f )
|
|
{
|
|
if ( mouse is null || mouse.MouseState != InputContext.InputState.UI )
|
|
return;
|
|
}
|
|
|
|
if ( mouse is not null )
|
|
{
|
|
mouse.IN_Button( down, button, false, EngineToModifier( ikeymods ) );
|
|
}
|
|
|
|
//
|
|
// When a button is released, we send it to each context. These contexts may have
|
|
// the button as pressed. The release should be sent to them so they can clear it.
|
|
//
|
|
if ( !down )
|
|
{
|
|
foreach ( var context in Contexts )
|
|
{
|
|
if ( context == mouse ) continue;
|
|
|
|
context.IN_ButtonReleased( button, EngineToModifier( ikeymods ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static void OnWindowActive( bool active )
|
|
{
|
|
if ( active )
|
|
{
|
|
timeSinceWindowActive = 0;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Reset state and do button release events
|
|
//
|
|
PressedButtons.Clear();
|
|
|
|
foreach ( var context in Contexts )
|
|
{
|
|
context.ReleaseAllButtons();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cursor is hidden and restricted to window (game mode) but the mouse has been moved
|
|
/// </summary>
|
|
internal static void OnMouseMotion( float dx, float dy )
|
|
{
|
|
var delta = new Vector2( dx, dy );
|
|
|
|
MouseCursorDelta += delta;
|
|
MouseCursorPosition += delta;
|
|
|
|
// game or mouse capture
|
|
var mouse = Contexts.FirstOrDefault( x => x.MouseState != InputContext.InputState.Ignore );
|
|
if ( mouse is not null )
|
|
{
|
|
mouse.In_MousePosition( MouseCursorPosition, delta );
|
|
return;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cursor is visible and mouse is being moved
|
|
/// </summary>
|
|
internal static void OnMousePositionChange( float x, float y, float dx, float dy )
|
|
{
|
|
var delta = new Vector2( 0, 0 );
|
|
|
|
// if we're not in relative mode - take the delta from this
|
|
if ( !NativeEngine.InputSystem.GetRelativeMouseMode() )
|
|
{
|
|
delta = new Vector2( dx, dy );
|
|
MouseCursorDelta += delta;
|
|
}
|
|
|
|
MouseCursorPosition = new Vector2( x, y );
|
|
|
|
// if this is set, we're in capture mode - so just update the position
|
|
// which will update the position of the cursor when we come out of it
|
|
if ( mouseCapturePosition is not null )
|
|
{
|
|
mouseCapturePosition = MouseCursorPosition;
|
|
return;
|
|
}
|
|
|
|
var mouse = Contexts.FirstOrDefault( x => x.MouseState != InputContext.InputState.Ignore );
|
|
if ( mouse is not null )
|
|
{
|
|
mouse.In_MousePosition( MouseCursorPosition, delta );
|
|
}
|
|
}
|
|
|
|
internal static void OnGameControllerButton( int deviceId, GameControllerCode button, bool down )
|
|
{
|
|
if ( button == GameControllerCode.Start )
|
|
{
|
|
OnEscapePressed( down );
|
|
return;
|
|
}
|
|
|
|
OnGamepadCode( deviceId, button.ToGamepadCode(), down );
|
|
}
|
|
|
|
/// <summary>
|
|
/// The escape, or start button has been pressed
|
|
/// </summary>
|
|
private static void OnEscapePressed( bool down )
|
|
{
|
|
EscapeIsDown = down;
|
|
|
|
if ( down )
|
|
{
|
|
EscapeWasPressed = true;
|
|
TimeSinceEscapePressed = 0;
|
|
|
|
// Any focused UI? Let that swallow the escape button. This is for things like escaping from text areas
|
|
var escapeTarget = Contexts.FirstOrDefault( x => x.KeyboardState != InputContext.InputState.Ignore && x.KeyboardFocusPanel is not null );
|
|
if ( escapeTarget is not null && escapeTarget.In_Escape() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Let the game input get first dibs
|
|
if ( IGameInstance.Current is not null && IGameInstanceDll.Current.InputContext.In_Escape() )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void OnGamepadCode( int deviceId, GamepadCode code, bool down )
|
|
{
|
|
var controller = Controller.All.FirstOrDefault( x => x.DeviceId == deviceId );
|
|
Log.Trace( $"OnGameControllerButton {controller} - {code}, {down}" );
|
|
|
|
Sandbox.Input.UsingController = true;
|
|
|
|
SetButtonState( code, down );
|
|
|
|
foreach ( var action in Sandbox.Input.InputActions.Where( x => x.GamepadCode != GamepadCode.None && x.GamepadCode == code ) )
|
|
{
|
|
var i = Sandbox.Input.GetActionIndex( action );
|
|
foreach ( var e in Sandbox.Input.Contexts )
|
|
{
|
|
if ( down )
|
|
{
|
|
e.AccumActionsPressed |= 1UL << i;
|
|
}
|
|
else
|
|
{
|
|
e.AccumActionsReleased |= 1UL << i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static void OnGameControllerAxis( int deviceId, GameControllerAxis axis, int value )
|
|
{
|
|
var controller = Controller.All.FirstOrDefault( x => x.DeviceId == deviceId );
|
|
Log.Trace( $"OnGameControllerButton {controller} - {axis}, {value}" );
|
|
|
|
if ( controller is null )
|
|
return;
|
|
|
|
controller.SetAxis( axis, value );
|
|
|
|
//// We're going to check our triggers and convert them into a virtual button, for ease of use
|
|
//// (and backwards compatibility with SteamInput)
|
|
|
|
//// We don't care about non triggers
|
|
if ( axis < GameControllerAxis.TriggerLeft )
|
|
return;
|
|
|
|
const float triggerDeadzone = 0.75f;
|
|
|
|
// I hate this but okay
|
|
GamepadCode code = axis switch
|
|
{
|
|
GameControllerAxis.TriggerLeft => GamepadCode.LeftTrigger,
|
|
GameControllerAxis.TriggerRight => GamepadCode.RightTrigger,
|
|
_ => GamepadCode.None,
|
|
};
|
|
|
|
OnGamepadCode( deviceId, code, value >= triggerDeadzone );
|
|
}
|
|
|
|
internal static void OnGameControllerConnected( int joystickId, int deviceId )
|
|
{
|
|
var controller = new Controller( joystickId, deviceId );
|
|
Log.Info( $"New {controller} controller detected" );
|
|
|
|
Controller.All.Add( controller );
|
|
}
|
|
|
|
internal static void OnGameControllerDisconnected( int joystickId )
|
|
{
|
|
var controller = Controller.All.FirstOrDefault( x => x.SDLHandle == joystickId );
|
|
if ( controller is not null )
|
|
{
|
|
Log.Info( $"{controller} controller removed" );
|
|
Controller.All.Remove( controller );
|
|
}
|
|
else
|
|
{
|
|
Log.Warning( $"Couldn't find Controller instance with {joystickId}" );
|
|
}
|
|
}
|
|
|
|
internal static void OnKey( ButtonCode button, bool down, bool repeat, int ikeymods, int vkcode )
|
|
{
|
|
if ( !repeat )
|
|
{
|
|
SetButtonState( button, down );
|
|
}
|
|
|
|
if ( button == ButtonCode.KEY_ESCAPE )
|
|
{
|
|
if ( repeat )
|
|
return;
|
|
|
|
OnEscapePressed( down );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Function keys
|
|
//
|
|
if ( button >= ButtonCode.KEY_F1 && button <= ButtonCode.KEY_F12 )
|
|
{
|
|
if ( !down || repeat ) return;
|
|
|
|
IToolsDll.Current?.OnFunctionKey( button, EngineToModifier( ikeymods ) );
|
|
|
|
var bind = g_pInputService.GetBinding( button );
|
|
if ( string.IsNullOrEmpty( bind ) ) return;
|
|
|
|
ConVarSystem.Run( bind );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Console
|
|
//
|
|
if ( button == ButtonCode.KEY_BACKQUOTE || button == ButtonCode.KEY_TILDE )
|
|
{
|
|
if ( !down || repeat ) return;
|
|
|
|
if ( Engine.IToolsDll.Current?.ConsoleFocus() ?? false )
|
|
return;
|
|
|
|
ConVarSystem.Run( "con_toggle" );
|
|
return;
|
|
}
|
|
|
|
var keyboard = Contexts.FirstOrDefault( x => x.KeyboardState != InputContext.InputState.Ignore );
|
|
if ( keyboard is not null )
|
|
{
|
|
keyboard.IN_Button( down, button, repeat, EngineToModifier( ikeymods ) );
|
|
}
|
|
|
|
//
|
|
// When a button is released, we send it to each context. These contexts may have
|
|
// the button as pressed. The release should be sent to them so they can clear it.
|
|
//
|
|
if ( !down )
|
|
{
|
|
foreach ( var context in Contexts )
|
|
{
|
|
if ( context == keyboard ) continue;
|
|
|
|
context.IN_ButtonReleased( button, EngineToModifier( ikeymods ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static void OnText( uint key )
|
|
{
|
|
var keyboard = Contexts.FirstOrDefault( x => x.KeyboardState == InputContext.InputState.UI );
|
|
if ( keyboard is not null )
|
|
{
|
|
keyboard.IN_Text( (char)key );
|
|
}
|
|
}
|
|
|
|
internal static void OnMouseWheel( int x, int y, int ikeymods )
|
|
{
|
|
var value = new Vector2( x, y );
|
|
var mouse = Contexts.FirstOrDefault( x => x.MouseState != InputContext.InputState.Ignore );
|
|
|
|
if ( mouse is not null )
|
|
{
|
|
if ( y < 0 )
|
|
{
|
|
mouse.IN_Button( true, ButtonCode.MouseWheelDown, false, default );
|
|
mouse.IN_Button( false, ButtonCode.MouseWheelDown, false, default );
|
|
}
|
|
else
|
|
{
|
|
mouse.IN_Button( true, ButtonCode.MouseWheelUp, false, default );
|
|
mouse.IN_Button( false, ButtonCode.MouseWheelUp, false, default );
|
|
}
|
|
|
|
mouse.IN_MouseWheel( value, EngineToModifier( ikeymods ) );
|
|
}
|
|
}
|
|
|
|
internal static void OnImeStart()
|
|
{
|
|
var keyboard = Contexts.FirstOrDefault( x => x.KeyboardState != InputContext.InputState.Ignore );
|
|
if ( keyboard is not null )
|
|
{
|
|
keyboard.IN_ImeStart();
|
|
}
|
|
}
|
|
|
|
internal static void OnImeComposition( string text, bool final )
|
|
{
|
|
var keyboard = Contexts.FirstOrDefault( x => x.KeyboardState != InputContext.InputState.Ignore );
|
|
if ( keyboard is not null )
|
|
{
|
|
keyboard.IN_ImeComposition( text, final );
|
|
}
|
|
}
|
|
|
|
internal static void OnImeEnd()
|
|
{
|
|
var keyboard = Contexts.FirstOrDefault( x => x.KeyboardState != InputContext.InputState.Ignore );
|
|
if ( keyboard is not null )
|
|
{
|
|
keyboard.IN_ImeEnd();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert engine (IE_ShiftPressed etc) to our KeyboardModifiers enum
|
|
/// </summary>
|
|
static KeyboardModifiers EngineToModifier( int engine )
|
|
{
|
|
KeyboardModifiers m = KeyboardModifiers.None;
|
|
|
|
if ( (engine & 1) == 1 ) m |= KeyboardModifiers.Shift;
|
|
if ( (engine & 2) == 2 ) m |= KeyboardModifiers.Ctrl;
|
|
if ( (engine & 4) == 4 ) m |= KeyboardModifiers.Alt;
|
|
//if ( (m_nData2 & 8) == 8 ) m |= KeyboardModifiers.Windows;
|
|
//if ( (m_nData2 & 16) == 8 ) m |= KeyboardModifiers.Finger;
|
|
|
|
return m;
|
|
}
|
|
}
|