diff --git a/InputSystems/ANX.InputSystem.Recording/Creator.cs b/InputSystems/ANX.InputSystem.Recording/Creator.cs index a3abd491..58d76577 100644 --- a/InputSystems/ANX.InputSystem.Recording/Creator.cs +++ b/InputSystems/ANX.InputSystem.Recording/Creator.cs @@ -113,11 +113,7 @@ namespace ANX.InputSystem.Recording public bool IsSupported { - get - { - //TODO: this is just a very basic version of test for support - return AddInSystemFactory.Instance.OperatingSystem.Platform == PlatformID.Win32NT; - } + get { return true; } //This is just a proxy, so it runs on all plattforms } } diff --git a/InputSystems/ANX.InputSystem.Recording/Metadata.Designer.cs b/InputSystems/ANX.InputSystem.Recording/Metadata.Designer.cs index 101f0079..bbe35c67 100644 --- a/InputSystems/ANX.InputSystem.Recording/Metadata.Designer.cs +++ b/InputSystems/ANX.InputSystem.Recording/Metadata.Designer.cs @@ -61,7 +61,7 @@ namespace ANX.InputSystem.Recording { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Win32NT ähnelt. + /// Sucht eine lokalisierte Zeichenfolge, die Win32NT Unix MacOsX ähnelt. /// public static string SupportedPlatforms { get { diff --git a/InputSystems/ANX.InputSystem.Recording/Metadata.resx b/InputSystems/ANX.InputSystem.Recording/Metadata.resx index c90f8c84..8451d556 100644 --- a/InputSystems/ANX.InputSystem.Recording/Metadata.resx +++ b/InputSystems/ANX.InputSystem.Recording/Metadata.resx @@ -118,6 +118,6 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Win32NT + Win32NT Unix MacOsX \ No newline at end of file diff --git a/InputSystems/ANX.InputSystem.Recording/RecordableDevice.cs b/InputSystems/ANX.InputSystem.Recording/RecordableDevice.cs index daa8b76e..c44a2c7c 100644 --- a/InputSystems/ANX.InputSystem.Recording/RecordableDevice.cs +++ b/InputSystems/ANX.InputSystem.Recording/RecordableDevice.cs @@ -63,41 +63,38 @@ namespace ANX.InputSystem.Recording { protected Stream recordStream; //The stream where the input is written to protected int nullStateCounter; //Used to sum up frames with no input. + protected bool isInitialized = false; public RecordingState RecordingState { get; protected set; } public event EventHandler EndOfPlaybackReached; /// - /// How many bytes this Instance requires per Frame. Must never change! + /// How many bytes this Instance requires per Paket. Must never change! /// - public int FramePacketLenght { get; protected set; } + public int PacketLenght { get; protected set; } public RecordableDevice() { RecordingState = RecordingState.None; } - /// - /// Initializes the Device using a new - /// MemoryStream for input-buffering. - /// - public virtual void Initialize() - { - Initialize(new MemoryStream()); - } - /// /// Initializes the Device using the specified stream /// for input-buffering. /// - public virtual void Initialize(Stream bufferStream) + protected void Initialize(Stream bufferStream) { recordStream = bufferStream; + + isInitialized = true; } public virtual void StartRecording() { + if (!isInitialized) + throw new InvalidOperationException("This instance is not initialized!"); + if (RecordingState == RecordingState.Recording) return; @@ -114,6 +111,9 @@ namespace ANX.InputSystem.Recording public virtual void StartPlayback() { + if (!isInitialized) + throw new InvalidOperationException("This instance is not initialized!"); + if (RecordingState == RecordingState.Recording) throw new InvalidOperationException("Recording is currently running for this device."); @@ -128,7 +128,6 @@ namespace ANX.InputSystem.Recording /// /// Writes the current input state to the buffering stream. Pass null /// for state, if no input is done (no keys down etc.). - /// Must be called once per Frame! /// protected virtual void WriteState(byte[] state) { @@ -138,7 +137,7 @@ namespace ANX.InputSystem.Recording return; } - if (state.Length != FramePacketLenght) + if (state.Length != PacketLenght) throw new InvalidOperationException("The passed state's lenght does not match the speficed FramePaketLenght."); if (nullStateCounter > 0) //Note how many packets we had nothing @@ -153,8 +152,7 @@ namespace ANX.InputSystem.Recording /// /// Reads the next input-state from the buffering stream. Might - /// return null, if no input was made in this frame. - /// Must be called once per Frame! + /// return null, if no input was made at this Position. /// protected virtual byte[] ReadState() { @@ -179,8 +177,8 @@ namespace ANX.InputSystem.Recording nullStateCounter = BitConverter.ToInt32(buffer, 0) - 1; return null; case PacketType.InputData: - byte[] buffer2 = new byte[FramePacketLenght]; - recordStream.Read(buffer2, 0, FramePacketLenght); + byte[] buffer2 = new byte[PacketLenght]; + recordStream.Read(buffer2, 0, PacketLenght); return buffer2; default: throw new NotImplementedException("The PaketType " + Enum.GetName(typeof(PacketType), type) + "is not supported."); @@ -188,6 +186,10 @@ namespace ANX.InputSystem.Recording } + /// + /// Fires the EndOfPlaybackReaced event. Overwrite this method to change + /// this behavoir. + /// protected virtual void OnEndOfPlaybackReached() { if (EndOfPlaybackReached != null) diff --git a/InputSystems/ANX.InputSystem.Recording/RecordingMouse.cs b/InputSystems/ANX.InputSystem.Recording/RecordingMouse.cs index f660a194..d510cdfa 100644 --- a/InputSystems/ANX.InputSystem.Recording/RecordingMouse.cs +++ b/InputSystems/ANX.InputSystem.Recording/RecordingMouse.cs @@ -6,6 +6,7 @@ using System.Text; using ANX.Framework.NonXNA; using ANX.Framework.Input; using System.IO; +using System.Runtime.InteropServices; #endregion @@ -69,6 +70,7 @@ namespace ANX.InputSystem.Recording ScrollWheel = 32, XPosition = 64, YPosition = 128, + LRMButtons = LeftButton | RightButton | MiddleButton, XButtons = X1Button | X2Button, AllButtons = LRMButtons | XButtons, @@ -77,45 +79,126 @@ namespace ANX.InputSystem.Recording } /// - /// Wrapper arround another IGamePad, will record all inputs and allows playback. + /// Used to store the ButtonStates packed to one byte. + /// + [Flags] + enum MouseButtons : byte + { + Left = 1, + Right = 2, + Middle = 4, + X1 = 8, + X2 = 16 + } + + /// + /// Wrapper arround another IMouse, will record all inputs and allows playback. /// public class RecordingMouse : RecordableDevice, IMouse { - public IntPtr WindowHandle { get; set; } + protected IMouse realMouse; + protected MouseRecordInfo recordInfo; - public MouseState GetState() + public IntPtr WindowHandle + { + get { return realMouse.WindowHandle; } + set { realMouse.WindowHandle = value; } + } + + public MouseState GetState() //The main recording/playback logic is placed here { - throw new NotImplementedException(); + switch(RecordingState) + { + case RecordingState.None: + return realMouse.GetState(); + case RecordingState.Playback: + case RecordingState.Recording: + MouseState state = realMouse.GetState(); + //Pack the state to a buffer and save it. In can be never null, because the mouse has allways a position. + //TODO: Check if the position is not recorded + byte[] buffer = new byte[PacketLenght]; + byte offset = 0; + if ((recordInfo & MouseRecordInfo.AllButtons) != 0) //Any of the Buttons is recorded + { + buffer[offset] |= state.LeftButton == ButtonState.Pressed ? (byte)MouseButtons.Left : (byte)0; //TODO: Is there a byte literal? (like 118L or 91.8f) + buffer[offset] |= state.RightButton == ButtonState.Pressed ? (byte)MouseButtons.Right : (byte)0; + buffer[offset] |= state.MiddleButton == ButtonState.Pressed ? (byte)MouseButtons.Middle : (byte)0; + buffer[offset] |= state.XButton1 == ButtonState.Pressed ? (byte)MouseButtons.X1 : (byte)0; + buffer[offset] |= state.XButton2 == ButtonState.Pressed ? (byte)MouseButtons.X2 : (byte)0; + offset++; + } + + if (recordInfo.HasFlag(MouseRecordInfo.ScrollWheel)) + Array.ConstrainedCopy(BitConverter.GetBytes(state.ScrollWheelValue), 0, buffer, offset++, 4); //int is always 4 byte long. + + if(recordInfo.HasFlag(MouseRecordInfo.XPosition)) + Array.ConstrainedCopy(BitConverter.GetBytes(state.X), 0, buffer, offset++, 4); //int is always 4 byte long. + + if(recordInfo.HasFlag(MouseRecordInfo.YPosition)) + Array.ConstrainedCopy(BitConverter.GetBytes(state.Y), 0, buffer, offset++, 4); //int is always 4 byte long. + + return state; + default: + throw new InvalidOperationException("The recordsingState is invalid!"); + } } public void SetPosition(int x, int y) { - throw new NotImplementedException(); + //We just pass this call the underlying IMouse, unless we are in Playback mode (we don't want the Mouse to jump arround during playback) + //There is no need in recording this calls, as they are reflected in the next frame's Mouse position. + if (RecordingState != RecordingState.Playback) + realMouse.SetPosition(x, y); } + /// + /// Intializes this instance using a new MemoryStream as the Buffer, the + /// default's InputSystems Mouse and the passed MouseRecordInfo. + /// public void Initialize(MouseRecordInfo info) { - base.Initialize(); + this.Initialize(info, new MemoryStream(), AddInSystemFactory.Instance.GetDefaultCreator().Mouse); } + /// + /// Intializes this instance using a new MemoryStream as the Buffer,recording + /// the passed IMouse, using the passed MouseRecordInfo. + /// + public void Initialize(MouseRecordInfo info, IMouse mouse) + { + this.Initialize(info, new MemoryStream(), mouse); + } + + /// + /// Intializes this instance using the passed Stream as the Buffer, the + /// default's InputSystems Mouse and the passed MouseRecordInfo. + /// public void Initialize(MouseRecordInfo info, Stream bufferStream) { + this.Initialize(info, bufferStream, AddInSystemFactory.Instance.GetDefaultCreator().Mouse); + } + + /// + /// Intializes this instance using the passed Stream as the Buffer, recording + /// the passed IMouse, using the passed MouseRecordInfo. + /// + public void Initialize(MouseRecordInfo info, Stream bufferStream, IMouse mouse) + { + realMouse = mouse; + realMouse.WindowHandle = WindowHandle; + + recordInfo = info; + PacketLenght = GetPaketSize(info); + base.Initialize(bufferStream); } private int GetPaketSize(MouseRecordInfo info) { - int ret = 0; //TODO: Pack the bools in one byte to save space sizeof(bool) == sizeof(byte)! - if (info.HasFlag(MouseRecordInfo.LeftButton)) - ret += sizeof(bool); - if (info.HasFlag(MouseRecordInfo.RightButton)) - ret += sizeof(bool); - if (info.HasFlag(MouseRecordInfo.MiddleButton)) - ret += sizeof(bool); - if (info.HasFlag(MouseRecordInfo.X1Button)) - ret += sizeof(bool); - if (info.HasFlag(MouseRecordInfo.X2Button)) - ret += sizeof(bool); + int ret = 0; + + if ((info & MouseRecordInfo.AllButtons) != 0) //We pack all Buttons in one byte, so it does not matter witch buttons are set. + ret += sizeof(byte); if (info.HasFlag(MouseRecordInfo.XPosition)) ret += sizeof(int);