Added touch input support to XNA build.

Tweaked keyboard services, including how game port generates keys.
This commit is contained in:
Sean Fausett 2011-01-08 00:55:17 +13:00
parent fe9abb1c2b
commit b0d09b7fb7
20 changed files with 575 additions and 173 deletions

View File

@ -1,5 +1,4 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.GamerServices;
@ -37,18 +36,6 @@ namespace Jellyfish.Library
}
}
[SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
protected override void Update(GameTime gameTime)
{
var gamePadState = GamePad.GetState(PlayerIndex.One);
if (gamePadState.Buttons.Back == ButtonState.Pressed)
{
Exit();
}
base.Update(gameTime);
}
public string Name { get; private set; }
public GraphicsDeviceManager GraphicsDeviceManager { get; private set; }
public IGraphicsDeviceService GraphicsDeviceService { get; private set; }

View File

@ -112,6 +112,10 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="FrameRateCounter.cs" />
<Compile Include="GameBase.cs" />
<Compile Include="TouchButton.cs" />
<Compile Include="TouchJoystick.cs" />
<Compile Include="TouchRegion.cs" />
<Compile Include="TouchRegionCollection.cs" />
</ItemGroup>
<ItemGroup>
<CodeAnalysisDictionary Include="..\CustomDictionary.xml">

View File

@ -127,6 +127,10 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="FrameRateCounter.cs" />
<Compile Include="GameBase.cs" />
<Compile Include="TouchButton.cs" />
<Compile Include="TouchJoystick.cs" />
<Compile Include="TouchRegion.cs" />
<Compile Include="TouchRegionCollection.cs" />
</ItemGroup>
<ItemGroup>
<CodeAnalysisDictionary Include="..\CustomDictionary.xml">

View File

@ -142,6 +142,10 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="FrameRateCounter.cs" />
<Compile Include="GameBase.cs" />
<Compile Include="TouchButton.cs" />
<Compile Include="TouchJoystick.cs" />
<Compile Include="TouchRegion.cs" />
<Compile Include="TouchRegionCollection.cs" />
</ItemGroup>
<ItemGroup>
<CodeAnalysisDictionary Include="..\CustomDictionary.xml">

View File

@ -0,0 +1,12 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input.Touch;
namespace Jellyfish.Library
{
public sealed class TouchButton : TouchRegion
{
public bool HasValue { get { return Touch.HasValue; } }
public bool IsButtonDown { get { var touch = Touch.Value; return ((touch.State == TouchLocationState.Pressed) || (touch.State == TouchLocationState.Moved)); } }
public Vector2 Position { get { return Touch.Value.Position; } }
}
}

View File

@ -0,0 +1,49 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input.Touch;
namespace Jellyfish.Library
{
public sealed class TouchJoystick : TouchRegion
{
public Vector2 GetJoystick()
{
TouchLocation touch;
bool isValid;
if (KeepLast && LastTouch.HasValue)
{
touch = LastTouch.Value;
isValid = (touch.State != TouchLocationState.Invalid);
}
else
{
touch = Touch.Value;
isValid = (touch.State == TouchLocationState.Pressed) || (touch.State == TouchLocationState.Moved);
}
if (isValid)
{
var center = Center;
var joystick = new Vector2((touch.Position.X - center.X) / Radius, (center.Y - touch.Position.Y) / Radius);
if (joystick.LengthSquared() > 1)
{
joystick.Normalize();
}
return joystick;
}
return Vector2.Zero;
}
public void SetRadius(float radius) // scaled
{
Radius = (int)(radius * Math.Min(TouchPanel.DisplayWidth, TouchPanel.DisplayHeight));
}
public int Radius { get; set; }
public bool KeepLast { get; set; }
public Vector2 Center { get { return FirstTouch.Value.Position; } }
public bool HasValue { get { return ((KeepLast && LastTouch.HasValue) || Touch.HasValue); } }
public Vector2 Position { get { return (KeepLast && LastTouch.HasValue) ? LastTouch.Value.Position : Touch.Value.Position; } }
}
}

View File

@ -0,0 +1,20 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input.Touch;
namespace Jellyfish.Library
{
public class TouchRegion
{
public void SetBounds(float x, float y, float width, float height) // scaled
{
Bounds = new Rectangle((int)(x * TouchPanel.DisplayWidth), (int)(y * TouchPanel.DisplayHeight), (int)(width * TouchPanel.DisplayWidth), (int)(height * TouchPanel.DisplayHeight));
}
public Rectangle Bounds { get; set; }
public int Order { get; set; }
internal TouchLocation? Touch { get; set; }
internal TouchLocation? FirstTouch { get; set; }
internal TouchLocation? LastTouch { get; set; }
}
}

View File

@ -0,0 +1,79 @@
using System.Collections.ObjectModel;
using Microsoft.Xna.Framework.Input.Touch;
namespace Jellyfish.Library
{
public sealed class TouchRegionCollection : Collection<TouchRegion>
{
public TouchRegionCollection()
{
}
public void Update(ref TouchCollection touches)
{
for (int i = 0; i < base.Count; i++)
{
base[i].Touch = null;
}
for (int i = 0; i < touches.Count; i++)
{
var touch = touches[i];
if (UpdateById(ref touch))
{
continue;
}
TouchLocation prevTouch;
if (touch.TryGetPreviousLocation(out prevTouch))
{
UpdateByPosition(ref prevTouch);
}
else
{
UpdateByPosition(ref touch);
}
}
}
private bool UpdateById(ref TouchLocation touch)
{
for (int i = 0; i < base.Count; i++)
{
var region = base[i];
if (region.LastTouch.HasValue && (region.LastTouch.Value.Id == touch.Id))
{
region.Touch = touch;
region.LastTouch = touch;
return true;
}
}
return false;
}
private void UpdateByPosition(ref TouchLocation touch)
{
if ((touch.State == TouchLocationState.Pressed) || (touch.State == TouchLocationState.Moved))
{
TouchRegion topMostRegion = null;
for (int i = 0; i < base.Count; i++)
{
var region = base[i];
if (region.Bounds.Contains((int)touch.Position.X, (int)touch.Position.Y) && ((topMostRegion == null) || (topMostRegion.Order < region.Order)))
{
topMostRegion = region;
}
}
if ((topMostRegion != null) && !topMostRegion.Touch.HasValue)
{
topMostRegion.Touch = touch;
topMostRegion.FirstTouch = touch;
topMostRegion.LastTouch = touch;
}
}
}
}
}

View File

@ -18,6 +18,7 @@
</Recognized>
<Unrecognized>
<Word>DownRight</Word>
<Word>GamePad</Word>
<Word>UpRight</Word>
</Unrecognized>
</Words>

View File

@ -23,6 +23,30 @@ namespace Jellyfish.Virtu
_gamePortService = Machine.Services.GetService<GamePortService>();
JoystickDeadZone = 0.4f;
#if WINDOWS_PHONE
UseTouch = true;
#endif
InvertPaddles = true; // Raster Blaster
SwapPaddles = true;
Joystick0TouchX = 0.35f;
Joystick0TouchY = 0.6f;
Joystick0TouchWidth = 0.25f;
Joystick0TouchHeight = 0.4f;
Joystick0TouchRadius = 0.2f;
Joystick0TouchKeepLast = true;
Button0TouchX = 0;
Button0TouchY = 0;
Button0TouchWidth = 0.5f;
Button0TouchHeight = 1;
Button1TouchX = 0.5f;
Button1TouchY = 0;
Button1TouchWidth = 0.5f;
Button1TouchHeight = 1;
Button2TouchX = 0.75f;
Button2TouchY = 0;
Button2TouchWidth = 0.25f;
Button2TouchHeight = 0.25f;
Button2TouchOrder = 1;
}
public override void LoadState(BinaryReader reader, Version version)
@ -32,8 +56,10 @@ namespace Jellyfish.Virtu
throw new ArgumentNullException("reader");
}
JoystickDeadZone = reader.ReadSingle();
InvertPaddles = reader.ReadBoolean();
SwapPaddles = reader.ReadBoolean();
UseShiftKeyMod = reader.ReadBoolean();
JoystickDeadZone = reader.ReadSingle();
UseKeyboard = reader.ReadBoolean();
Joystick0UpLeftKey = reader.ReadInt32();
@ -55,6 +81,37 @@ namespace Jellyfish.Virtu
Button0Key = reader.ReadInt32();
Button1Key = reader.ReadInt32();
Button2Key = reader.ReadInt32();
UseTouch = reader.ReadBoolean();
Joystick0TouchX = reader.ReadSingle();
Joystick0TouchY = reader.ReadSingle();
Joystick0TouchWidth = reader.ReadSingle();
Joystick0TouchHeight = reader.ReadSingle();
Joystick0TouchOrder = reader.ReadInt32();
Joystick0TouchRadius = reader.ReadSingle();
Joystick0TouchKeepLast = reader.ReadBoolean();
Joystick1TouchX = reader.ReadSingle();
Joystick1TouchY = reader.ReadSingle();
Joystick1TouchWidth = reader.ReadSingle();
Joystick1TouchHeight = reader.ReadSingle();
Joystick1TouchOrder = reader.ReadInt32();
Joystick1TouchRadius = reader.ReadSingle();
Joystick1TouchKeepLast = reader.ReadBoolean();
Button0TouchX = reader.ReadSingle();
Button0TouchY = reader.ReadSingle();
Button0TouchWidth = reader.ReadSingle();
Button0TouchHeight = reader.ReadSingle();
Button0TouchOrder = reader.ReadInt32();
Button1TouchX = reader.ReadSingle();
Button1TouchY = reader.ReadSingle();
Button1TouchWidth = reader.ReadSingle();
Button1TouchHeight = reader.ReadSingle();
Button1TouchOrder = reader.ReadInt32();
Button2TouchX = reader.ReadSingle();
Button2TouchY = reader.ReadSingle();
Button2TouchWidth = reader.ReadSingle();
Button2TouchHeight = reader.ReadSingle();
Button2TouchOrder = reader.ReadInt32();
}
public override void SaveState(BinaryWriter writer)
@ -64,8 +121,10 @@ namespace Jellyfish.Virtu
throw new ArgumentNullException("writer");
}
writer.Write(JoystickDeadZone);
writer.Write(InvertPaddles);
writer.Write(SwapPaddles);
writer.Write(UseShiftKeyMod);
writer.Write(JoystickDeadZone);
writer.Write(UseKeyboard);
writer.Write(Joystick0UpLeftKey);
@ -87,6 +146,37 @@ namespace Jellyfish.Virtu
writer.Write(Button0Key);
writer.Write(Button1Key);
writer.Write(Button2Key);
writer.Write(UseTouch);
writer.Write(Joystick0TouchX);
writer.Write(Joystick0TouchY);
writer.Write(Joystick0TouchWidth);
writer.Write(Joystick0TouchHeight);
writer.Write(Joystick0TouchOrder);
writer.Write(Joystick0TouchRadius);
writer.Write(Joystick0TouchKeepLast);
writer.Write(Joystick1TouchX);
writer.Write(Joystick1TouchY);
writer.Write(Joystick1TouchWidth);
writer.Write(Joystick1TouchHeight);
writer.Write(Joystick1TouchOrder);
writer.Write(Joystick1TouchRadius);
writer.Write(Joystick1TouchKeepLast);
writer.Write(Button0TouchX);
writer.Write(Button0TouchY);
writer.Write(Button0TouchWidth);
writer.Write(Button0TouchHeight);
writer.Write(Button0TouchOrder);
writer.Write(Button1TouchX);
writer.Write(Button1TouchY);
writer.Write(Button1TouchWidth);
writer.Write(Button1TouchHeight);
writer.Write(Button1TouchOrder);
writer.Write(Button2TouchX);
writer.Write(Button2TouchY);
writer.Write(Button2TouchWidth);
writer.Write(Button2TouchHeight);
writer.Write(Button2TouchOrder);
}
public bool ReadButton0()
@ -121,61 +211,68 @@ namespace Jellyfish.Virtu
((Joystick0LeftKey > 0) && _keyboardService.IsKeyDown(Joystick0LeftKey)) ||
((Joystick0DownLeftKey > 0) && _keyboardService.IsKeyDown(Joystick0DownLeftKey)))
{
paddle0 -= 128;
paddle0 -= PaddleScale;
}
if (((Joystick0UpRightKey > 0) && _keyboardService.IsKeyDown(Joystick0UpRightKey)) ||
((Joystick0RightKey > 0) && _keyboardService.IsKeyDown(Joystick0RightKey)) ||
((Joystick0DownRightKey > 0) && _keyboardService.IsKeyDown(Joystick0DownRightKey)))
{
paddle0 += 128;
paddle0 += PaddleScale;
}
if (((Joystick0UpLeftKey > 0) && _keyboardService.IsKeyDown(Joystick0UpLeftKey)) ||
((Joystick0UpKey > 0) && _keyboardService.IsKeyDown(Joystick0UpKey)) ||
((Joystick0UpRightKey > 0) && _keyboardService.IsKeyDown(Joystick0UpRightKey)))
{
paddle1 -= 128;
paddle1 -= PaddleScale;
}
if (((Joystick0DownLeftKey > 0) && _keyboardService.IsKeyDown(Joystick0DownLeftKey)) ||
((Joystick0DownKey > 0) && _keyboardService.IsKeyDown(Joystick0DownKey)) ||
((Joystick0DownRightKey > 0) && _keyboardService.IsKeyDown(Joystick0DownRightKey)))
{
paddle1 += 128;
paddle1 += PaddleScale;
}
if (((Joystick1UpLeftKey > 0) && _keyboardService.IsKeyDown(Joystick1UpLeftKey)) ||
((Joystick1LeftKey > 0) && _keyboardService.IsKeyDown(Joystick1LeftKey)) ||
((Joystick1DownLeftKey > 0) && _keyboardService.IsKeyDown(Joystick1DownLeftKey)))
{
paddle2 -= 128;
paddle2 -= PaddleScale;
}
if (((Joystick1UpRightKey > 0) && _keyboardService.IsKeyDown(Joystick1UpRightKey)) ||
((Joystick1RightKey > 0) && _keyboardService.IsKeyDown(Joystick1RightKey)) ||
((Joystick1DownRightKey > 0) && _keyboardService.IsKeyDown(Joystick1DownRightKey)))
{
paddle2 += 128;
paddle2 += PaddleScale;
}
if (((Joystick1UpLeftKey > 0) && _keyboardService.IsKeyDown(Joystick1UpLeftKey)) ||
((Joystick1UpKey > 0) && _keyboardService.IsKeyDown(Joystick1UpKey)) ||
((Joystick1UpRightKey > 0) && _keyboardService.IsKeyDown(Joystick1UpRightKey)))
{
paddle3 -= 128;
paddle3 -= PaddleScale;
}
if (((Joystick1DownLeftKey > 0) && _keyboardService.IsKeyDown(Joystick1DownLeftKey)) ||
((Joystick1DownKey > 0) && _keyboardService.IsKeyDown(Joystick1DownKey)) ||
((Joystick1DownRightKey > 0) && _keyboardService.IsKeyDown(Joystick1DownRightKey)))
{
paddle3 += 128;
paddle3 += PaddleScale;
}
}
if (InvertPaddles)
{
paddle0 = 2 * PaddleScale - paddle0;
paddle1 = 2 * PaddleScale - paddle1;
paddle2 = 2 * PaddleScale - paddle2;
paddle3 = 2 * PaddleScale - paddle3;
}
Paddle0Strobe = true;
Paddle1Strobe = true;
Paddle2Strobe = true;
Paddle3Strobe = true;
Machine.Events.AddEvent(MathHelpers.ClampByte(paddle0) * CyclesPerValue, _resetPaddle0StrobeEvent); // [7-29]
Machine.Events.AddEvent(MathHelpers.ClampByte(paddle1) * CyclesPerValue, _resetPaddle1StrobeEvent);
Machine.Events.AddEvent(MathHelpers.ClampByte(paddle2) * CyclesPerValue, _resetPaddle2StrobeEvent);
Machine.Events.AddEvent(MathHelpers.ClampByte(paddle3) * CyclesPerValue, _resetPaddle3StrobeEvent);
Machine.Events.AddEvent(MathHelpers.ClampByte(SwapPaddles ? paddle1 : paddle0) * CyclesPerValue, _resetPaddle0StrobeEvent); // [7-29]
Machine.Events.AddEvent(MathHelpers.ClampByte(SwapPaddles ? paddle0 : paddle1) * CyclesPerValue, _resetPaddle1StrobeEvent);
Machine.Events.AddEvent(MathHelpers.ClampByte(SwapPaddles ? paddle3 : paddle2) * CyclesPerValue, _resetPaddle2StrobeEvent);
Machine.Events.AddEvent(MathHelpers.ClampByte(SwapPaddles ? paddle2 : paddle3) * CyclesPerValue, _resetPaddle3StrobeEvent);
}
private void ResetPaddle0StrobeEvent()
@ -198,8 +295,12 @@ namespace Jellyfish.Virtu
Paddle3Strobe = false;
}
public float JoystickDeadZone { get; set; }
public const int PaddleScale = 128;
public bool InvertPaddles { get; set; }
public bool SwapPaddles { get; set; }
public bool UseShiftKeyMod { get; set; }
public float JoystickDeadZone { get; set; }
public bool UseKeyboard { get; set; }
public int Joystick0UpLeftKey { get; set; }
@ -222,6 +323,37 @@ namespace Jellyfish.Virtu
public int Button1Key { get; set; }
public int Button2Key { get; set; }
public bool UseTouch { get; set; }
public float Joystick0TouchX { get; set; }
public float Joystick0TouchY { get; set; }
public float Joystick0TouchWidth { get; set; }
public float Joystick0TouchHeight { get; set; }
public int Joystick0TouchOrder { get; set; }
public float Joystick0TouchRadius { get; set; }
public bool Joystick0TouchKeepLast { get; set; }
public float Joystick1TouchX { get; set; }
public float Joystick1TouchY { get; set; }
public float Joystick1TouchWidth { get; set; }
public float Joystick1TouchHeight { get; set; }
public int Joystick1TouchOrder { get; set; }
public float Joystick1TouchRadius { get; set; }
public bool Joystick1TouchKeepLast { get; set; }
public float Button0TouchX { get; set; }
public float Button0TouchY { get; set; }
public float Button0TouchWidth { get; set; }
public float Button0TouchHeight { get; set; }
public int Button0TouchOrder { get; set; }
public float Button1TouchX { get; set; }
public float Button1TouchY { get; set; }
public float Button1TouchWidth { get; set; }
public float Button1TouchHeight { get; set; }
public int Button1TouchOrder { get; set; }
public float Button2TouchX { get; set; }
public float Button2TouchY { get; set; }
public float Button2TouchWidth { get; set; }
public float Button2TouchHeight { get; set; }
public int Button2TouchOrder { get; set; }
public bool Paddle0Strobe { get; private set; }
public bool Paddle1Strobe { get; private set; }
public bool Paddle2Strobe { get; private set; }

View File

@ -1,5 +1,4 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Jellyfish.Virtu.Services;
@ -15,7 +14,9 @@ namespace Jellyfish.Virtu
public override void Initialize()
{
_keyboardService = Machine.Services.GetService<KeyboardService>();
_gamePortService = Machine.Services.GetService<GamePortService>();
UseGamePort = true; // Raster Blaster
Button2Key = ' ';
}
public override void LoadState(BinaryReader reader, Version version)
@ -76,99 +77,6 @@ namespace Jellyfish.Virtu
writer.Write(Button2Key);
}
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
public int ReadLatch()
{
if (Strobe)
{
return Latch;
}
if (UseGamePort)
{
if ((Joystick0UpLeftKey > 0) && _gamePortService.IsJoystick0Up && _gamePortService.IsJoystick0Left)
{
Latch = Joystick0UpLeftKey;
}
else if ((Joystick0UpRightKey > 0) && _gamePortService.IsJoystick0Up && _gamePortService.IsJoystick0Right)
{
Latch = Joystick0UpRightKey;
}
else if ((Joystick0DownLeftKey > 0) && _gamePortService.IsJoystick0Down && _gamePortService.IsJoystick0Left)
{
Latch = Joystick0DownLeftKey;
}
else if ((Joystick0DownRightKey > 0) && _gamePortService.IsJoystick0Down && _gamePortService.IsJoystick0Right)
{
Latch = Joystick0DownRightKey;
}
else if ((Joystick0UpKey > 0) && _gamePortService.IsJoystick0Up)
{
Latch = Joystick0UpKey;
}
else if ((Joystick0LeftKey > 0) && _gamePortService.IsJoystick0Left)
{
Latch = Joystick0LeftKey;
}
else if ((Joystick0RightKey > 0) && _gamePortService.IsJoystick0Right)
{
Latch = Joystick0RightKey;
}
else if ((Joystick0DownKey > 0) && _gamePortService.IsJoystick0Down)
{
Latch = Joystick0DownKey;
}
if ((Joystick1UpLeftKey > 0) && _gamePortService.IsJoystick1Up && _gamePortService.IsJoystick1Left) // override
{
Latch = Joystick1UpLeftKey;
}
else if ((Joystick1UpRightKey > 0) && _gamePortService.IsJoystick1Up && _gamePortService.IsJoystick1Right)
{
Latch = Joystick1UpRightKey;
}
else if ((Joystick1DownLeftKey > 0) && _gamePortService.IsJoystick1Down && _gamePortService.IsJoystick1Left)
{
Latch = Joystick1DownLeftKey;
}
else if ((Joystick1DownRightKey > 0) && _gamePortService.IsJoystick1Down && _gamePortService.IsJoystick1Right)
{
Latch = Joystick1DownRightKey;
}
else if ((Joystick1UpKey > 0) && _gamePortService.IsJoystick1Up)
{
Latch = Joystick1UpKey;
}
else if ((Joystick1LeftKey > 0) && _gamePortService.IsJoystick1Left)
{
Latch = Joystick1LeftKey;
}
else if ((Joystick1RightKey > 0) && _gamePortService.IsJoystick1Right)
{
Latch = Joystick1RightKey;
}
else if ((Joystick1DownKey > 0) && _gamePortService.IsJoystick1Down)
{
Latch = Joystick1DownKey;
}
if ((Button0Key > 0) && _gamePortService.IsButton0Down) // override
{
Latch = Button0Key;
}
else if ((Button1Key > 0) && _gamePortService.IsButton1Down)
{
Latch = Button1Key;
}
else if ((Button2Key > 0) && _gamePortService.IsButton2Down)
{
Latch = Button2Key;
}
}
return Latch;
}
public void ResetStrobe()
{
Strobe = false;
@ -200,7 +108,6 @@ namespace Jellyfish.Virtu
public bool Strobe { get; private set; }
private KeyboardService _keyboardService;
private GamePortService _gamePortService;
private int _latch;
}

View File

@ -233,56 +233,56 @@ namespace Jellyfish.Virtu
{
case 0xC000: case 0xC001: case 0xC002: case 0xC003: case 0xC004: case 0xC005: case 0xC006: case 0xC007: // [7-15]
case 0xC008: case 0xC009: case 0xC00A: case 0xC00B: case 0xC00C: case 0xC00D: case 0xC00E: case 0xC00F:
return SetBit7(_keyboard.ReadLatch(), _keyboard.Strobe);
return SetBit7(_keyboard.Latch, _keyboard.Strobe);
case 0xC010:
_keyboard.ResetStrobe();
return SetBit7(_keyboard.ReadLatch(), _keyboard.IsAnyKeyDown);
return SetBit7(_keyboard.Latch, _keyboard.IsAnyKeyDown);
case 0xC011:
return SetBit7(_keyboard.ReadLatch(), !IsHighRamBank1); // Bank1' [5-22]
return SetBit7(_keyboard.Latch, !IsHighRamBank1); // Bank1' [5-22]
case 0xC012:
return SetBit7(_keyboard.ReadLatch(), IsHighRamRead);
return SetBit7(_keyboard.Latch, IsHighRamRead);
case 0xC013:
return SetBit7(_keyboard.ReadLatch(), IsRamReadAux);
return SetBit7(_keyboard.Latch, IsRamReadAux);
case 0xC014:
return SetBit7(_keyboard.ReadLatch(), IsRamWriteAux);
return SetBit7(_keyboard.Latch, IsRamWriteAux);
case 0xC015:
return SetBit7(_keyboard.ReadLatch(), IsRomC1CFInternal);
return SetBit7(_keyboard.Latch, IsRomC1CFInternal);
case 0xC016:
return SetBit7(_keyboard.ReadLatch(), IsZeroPageAux);
return SetBit7(_keyboard.Latch, IsZeroPageAux);
case 0xC017:
return SetBit7(_keyboard.ReadLatch(), IsRomC3C3External);
return SetBit7(_keyboard.Latch, IsRomC3C3External);
case 0xC018:
return SetBit7(_keyboard.ReadLatch(), Is80Store);
return SetBit7(_keyboard.Latch, Is80Store);
case 0xC019:
return SetBit7(_keyboard.ReadLatch(), !_video.IsVBlank); // Vbl' [7-5]
return SetBit7(_keyboard.Latch, !_video.IsVBlank); // Vbl' [7-5]
case 0xC01A:
return SetBit7(_keyboard.ReadLatch(), IsText);
return SetBit7(_keyboard.Latch, IsText);
case 0xC01B:
return SetBit7(_keyboard.ReadLatch(), IsMixed);
return SetBit7(_keyboard.Latch, IsMixed);
case 0xC01C:
return SetBit7(_keyboard.ReadLatch(), IsPage2);
return SetBit7(_keyboard.Latch, IsPage2);
case 0xC01D:
return SetBit7(_keyboard.ReadLatch(), IsHires);
return SetBit7(_keyboard.Latch, IsHires);
case 0xC01E:
return SetBit7(_keyboard.ReadLatch(), IsCharSetAlternate);
return SetBit7(_keyboard.Latch, IsCharSetAlternate);
case 0xC01F:
return SetBit7(_keyboard.ReadLatch(), Is80Columns);
return SetBit7(_keyboard.Latch, Is80Columns);
case 0xC020: case 0xC021: case 0xC022: case 0xC023: case 0xC024: case 0xC025: case 0xC026: case 0xC027: // [7-8]
case 0xC028: case 0xC029: case 0xC02A: case 0xC02B: case 0xC02C: case 0xC02D: case 0xC02E: case 0xC02F:

View File

@ -1,4 +1,6 @@
namespace Jellyfish.Virtu.Services
using System;
namespace Jellyfish.Virtu.Services
{
public class GamePortService : MachineService
{
@ -8,7 +10,65 @@
Paddle0 = Paddle1 = Paddle2 = Paddle3 = 255; // not connected
}
public virtual void Update() { } // main thread
public virtual void Update() // main thread
{
var keyboard = Machine.Keyboard;
if (keyboard.UseGamePort)
{
UpdateKey(keyboard.Joystick0UpKey, IsJoystick0Up, ref _isJoystick0UpKeyDown, ref _wasJoystick0UpKeyDown);
UpdateKey(keyboard.Joystick0LeftKey, IsJoystick0Left, ref _isJoystick0LeftKeyDown, ref _wasJoystick0LeftKeyDown);
UpdateKey(keyboard.Joystick0RightKey, IsJoystick0Right, ref _isJoystick0RightKeyDown, ref _wasJoystick0RightKeyDown);
UpdateKey(keyboard.Joystick0DownKey, IsJoystick0Down, ref _isJoystick0DownKeyDown, ref _wasJoystick0DownKeyDown);
UpdateKey(keyboard.Joystick0UpLeftKey, IsJoystick0Up && IsJoystick0Left, ref _isJoystick0UpLeftKeyDown, ref _wasJoystick0UpLeftKeyDown);
UpdateKey(keyboard.Joystick0UpRightKey, IsJoystick0Up && IsJoystick0Right, ref _isJoystick0UpRightKeyDown, ref _wasJoystick0UpRightKeyDown);
UpdateKey(keyboard.Joystick0DownLeftKey, IsJoystick0Down && IsJoystick0Left, ref _isJoystick0DownLeftKeyDown, ref _wasJoystick0DownLeftKeyDown);
UpdateKey(keyboard.Joystick0DownRightKey, IsJoystick0Down && IsJoystick0Right, ref _isJoystick0DownRightKeyDown, ref _wasJoystick0DownRightKeyDown);
UpdateKey(keyboard.Joystick1UpKey, IsJoystick1Up, ref _isJoystick1UpKeyDown, ref _wasJoystick1UpKeyDown);
UpdateKey(keyboard.Joystick1LeftKey, IsJoystick1Left, ref _isJoystick1LeftKeyDown, ref _wasJoystick1LeftKeyDown);
UpdateKey(keyboard.Joystick1RightKey, IsJoystick1Right, ref _isJoystick1RightKeyDown, ref _wasJoystick1RightKeyDown);
UpdateKey(keyboard.Joystick1DownKey, IsJoystick1Down, ref _isJoystick1DownKeyDown, ref _wasJoystick1DownKeyDown);
UpdateKey(keyboard.Joystick1UpLeftKey, IsJoystick1Up && IsJoystick1Left, ref _isJoystick1UpLeftKeyDown, ref _wasJoystick1UpLeftKeyDown);
UpdateKey(keyboard.Joystick1UpRightKey, IsJoystick1Up && IsJoystick1Right, ref _isJoystick1UpRightKeyDown, ref _wasJoystick1UpRightKeyDown);
UpdateKey(keyboard.Joystick1DownLeftKey, IsJoystick1Down && IsJoystick1Left, ref _isJoystick1DownLeftKeyDown, ref _wasJoystick1DownLeftKeyDown);
UpdateKey(keyboard.Joystick1DownRightKey, IsJoystick1Down && IsJoystick1Right, ref _isJoystick1DownRightKeyDown, ref _wasJoystick1DownRightKeyDown);
UpdateKey(keyboard.Button0Key, IsButton0Down, ref _isButton0KeyDown, ref _wasButton0KeyDown);
UpdateKey(keyboard.Button1Key, IsButton1Down, ref _isButton1KeyDown, ref _wasButton1KeyDown);
UpdateKey(keyboard.Button2Key, IsButton2Down, ref _isButton2KeyDown, ref _wasButton2KeyDown);
if (_lastKey > 0) // repeat last key
{
long time = DateTime.UtcNow.Ticks;
if (time - _lastTime >= _repeatTime)
{
_lastTime = time;
_repeatTime = RepeatSpeed;
keyboard.Latch = _lastKey;
}
}
}
}
private void UpdateKey(int key, bool isActive, ref bool isKeyDown, ref bool wasKeyDown)
{
wasKeyDown = isKeyDown;
isKeyDown = (key > 0) && isActive;
if (isKeyDown != wasKeyDown)
{
if (isKeyDown)
{
_lastKey = key;
_lastTime = DateTime.UtcNow.Ticks;
_repeatTime = RepeatDelay;
Machine.Keyboard.Latch = key;
}
else if (key == _lastKey)
{
_lastKey = 0;
}
}
}
public int Paddle0 { get; protected set; }
public int Paddle1 { get; protected set; }
@ -28,5 +88,52 @@
public bool IsButton0Down { get; protected set; }
public bool IsButton1Down { get; protected set; }
public bool IsButton2Down { get; protected set; }
private static readonly long RepeatDelay = TimeSpan.FromMilliseconds(500).Ticks;
private static readonly long RepeatSpeed = TimeSpan.FromMilliseconds(32).Ticks;
private bool _isJoystick0UpLeftKeyDown;
private bool _isJoystick0UpKeyDown;
private bool _isJoystick0UpRightKeyDown;
private bool _isJoystick0LeftKeyDown;
private bool _isJoystick0RightKeyDown;
private bool _isJoystick0DownLeftKeyDown;
private bool _isJoystick0DownKeyDown;
private bool _isJoystick0DownRightKeyDown;
private bool _isJoystick1UpLeftKeyDown;
private bool _isJoystick1UpKeyDown;
private bool _isJoystick1UpRightKeyDown;
private bool _isJoystick1LeftKeyDown;
private bool _isJoystick1RightKeyDown;
private bool _isJoystick1DownLeftKeyDown;
private bool _isJoystick1DownKeyDown;
private bool _isJoystick1DownRightKeyDown;
private bool _isButton0KeyDown;
private bool _isButton1KeyDown;
private bool _isButton2KeyDown;
private bool _wasJoystick0UpLeftKeyDown;
private bool _wasJoystick0UpKeyDown;
private bool _wasJoystick0UpRightKeyDown;
private bool _wasJoystick0LeftKeyDown;
private bool _wasJoystick0RightKeyDown;
private bool _wasJoystick0DownLeftKeyDown;
private bool _wasJoystick0DownKeyDown;
private bool _wasJoystick0DownRightKeyDown;
private bool _wasJoystick1UpLeftKeyDown;
private bool _wasJoystick1UpKeyDown;
private bool _wasJoystick1UpRightKeyDown;
private bool _wasJoystick1LeftKeyDown;
private bool _wasJoystick1RightKeyDown;
private bool _wasJoystick1DownLeftKeyDown;
private bool _wasJoystick1DownKeyDown;
private bool _wasJoystick1DownRightKeyDown;
private bool _wasButton0KeyDown;
private bool _wasButton1KeyDown;
private bool _wasButton2KeyDown;
private int _lastKey;
private long _lastTime;
private long _repeatTime;
}
}

View File

@ -33,9 +33,9 @@ namespace Jellyfish.Virtu.Services
{
_updateAnyKeyDown = false;
IsAnyKeyDown = false;
foreach (Key key in KeyValues)
for (int i = 0; i < KeyValues.Length; i++)
{
if (IsKeyDown(key))
if (IsKeyDown(KeyValues[i]))
{
IsAnyKeyDown = true;
break;
@ -111,9 +111,9 @@ namespace Jellyfish.Virtu.Services
private void OnPageLostFocus(object sender, RoutedEventArgs e) // reset keyboard state on lost focus; can't access keyboard state on got focus
{
IsAnyKeyDown = false;
foreach (Key key in KeyValues)
for (int i = 0; i < KeyValues.Length; i++)
{
_states[(int)key] = false;
_states[(int)KeyValues[i]] = false;
}
}

View File

@ -33,8 +33,9 @@ namespace Jellyfish.Virtu.Services
{
_updateAnyKeyDown = false;
IsAnyKeyDown = false;
foreach (Key key in KeyValues)
for (int i = 0; i < KeyValues.Length; i++)
{
var key = KeyValues[i];
bool isKeyDown = keyboard.IsKeyDown(key);
_states[(int)key] = isKeyDown;
if (isKeyDown)

View File

@ -81,6 +81,9 @@
<Reference Include="Microsoft.Xna.Framework.GamerServices">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.Xna.Framework.Input.Touch">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.Xna.Framework.Xact">
<Private>False</Private>
</Reference>

View File

@ -84,6 +84,9 @@
<Reference Include="Microsoft.Xna.Framework.GamerServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.Xna.Framework.Input.Touch, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.Xna.Framework.Xact, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
<Private>False</Private>
</Reference>

View File

@ -2,6 +2,8 @@
using Jellyfish.Virtu.Services;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
namespace Jellyfish.Virtu
{
@ -60,8 +62,17 @@ namespace Jellyfish.Virtu
protected override void Update(GameTime gameTime)
{
_keyboardService.Update();
_gamePortService.Update();
var keyboardState = Microsoft.Xna.Framework.Input.Keyboard.GetState();
var gamePadState = GamePad.GetState(PlayerIndex.One);
var touches = TouchPanel.GetState();
if (gamePadState.Buttons.Back == ButtonState.Pressed)
{
Exit();
}
_keyboardService.Update(ref keyboardState, ref gamePadState);
_gamePortService.Update(ref gamePadState, ref touches);
base.Update(gameTime);
}
@ -83,8 +94,8 @@ namespace Jellyfish.Virtu
private DebugService _debugService;
private StorageService _storageService;
private KeyboardService _keyboardService;
private GamePortService _gamePortService;
private XnaKeyboardService _keyboardService;
private XnaGamePortService _gamePortService;
private AudioService _audioService;
private VideoService _videoService;
}

View File

@ -1,5 +1,7 @@
using Microsoft.Xna.Framework;
using System.Diagnostics.CodeAnalysis;
using Jellyfish.Library;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
namespace Jellyfish.Virtu.Services
{
@ -8,24 +10,28 @@ namespace Jellyfish.Virtu.Services
public XnaGamePortService(Machine machine) :
base(machine)
{
_touchRegions = new TouchRegionCollection { _touchJoystick0, _touchJoystick1, _touchButton0, _touchButton1, _touchButton2 };
}
public override void Update() // main thread
[SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
public void Update(ref GamePadState gamePadState, ref TouchCollection touches) // main thread
{
_lastState = _state;
_state = GamePad.GetState(PlayerIndex.One);
_state = gamePadState;
var gamePort = Machine.GamePort;
if (_state.IsConnected && (_state != _lastState))
{
var left = _state.ThumbSticks.Left;
var right = _state.ThumbSticks.Right;
var dpad = _state.DPad;
var gamePort = Machine.GamePort;
var buttons = _state.Buttons;
Paddle0 = (int)((1 + left.X) * PaddleScale);
Paddle1 = (int)((1 - left.Y) * PaddleScale); // invert y
Paddle2 = (int)((1 + right.X) * PaddleScale);
Paddle3 = (int)((1 - right.Y) * PaddleScale); // invert y
Paddle0 = (int)((1 + left.X) * GamePort.PaddleScale);
Paddle1 = (int)((1 - left.Y) * GamePort.PaddleScale); // invert y
Paddle2 = (int)((1 + right.X) * GamePort.PaddleScale);
Paddle3 = (int)((1 - right.Y) * GamePort.PaddleScale); // invert y
IsJoystick0Up = ((left.Y > gamePort.JoystickDeadZone) || (dpad.Up == ButtonState.Pressed));
IsJoystick0Left = ((left.X < -gamePort.JoystickDeadZone) || (dpad.Left == ButtonState.Pressed));
@ -37,15 +43,85 @@ namespace Jellyfish.Virtu.Services
IsJoystick1Right = (right.X > gamePort.JoystickDeadZone);
IsJoystick1Down = (right.Y < -gamePort.JoystickDeadZone);
IsButton0Down = ((_state.Buttons.A == ButtonState.Pressed) || (_state.Buttons.LeftShoulder == ButtonState.Pressed));
IsButton1Down = ((_state.Buttons.B == ButtonState.Pressed) || (_state.Buttons.RightShoulder == ButtonState.Pressed));
IsButton2Down = (_state.Buttons.X == ButtonState.Pressed);
IsButton0Down = ((buttons.A == ButtonState.Pressed) || (buttons.LeftShoulder == ButtonState.Pressed));
IsButton1Down = ((buttons.B == ButtonState.Pressed) || (buttons.RightShoulder == ButtonState.Pressed));
IsButton2Down = (buttons.X == ButtonState.Pressed);
}
if (gamePort.UseTouch) // override
{
UpdateTouch(ref touches);
}
base.Update();
}
private void UpdateTouch(ref TouchCollection touches)
{
var gamePort = Machine.GamePort;
_touchJoystick0.SetBounds(gamePort.Joystick0TouchX, gamePort.Joystick0TouchY, gamePort.Joystick0TouchWidth, gamePort.Joystick0TouchHeight);
_touchJoystick0.SetRadius(gamePort.Joystick0TouchRadius);
_touchJoystick0.KeepLast = gamePort.Joystick0TouchKeepLast;
_touchJoystick0.Order = gamePort.Joystick0TouchOrder;
_touchJoystick1.SetBounds(gamePort.Joystick1TouchX, gamePort.Joystick1TouchY, gamePort.Joystick1TouchWidth, gamePort.Joystick1TouchHeight);
_touchJoystick1.SetRadius(gamePort.Joystick1TouchRadius);
_touchJoystick1.KeepLast = gamePort.Joystick1TouchKeepLast;
_touchJoystick1.Order = gamePort.Joystick1TouchOrder;
_touchButton0.SetBounds(gamePort.Button0TouchX, gamePort.Button0TouchY, gamePort.Button0TouchWidth, gamePort.Button0TouchHeight);
_touchButton0.Order = gamePort.Button0TouchOrder;
_touchButton1.SetBounds(gamePort.Button1TouchX, gamePort.Button1TouchY, gamePort.Button1TouchWidth, gamePort.Button1TouchHeight);
_touchButton1.Order = gamePort.Button1TouchOrder;
_touchButton2.SetBounds(gamePort.Button2TouchX, gamePort.Button2TouchY, gamePort.Button2TouchWidth, gamePort.Button2TouchHeight);
_touchButton2.Order = gamePort.Button2TouchOrder;
_touchRegions.Update(ref touches);
if (_touchJoystick0.HasValue)
{
var joystick = _touchJoystick0.GetJoystick();
Paddle0 = (int)((1 + joystick.X) * GamePort.PaddleScale);
Paddle1 = (int)((1 - joystick.Y) * GamePort.PaddleScale); // invert y
IsJoystick0Up = (joystick.Y > gamePort.JoystickDeadZone);
IsJoystick0Left = (joystick.X < -gamePort.JoystickDeadZone);
IsJoystick0Right = (joystick.X > gamePort.JoystickDeadZone);
IsJoystick0Down = (joystick.Y < -gamePort.JoystickDeadZone);
}
if (_touchJoystick1.HasValue)
{
var joystick = _touchJoystick1.GetJoystick();
Paddle2 = (int)((1 + joystick.X) * GamePort.PaddleScale);
Paddle3 = (int)((1 - joystick.Y) * GamePort.PaddleScale); // invert y
IsJoystick1Up = (joystick.Y > gamePort.JoystickDeadZone);
IsJoystick1Left = (joystick.X < -gamePort.JoystickDeadZone);
IsJoystick1Right = (joystick.X > gamePort.JoystickDeadZone);
IsJoystick1Down = (joystick.Y < -gamePort.JoystickDeadZone);
}
if (_touchButton0.HasValue)
{
IsButton0Down = _touchButton0.IsButtonDown;
}
if (_touchButton1.HasValue)
{
IsButton1Down = _touchButton1.IsButtonDown;
}
if (_touchButton2.HasValue)
{
IsButton2Down = _touchButton2.IsButtonDown;
}
}
private const int PaddleScale = 128;
private GamePadState _state;
private GamePadState _lastState;
private TouchJoystick _touchJoystick0 = new TouchJoystick();
private TouchJoystick _touchJoystick1 = new TouchJoystick();
private TouchButton _touchButton0 = new TouchButton();
private TouchButton _touchButton1 = new TouchButton();
private TouchButton _touchButton2 = new TouchButton();
private TouchRegionCollection _touchRegions;
}
}

View File

@ -18,19 +18,21 @@ namespace Jellyfish.Virtu.Services
return IsKeyDown((Keys)key);
}
public override void Update() // main thread
[SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
public void Update(ref KeyboardState keyboardState, ref GamePadState gamePadState) // main thread
{
_lastState = _state;
_state = Microsoft.Xna.Framework.Input.Keyboard.GetState();
_state = keyboardState;
var gamePadState = GamePad.GetState(PlayerIndex.One);
bool gamePadControl = (gamePadState.Buttons.LeftStick == ButtonState.Pressed);
var gamePadButtons = gamePadState.Buttons;
bool gamePadControl = (gamePadButtons.LeftStick == ButtonState.Pressed);
if (_state != _lastState)
{
IsAnyKeyDown = false;
foreach (Keys key in KeyValues) // xna doesn't support buffered input; loses input order and could lose keys between updates
for (int i = 0; i < KeyValues.Length; i++) // xna doesn't support buffered input; loses input order and could lose keys between updates
{
var key = KeyValues[i];
if (_state.IsKeyDown(key))
{
IsAnyKeyDown = true;
@ -70,9 +72,9 @@ namespace Jellyfish.Virtu.Services
IsControlKeyDown = IsKeyDown(Keys.LeftControl) || IsKeyDown(Keys.RightControl);
IsShiftKeyDown = IsKeyDown(Keys.LeftShift) || IsKeyDown(Keys.RightShift);
IsOpenAppleKeyDown = IsKeyDown(Keys.LeftAlt) || IsKeyDown(Keys.NumPad0) || (gamePadState.Buttons.LeftShoulder == ButtonState.Pressed);
IsCloseAppleKeyDown = IsKeyDown(Keys.RightAlt) || IsKeyDown(Keys.Decimal) || (gamePadState.Buttons.RightShoulder == ButtonState.Pressed);
IsResetKeyDown = (IsControlKeyDown && IsKeyDown(Keys.Back)) || (gamePadControl && (gamePadState.Buttons.Start == ButtonState.Pressed));
IsOpenAppleKeyDown = IsKeyDown(Keys.LeftAlt) || IsKeyDown(Keys.NumPad0) || (gamePadButtons.LeftShoulder == ButtonState.Pressed);
IsCloseAppleKeyDown = IsKeyDown(Keys.RightAlt) || IsKeyDown(Keys.Decimal) || (gamePadButtons.RightShoulder == ButtonState.Pressed);
IsResetKeyDown = (IsControlKeyDown && IsKeyDown(Keys.Back)) || (gamePadControl && (gamePadButtons.Start == ButtonState.Pressed));
base.Update();
}