Cosmetic changes.

Modified to clear audio buffer on reset.
Refactored keyboard services and unified key bindings where practical.

--HG--
extra : convert_revision : svn%3Affd33b8c-2492-42e0-bdc5-587b920b7d6d/trunk%4044385
This commit is contained in:
Sean Fausett 2010-04-01 23:00:24 +00:00
parent 0d1a883260
commit 26bd5e3aa9
24 changed files with 233 additions and 284 deletions

View File

@ -6,6 +6,11 @@ namespace Jellyfish.Library
{ {
public class ApplicationBase : Application public class ApplicationBase : Application
{ {
public ApplicationBase() :
this(null)
{
}
public ApplicationBase(string name) public ApplicationBase(string name)
{ {
Name = name; Name = name;
@ -17,6 +22,7 @@ public ApplicationBase(string name)
private void OnApplicationUnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) private void OnApplicationUnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{ {
MessageBox.Show(GetExceptionMessage(e.ExceptionObject), GetExceptionCaption("Application Exception", false), MessageBoxButton.OK); MessageBox.Show(GetExceptionMessage(e.ExceptionObject), GetExceptionCaption("Application Exception", false), MessageBoxButton.OK);
e.Handled = true;
} }
//private void OnAppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e) //private void OnAppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
@ -48,8 +54,7 @@ private static string GetExceptionMessage(Exception exception)
{ {
message.Append(exception.Message.ToString()); message.Append(exception.Message.ToString());
message.Append(Environment.NewLine); message.Append(Environment.NewLine);
message.Append(Environment.NewLine); message.Append(exception.StackTrace.ToString());
message.Append(exception.ToString()); // includes stack trace
} }
return message.ToString(); return message.ToString();

View File

@ -9,6 +9,12 @@ namespace Jellyfish.Library
{ {
public class ApplicationBase : Application public class ApplicationBase : Application
{ {
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
public ApplicationBase() :
this(null)
{
}
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
public ApplicationBase(string name) public ApplicationBase(string name)
{ {
@ -21,8 +27,8 @@ public ApplicationBase(string name)
private void OnApplicationDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) private void OnApplicationDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{ {
MessageBox.Show(GetExceptionMessage(e.Exception), GetExceptionCaption("Application Dispatcher Exception", true)); MessageBox.Show(GetExceptionMessage(e.Exception), GetExceptionCaption("Application Dispatcher Exception", true));
Shutdown();
e.Handled = true; e.Handled = true;
Shutdown();
} }
private void OnAppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e) private void OnAppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
@ -55,8 +61,7 @@ private static string GetExceptionMessage(Exception exception)
{ {
message.Append(exception.Message.ToString()); message.Append(exception.Message.ToString());
message.Append(Environment.NewLine); message.Append(Environment.NewLine);
message.Append(Environment.NewLine); message.Append(exception.StackTrace.ToString());
message.Append(exception.ToString()); // includes stack trace
} }
return message.ToString(); return message.ToString();

View File

@ -7,6 +7,11 @@ namespace Jellyfish.Library
{ {
public class GameBase : Game public class GameBase : Game
{ {
public GameBase() :
this(null)
{
}
public GameBase(string name) public GameBase(string name)
{ {
Name = name; Name = name;
@ -29,6 +34,7 @@ protected override void Update(GameTime gameTime)
{ {
Exit(); Exit();
} }
base.Update(gameTime); base.Update(gameTime);
} }

View File

@ -63,7 +63,7 @@ public override void WriteTrack(int number, int fraction, byte[] buffer)
if (!Read3Nibbles(0xD5, 0xAA, 0x96, 0x304)) if (!Read3Nibbles(0xD5, 0xAA, 0x96, 0x304))
break; // no address prologue break; // no address prologue
int readVolume = ReadNibble44(); /*int readVolume = */ReadNibble44();
int readTrack = ReadNibble44(); int readTrack = ReadNibble44();
if (readTrack != track) if (readTrack != track)
@ -94,7 +94,7 @@ public override void WriteTrack(int number, int fraction, byte[] buffer)
} }
if (sectorsDone != 0xFFFF) if (sectorsDone != 0xFFFF)
throw new Exception("disk error"); // TODO: we should alert the user and "dump" a NIB throw new InvalidOperationException("disk error"); // TODO: we should alert the user and "dump" a NIB
} }
private byte ReadNibble() private byte ReadNibble()
@ -110,16 +110,15 @@ private byte ReadNibble()
private bool Read3Nibbles(byte data1, byte data2, byte data3, int maxReads) private bool Read3Nibbles(byte data1, byte data2, byte data3, int maxReads)
{ {
bool result = false; bool result = false;
byte nibble;
while (--maxReads > 0) while (--maxReads > 0)
{ {
if ((nibble = ReadNibble()) != data1) if (ReadNibble() != data1)
continue; continue;
if ((nibble = ReadNibble()) != data2) if (ReadNibble() != data2)
continue; continue;
if ((nibble = ReadNibble()) != data3) if (ReadNibble() != data3)
continue; continue;
result = true; result = true;

View File

@ -18,7 +18,6 @@ public override void Initialize()
_gamePortService = Machine.Services.GetService<GamePortService>(); _gamePortService = Machine.Services.GetService<GamePortService>();
_keyboardService.AsciiKeyDown += (sender, e) => Latch = e.AsciiKey; _keyboardService.AsciiKeyDown += (sender, e) => Latch = e.AsciiKey;
Machine.Video.VSync += OnVideoVSync;
} }
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
@ -121,30 +120,6 @@ public void ResetStrobe()
Strobe = false; Strobe = false;
} }
private void OnVideoVSync(object sender, EventArgs e)
{
if (_keyboardService.IsResetKeyDown)
{
Machine.Reset();
_keyboardService.WaitForResetKeyUp();
}
else if (_keyboardService.IsCpuThrottleKeyDown)
{
Machine.Cpu.ToggleThrottle();
_keyboardService.WaitForKeyUp();
}
else if (_keyboardService.IsVideoFullScreenKeyDown)
{
Machine.Video.ToggleFullScreen();
_keyboardService.WaitForKeyUp();
}
else if (_keyboardService.IsVideoMonochromeKeyDown)
{
Machine.Video.ToggleMonochrome();
_keyboardService.WaitForKeyUp();
}
}
public bool IsAnyKeyDown { get { return _keyboardService.IsAnyKeyDown; } } public bool IsAnyKeyDown { get { return _keyboardService.IsAnyKeyDown; } }
public bool Strobe { get; private set; } public bool Strobe { get; private set; }

View File

@ -38,7 +38,7 @@ public void Dispose()
public void Reset() public void Reset()
{ {
Components.ForEach(component => component.Reset()); Components.ForEach(component => component.Reset()); // while machine starting or paused
} }
public void Start() public void Start()

View File

@ -24,6 +24,11 @@ public void Output(int data) // machine thread
} }
} }
public void Reset()
{
Buffer.BlockCopy(SampleZero, 0, _buffer, 0, SampleSize);
}
public override void Stop() // main thread public override void Stop() // main thread
{ {
_readEvent.Set(); // signal events; avoids deadlock _readEvent.Set(); // signal events; avoids deadlock
@ -49,7 +54,9 @@ protected void Update(int bufferSize, Action<byte[], int> updateBuffer) // audio
public const int SampleChannels = 1; public const int SampleChannels = 1;
public const int SampleBits = 8; public const int SampleBits = 8;
public const int SampleLatency = 40; // ms public const int SampleLatency = 40; // ms
public const int SampleSize = (int)(SampleRate * SampleLatency / 1000f) * SampleChannels * SampleBits / 8; public const int SampleSize = (SampleRate * SampleLatency / 1000) * SampleChannels * (SampleBits / 8);
private static readonly byte[] SampleZero = new byte[SampleSize];
private byte[] _buffer = new byte[SampleSize]; private byte[] _buffer = new byte[SampleSize];
private int _index; private int _index;

View File

@ -56,7 +56,7 @@ public GamePortService(Machine machine) :
Paddle0 = Paddle1 = Paddle2 = Paddle3 = 255; // not connected Paddle0 = Paddle1 = Paddle2 = Paddle3 = 255; // not connected
} }
public virtual void Update() { } public virtual void Update() { } // main thread
public int Paddle0 { get; protected set; } public int Paddle0 { get; protected set; }
public int Paddle1 { get; protected set; } public int Paddle1 { get; protected set; }

View File

@ -30,6 +30,24 @@ protected KeyboardService(Machine machine) :
public abstract bool IsKeyDown(int key); public abstract bool IsKeyDown(int key);
public virtual void Update() // main thread
{
if (IsResetKeyDown)
{
if (!_resetKeyDown)
{
_resetKeyDown = true; // entering reset; pause until key released
Machine.Pause();
Machine.Reset();
}
}
else if (_resetKeyDown)
{
_resetKeyDown = false; // leaving reset
Machine.Unpause();
}
}
protected void OnAsciiKeyDown(int asciiKey) protected void OnAsciiKeyDown(int asciiKey)
{ {
EventHandler<AsciiKeyEventArgs> handler = AsciiKeyDown; EventHandler<AsciiKeyEventArgs> handler = AsciiKeyDown;
@ -39,33 +57,14 @@ protected void OnAsciiKeyDown(int asciiKey)
} }
} }
public abstract void Update();
public void WaitForKeyUp()
{
while (IsAnyKeyDown)
{
Thread.Sleep(10);
}
}
public void WaitForResetKeyUp()
{
while (IsResetKeyDown)
{
Thread.Sleep(10);
}
}
public event EventHandler<AsciiKeyEventArgs> AsciiKeyDown; public event EventHandler<AsciiKeyEventArgs> AsciiKeyDown;
public bool IsAnyKeyDown { get; protected set; } public bool IsAnyKeyDown { get; protected set; }
public bool IsOpenAppleKeyDown { get; protected set; } public bool IsOpenAppleKeyDown { get; protected set; }
public bool IsCloseAppleKeyDown { get; protected set; } public bool IsCloseAppleKeyDown { get; protected set; }
public bool IsResetKeyDown { get; protected set; }
public bool IsCpuThrottleKeyDown { get; protected set; } protected bool IsResetKeyDown { get; set; }
public bool IsVideoFullScreenKeyDown { get; protected set; }
public bool IsVideoMonochromeKeyDown { get; protected set; } private bool _resetKeyDown;
} }
} }

View File

@ -8,7 +8,7 @@ protected VideoService(Machine machine) :
} }
public abstract void SetPixel(int x, int y, uint color); public abstract void SetPixel(int x, int y, uint color);
public abstract void Update(); public abstract void Update(); // main thread
public void ToggleFullScreen() public void ToggleFullScreen()
{ {

View File

@ -6,13 +6,16 @@
xmlns:jv="clr-namespace:Jellyfish.Virtu;assembly=Jellyfish.Virtu"> xmlns:jv="clr-namespace:Jellyfish.Virtu;assembly=Jellyfish.Virtu">
<tk:DockPanel Background="Black"> <tk:DockPanel Background="Black">
<StackPanel Orientation="Horizontal" tk:DockPanel.Dock="Top"> <StackPanel Orientation="Horizontal" tk:DockPanel.Dock="Top">
<Button x:Name="_disk1Button" Content="Disk 1" IsTabStop="false" Margin="4 4 0 4"/> <Button x:Name="_disk1Button" Content="Disk 1" IsTabStop="False" Margin="4 4 0 4"/>
<Button x:Name="_disk2Button" Content="Disk 2" IsTabStop="false" Margin="4 4 0 4"/> <Button x:Name="_disk2Button" Content="Disk 2" IsTabStop="False" Margin="4 4 0 4"/>
<jl:FrameRateCounter Margin="4 4 0 4" VerticalAlignment="Center"/> <jl:FrameRateCounter Margin="4 4 0 4" VerticalAlignment="Center"/>
</StackPanel> </StackPanel>
<Grid Cursor="None"> <Grid>
<Image x:Name="_image" MinWidth="560" MinHeight="384"/> <Image x:Name="_image" MinWidth="560" MinHeight="384"/>
<MediaElement x:Name="_media"/> <MediaElement x:Name="_media"/>
<!--<ScrollViewer BorderThickness="0" IsTabStop="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalScrollBarVisibility="Auto">
<TextBlock x:Name="_debug" FontFamily="Consolas" FontSize="12" Foreground="White"/>
</ScrollViewer>-->
</Grid> </Grid>
</tk:DockPanel> </tk:DockPanel>
</UserControl> </UserControl>

View File

@ -26,8 +26,16 @@ public SilverlightAudioService(Machine machine, UserControl page, MediaElement m
//_page.Closed += (sender, e) => _media.Stop(); // SL is missing Closed / Unloaded event //_page.Closed += (sender, e) => _media.Stop(); // SL is missing Closed / Unloaded event
} }
private void OnMediaSourceUpdate(object sender, WaveMediaStreamSourceUpdateEventArgs e) private void OnMediaSourceUpdate(object sender, WaveMediaStreamSourceUpdateEventArgs e) // audio thread
{ {
//if (_count++ % (1000 / SampleLatency) == 0)
//{
// _page.Dispatcher.BeginInvoke(new Action(() =>
// {
// ((MainPage)_page)._debug.Text += string.Concat(DateTime.Now, " OnMediaSourceUpdate", Environment.NewLine);
// }));
//}
Update(e.BufferSize, (source, count) => Update(e.BufferSize, (source, count) =>
{ {
Buffer.BlockCopy(source, 0, e.Buffer, 0, count); Buffer.BlockCopy(source, 0, e.Buffer, 0, count);
@ -37,5 +45,6 @@ private void OnMediaSourceUpdate(object sender, WaveMediaStreamSourceUpdateEvent
private UserControl _page; private UserControl _page;
private MediaElement _media; private MediaElement _media;
private WaveMediaStreamSource _mediaSource = new WaveMediaStreamSource(SampleRate, SampleChannels, SampleBits, SampleSize, SampleLatency); private WaveMediaStreamSource _mediaSource = new WaveMediaStreamSource(SampleRate, SampleChannels, SampleBits, SampleSize, SampleLatency);
//private int _count;
} }
} }

View File

@ -29,7 +29,7 @@ public override bool IsKeyDown(int key)
return IsKeyDown((Key)key); return IsKeyDown((Key)key);
} }
public override void Update() public override void Update() // main thread
{ {
if (_updateAnyKeyDown) // SL is missing access to keyboard state; could lose track of keyboard state after Alt+Tab if (_updateAnyKeyDown) // SL is missing access to keyboard state; could lose track of keyboard state after Alt+Tab
{ {
@ -46,15 +46,13 @@ public override void Update()
} }
ModifierKeys modifiers = System.Windows.Input.Keyboard.Modifiers; ModifierKeys modifiers = System.Windows.Input.Keyboard.Modifiers;
IsOpenAppleKeyDown = ((modifiers & (ModifierKeys.Control | ModifierKeys.Alt)) == (ModifierKeys.Control | ModifierKeys.Alt)) || bool control = ((modifiers & ModifierKeys.Control) != 0);
(((modifiers & ModifierKeys.Control) != 0) && IsKeyDown(Key.Left));
IsCloseAppleKeyDown = ((modifiers & (ModifierKeys.Control | ModifierKeys.Windows)) == (ModifierKeys.Control | ModifierKeys.Windows)) ||
(((modifiers & ModifierKeys.Control) != 0) && IsKeyDown(Key.Right));
IsResetKeyDown = ((modifiers & ModifierKeys.Control) != 0) && (IsKeyDown(Key.F12) || IsKeyDown(Key.Up));
IsCpuThrottleKeyDown = IsKeyDown(Key.F8); IsOpenAppleKeyDown = ((modifiers & ModifierKeys.Alt) != 0) || IsKeyDown(Key.NumPad0);
IsVideoFullScreenKeyDown = IsKeyDown(Key.F11); IsCloseAppleKeyDown = ((modifiers & ModifierKeys.Windows) != 0) || IsKeyDown(Key.Decimal);
IsVideoMonochromeKeyDown = IsKeyDown(Key.F9); IsResetKeyDown = control && IsKeyDown(Key.Back);
base.Update();
} }
private bool IsKeyDown(Key key) private bool IsKeyDown(Key key)
@ -64,7 +62,10 @@ private bool IsKeyDown(Key key)
private void OnPageKeyDown(object sender, KeyEventArgs e) private void OnPageKeyDown(object sender, KeyEventArgs e)
{ {
//((MainPage)_page)._debug.Text += string.Concat("OnPageKeyDn: Key=", e.Key, " PlatformKeyCode=", e.PlatformKeyCode, Environment.NewLine);
_states[(int)e.Key] = true; _states[(int)e.Key] = true;
_updateAnyKeyDown = false;
IsAnyKeyDown = true; IsAnyKeyDown = true;
int asciiKey = GetAsciiKey(e.Key, e.PlatformKeyCode); int asciiKey = GetAsciiKey(e.Key, e.PlatformKeyCode);
@ -73,13 +74,38 @@ private void OnPageKeyDown(object sender, KeyEventArgs e)
OnAsciiKeyDown(asciiKey); OnAsciiKeyDown(asciiKey);
e.Handled = true; e.Handled = true;
} }
Update();
} }
private void OnPageKeyUp(object sender, KeyEventArgs e) private void OnPageKeyUp(object sender, KeyEventArgs e)
{ {
_capsLock ^= (e.Key == Key.CapsLock); // SL is missing caps lock support; try to track manually //((MainPage)_page)._debug.Text += string.Concat("OnPageKeyUp: Key=", e.Key, " PlatformKeyCode=", e.PlatformKeyCode, Environment.NewLine);
_states[(int)e.Key] = false; _states[(int)e.Key] = false;
_updateAnyKeyDown = true; _updateAnyKeyDown = true;
ModifierKeys modifiers = System.Windows.Input.Keyboard.Modifiers;
bool control = ((modifiers & ModifierKeys.Control) != 0);
if (e.Key == Key.CapsLock)
{
_capsLock ^= true; // SL is missing caps lock support; try to track manually
}
else if (control && (e.Key == Key.Divide))
{
Machine.Cpu.ToggleThrottle();
}
else if (control && (e.Key == Key.Multiply))
{
Machine.Video.ToggleMonochrome();
}
else if (control && (e.Key == Key.Subtract))
{
Machine.Video.ToggleFullScreen();
}
Update();
} }
private void OnPageLostFocus(object sender, RoutedEventArgs e) // reset keyboard state on lost focus; can't access keyboard state on got focus private void OnPageLostFocus(object sender, RoutedEventArgs e) // reset keyboard state on lost focus; can't access keyboard state on got focus
@ -124,7 +150,7 @@ private int GetAsciiKey(Key key, int platformKeyCode)
return 0x1B; return 0x1B;
case Key.Back: case Key.Back:
return 0x7F; return control ? -1 : 0x7F;
case Key.Space: case Key.Space:
return ' '; return ' ';
@ -355,51 +381,6 @@ private int GetAsciiKey(Key key, int platformKeyCode)
break; break;
} }
break; break;
case Key.NumPad1:
return '1';
case Key.NumPad2:
return '2';
case Key.NumPad3:
return '3';
case Key.NumPad4:
return '4';
case Key.NumPad5:
return '5';
case Key.NumPad6:
return '6';
case Key.NumPad7:
return '7';
case Key.NumPad8:
return '8';
case Key.NumPad9:
return '9';
case Key.NumPad0:
return '0';
case Key.Decimal:
return '.';
case Key.Divide:
return '/';
case Key.Multiply:
return '*';
case Key.Subtract:
return '-';
case Key.Add:
return '+';
} }
return -1; return -1;

View File

@ -32,7 +32,7 @@ public override void SetPixel(int x, int y, uint color)
_pixelsDirty = true; _pixelsDirty = true;
} }
public override void Update() public override void Update() // main thread
{ {
if (Application.Current.IsRunningOutOfBrowser && /*_window.IsActive &&*/ (_isFullScreen != IsFullScreen)) if (Application.Current.IsRunningOutOfBrowser && /*_window.IsActive &&*/ (_isFullScreen != IsFullScreen))
{ {

View File

@ -18,6 +18,13 @@ public override void Initialize()
Machine.Events.AddEvent(CyclesPerFlush * Machine.Settings.Cpu.Multiplier, _flushOutputEvent); Machine.Events.AddEvent(CyclesPerFlush * Machine.Settings.Cpu.Multiplier, _flushOutputEvent);
} }
public override void Reset()
{
_audioService.Reset();
_isHigh = false;
_highCycles = _totalCycles = 0;
}
public void ToggleOutput() public void ToggleOutput()
{ {
UpdateCycles(); UpdateCycles();

View File

@ -5,12 +5,15 @@
Title="Virtu" ResizeMode="CanMinimize" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen"> Title="Virtu" ResizeMode="CanMinimize" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen">
<DockPanel Background="Black"> <DockPanel Background="Black">
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top"> <StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
<Button x:Name="_disk1Button" Content="Disk 1" Focusable="false" IsTabStop="false" Margin="4 4 0 4"/> <Button x:Name="_disk1Button" Content="Disk 1" Focusable="False" IsTabStop="False" Margin="4 4 0 4"/>
<Button x:Name="_disk2Button" Content="Disk 2" Focusable="false" IsTabStop="false" Margin="4 4 0 4"/> <Button x:Name="_disk2Button" Content="Disk 2" Focusable="False" IsTabStop="False" Margin="4 4 0 4"/>
<jl:FrameRateCounter Margin="4 4 0 4" VerticalAlignment="Center"/> <jl:FrameRateCounter Margin="4 4 0 4" VerticalAlignment="Center"/>
</StackPanel> </StackPanel>
<Grid Cursor="None"> <Grid>
<Image x:Name="_image" MinWidth="560" MinHeight="384" RenderOptions.BitmapScalingMode="NearestNeighbor"/> <Image x:Name="_image" MinWidth="560" MinHeight="384" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
<!--<ScrollViewer BorderThickness="0" Focusable="False" IsTabStop="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalScrollBarVisibility="Auto">
<TextBlock x:Name="_debug" FontFamily="Consolas" FontSize="12" Foreground="White"/>
</ScrollViewer>-->
</Grid> </Grid>
</DockPanel> </DockPanel>
</Window> </Window>

View File

@ -32,8 +32,16 @@ protected override void Dispose(bool disposing)
base.Dispose(disposing); base.Dispose(disposing);
} }
private void OnDirectSoundUpdate(object sender, DirectSoundUpdateEventArgs e) private void OnDirectSoundUpdate(object sender, DirectSoundUpdateEventArgs e) // audio thread
{ {
//if (_count++ % (1000 / SampleLatency) == 0)
//{
// _window.Dispatcher.BeginInvoke(new Action(() =>
// {
// ((MainWindow)_window)._debug.Text += string.Concat(DateTime.Now, " OnDirectSoundUpdate", Environment.NewLine);
// }));
//}
Update(e.BufferSize, (source, count) => Update(e.BufferSize, (source, count) =>
{ {
Marshal.Copy(source, 0, e.Buffer, count); Marshal.Copy(source, 0, e.Buffer, count);
@ -42,5 +50,6 @@ private void OnDirectSoundUpdate(object sender, DirectSoundUpdateEventArgs e)
private Window _window; private Window _window;
private DirectSound _directSound = new DirectSound(SampleRate, SampleChannels, SampleBits, SampleSize); private DirectSound _directSound = new DirectSound(SampleRate, SampleChannels, SampleBits, SampleSize);
//private int _count;
} }
} }

View File

@ -28,7 +28,7 @@ public override bool IsKeyDown(int key)
return IsKeyDown((Key)key); return IsKeyDown((Key)key);
} }
public override void Update() public override void Update() // main thread
{ {
KeyboardDevice keyboard = System.Windows.Input.Keyboard.PrimaryDevice; KeyboardDevice keyboard = System.Windows.Input.Keyboard.PrimaryDevice;
if (_updateAnyKeyDown) if (_updateAnyKeyDown)
@ -46,14 +46,13 @@ public override void Update()
} }
} }
ModifierKeys modifiers = keyboard.Modifiers; bool control = ((keyboard.Modifiers & ModifierKeys.Control) != 0);
IsOpenAppleKeyDown = keyboard.IsKeyDown(Key.LeftAlt);
IsCloseAppleKeyDown = keyboard.IsKeyDown(Key.RightAlt);
IsResetKeyDown = ((modifiers & ModifierKeys.Control) != 0) && keyboard.IsKeyDown(Key.F12);
IsCpuThrottleKeyDown = keyboard.IsKeyDown(Key.F8); IsOpenAppleKeyDown = keyboard.IsKeyDown(Key.LeftAlt) || IsKeyDown(Key.NumPad0);
IsVideoFullScreenKeyDown = keyboard.IsKeyDown(Key.F11); IsCloseAppleKeyDown = keyboard.IsKeyDown(Key.RightAlt) || IsKeyDown(Key.Decimal);
IsVideoMonochromeKeyDown = keyboard.IsKeyDown(Key.F9); IsResetKeyDown = control && keyboard.IsKeyDown(Key.Back);
base.Update();
} }
private bool IsKeyDown(Key key) private bool IsKeyDown(Key key)
@ -63,7 +62,10 @@ private bool IsKeyDown(Key key)
private void OnWindowKeyDown(object sender, KeyEventArgs e) private void OnWindowKeyDown(object sender, KeyEventArgs e)
{ {
//((MainWindow)_window)._debug.Text += string.Concat("OnWindowKeyDn: Key=", e.Key, Environment.NewLine);
_states[(int)((e.Key == Key.System) ? e.SystemKey : e.Key)] = true; _states[(int)((e.Key == Key.System) ? e.SystemKey : e.Key)] = true;
_updateAnyKeyDown = false;
IsAnyKeyDown = true; IsAnyKeyDown = true;
int asciiKey = GetAsciiKey(e.Key, e.KeyboardDevice); int asciiKey = GetAsciiKey(e.Key, e.KeyboardDevice);
@ -72,12 +74,33 @@ private void OnWindowKeyDown(object sender, KeyEventArgs e)
OnAsciiKeyDown(asciiKey); OnAsciiKeyDown(asciiKey);
e.Handled = true; e.Handled = true;
} }
Update();
} }
private void OnWindowKeyUp(object sender, KeyEventArgs e) private void OnWindowKeyUp(object sender, KeyEventArgs e)
{ {
//((MainWindow)_window)._debug.Text += string.Concat("OnWindowKeyUp: Key=", e.Key, Environment.NewLine);
_states[(int)((e.Key == Key.System) ? e.SystemKey : e.Key)] = false; _states[(int)((e.Key == Key.System) ? e.SystemKey : e.Key)] = false;
_updateAnyKeyDown = true; _updateAnyKeyDown = true;
bool control = ((e.KeyboardDevice.Modifiers & ModifierKeys.Control) != 0);
if (control && (e.Key == Key.Divide))
{
Machine.Cpu.ToggleThrottle();
}
else if (control && (e.Key == Key.Multiply))
{
Machine.Video.ToggleMonochrome();
}
else if (control && (e.Key == Key.Subtract))
{
Machine.Video.ToggleFullScreen();
}
Update();
} }
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
@ -112,7 +135,7 @@ private static int GetAsciiKey(Key key, KeyboardDevice keyboard)
return 0x1B; return 0x1B;
case Key.Back: case Key.Back:
return 0x7F; return control ? -1 : 0x7F;
case Key.Space: case Key.Space:
return ' '; return ' ';
@ -257,51 +280,6 @@ private static int GetAsciiKey(Key key, KeyboardDevice keyboard)
case Key.OemPeriod: case Key.OemPeriod:
return shift ? '>' : '.'; return shift ? '>' : '.';
case Key.NumPad1:
return '1';
case Key.NumPad2:
return '2';
case Key.NumPad3:
return '3';
case Key.NumPad4:
return '4';
case Key.NumPad5:
return '5';
case Key.NumPad6:
return '6';
case Key.NumPad7:
return '7';
case Key.NumPad8:
return '8';
case Key.NumPad9:
return '9';
case Key.NumPad0:
return '0';
case Key.Decimal:
return '.';
case Key.Divide:
return '/';
case Key.Multiply:
return '*';
case Key.Subtract:
return '-';
case Key.Add:
return '+';
} }
return -1; return -1;

View File

@ -40,7 +40,7 @@ public override void SetPixel(int x, int y, uint color)
_pixelsDirty = true; _pixelsDirty = true;
} }
public override void Update() public override void Update() // main thread
{ {
if (_window.IsActive && (_isFullScreen != IsFullScreen)) if (_window.IsActive && (_isFullScreen != IsFullScreen))
{ {

View File

@ -7,7 +7,7 @@ namespace Jellyfish.Virtu
{ {
public sealed class MainGame : GameBase public sealed class MainGame : GameBase
{ {
public MainGame() : public MainGame() :
base("Virtu") base("Virtu")
{ {
Components.Add(new FrameRateCounter(this) { DrawOrder = 1, FontName = "Consolas" }); Components.Add(new FrameRateCounter(this) { DrawOrder = 1, FontName = "Consolas" });
@ -46,6 +46,7 @@ protected override void Dispose(bool disposing)
_audioService.Dispose(); _audioService.Dispose();
_videoService.Dispose(); _videoService.Dispose();
} }
base.Dispose(disposing); base.Dispose(disposing);
} }
@ -58,6 +59,7 @@ protected override void Update(GameTime gameTime)
{ {
_keyboardService.Update(); _keyboardService.Update();
_gamePortService.Update(); _gamePortService.Update();
base.Update(gameTime); base.Update(gameTime);
} }
@ -65,6 +67,7 @@ protected override void Draw(GameTime gameTime)
{ {
GraphicsDevice.Clear(Color.Black); GraphicsDevice.Clear(Color.Black);
_videoService.Update(); _videoService.Update();
base.Draw(gameTime); base.Draw(gameTime);
} }

View File

@ -30,7 +30,7 @@ protected override void Dispose(bool disposing)
} }
} }
private void OnDirectSoundUpdate(object sender, DirectSoundUpdateEventArgs e) private void OnDirectSoundUpdate(object sender, DirectSoundUpdateEventArgs e) // audio thread
{ {
Update(e.BufferSize, (source, count) => Update(e.BufferSize, (source, count) =>
{ {

View File

@ -10,7 +10,7 @@ public XnaGamePortService(Machine machine) :
{ {
} }
public override void Update() public override void Update() // main thread
{ {
_lastState = _state; _lastState = _state;
_state = GamePad.GetState(PlayerIndex.One); _state = GamePad.GetState(PlayerIndex.One);

View File

@ -18,14 +18,14 @@ public override bool IsKeyDown(int key)
return IsKeyDown((Keys)key); return IsKeyDown((Keys)key);
} }
public override void Update() public override void Update() // main thread
{ {
#if XBOX
GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);
#endif
_lastState = _state; _lastState = _state;
_state = Microsoft.Xna.Framework.Input.Keyboard.GetState(); _state = Microsoft.Xna.Framework.Input.Keyboard.GetState();
GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);
bool gamePadControl = (gamePadState.Buttons.LeftStick == ButtonState.Pressed);
if (_state != _lastState) if (_state != _lastState)
{ {
IsAnyKeyDown = false; IsAnyKeyDown = false;
@ -36,25 +36,22 @@ public override void Update()
IsAnyKeyDown = true; IsAnyKeyDown = true;
if (!_lastState.IsKeyDown(key)) if (!_lastState.IsKeyDown(key))
{ {
_capsLock ^= (key == Keys.CapsLock);
_lastKey = key; _lastKey = key;
_lastTime = DateTime.UtcNow.Ticks; _lastTime = DateTime.UtcNow.Ticks;
_repeatTime = RepeatDelay; _repeatTime = RepeatDelay;
#if XBOX OnKeyDown(key, gamePadControl);
int asciiKey = GetAsciiKey(key, ref gamePadState);
#else
int asciiKey = GetAsciiKey(key);
#endif
if (asciiKey >= 0)
{
OnAsciiKeyDown(asciiKey);
}
} }
} }
else if (key == _lastKey) else
{ {
_lastKey = Keys.None; if (key == _lastKey)
{
_lastKey = Keys.None;
}
if (_lastState.IsKeyDown(key))
{
OnKeyUp(key, gamePadControl);
}
} }
} }
} }
@ -66,34 +63,17 @@ public override void Update()
{ {
_lastTime = time; _lastTime = time;
_repeatTime = RepeatSpeed; _repeatTime = RepeatSpeed;
#if XBOX OnKeyDown(_lastKey, gamePadControl);
int asciiKey = GetAsciiKey(_lastKey, ref gamePadState);
#else
int asciiKey = GetAsciiKey(_lastKey);
#endif
if (asciiKey >= 0)
{
OnAsciiKeyDown(asciiKey);
}
} }
} }
#if XBOX
IsOpenAppleKeyDown = IsKeyDown(Keys.LeftAlt) || (gamePadState.Buttons.LeftShoulder == ButtonState.Pressed);
IsCloseAppleKeyDown = IsKeyDown(Keys.RightAlt) || (gamePadState.Buttons.RightShoulder == ButtonState.Pressed);
IsResetKeyDown = ((IsKeyDown(Keys.LeftControl) || IsKeyDown(Keys.RightControl)) && IsKeyDown(Keys.F12)) ||
((gamePadState.Buttons.LeftStick == ButtonState.Pressed) && (gamePadState.Buttons.Start == ButtonState.Pressed));
IsCpuThrottleKeyDown = IsKeyDown(Keys.F8) || ((IsKeyDown(Keys.ChatPadGreen) || IsKeyDown(Keys.ChatPadOrange)) && IsKeyDown(Keys.D8)); bool control = IsKeyDown(Keys.LeftControl) || IsKeyDown(Keys.RightControl);
IsVideoMonochromeKeyDown = IsKeyDown(Keys.F9) || ((IsKeyDown(Keys.ChatPadGreen) || IsKeyDown(Keys.ChatPadOrange)) && IsKeyDown(Keys.D9));
#else
IsOpenAppleKeyDown = IsKeyDown(Keys.LeftAlt);
IsCloseAppleKeyDown = IsKeyDown(Keys.RightAlt);
IsResetKeyDown = (IsKeyDown(Keys.LeftControl) || IsKeyDown(Keys.RightControl)) && IsKeyDown(Keys.F12);
IsCpuThrottleKeyDown = IsKeyDown(Keys.F8); IsOpenAppleKeyDown = IsKeyDown(Keys.LeftAlt) || IsKeyDown(Keys.NumPad0) || (gamePadState.Buttons.LeftShoulder == ButtonState.Pressed);
IsVideoFullScreenKeyDown = IsKeyDown(Keys.F11); IsCloseAppleKeyDown = IsKeyDown(Keys.RightAlt) || IsKeyDown(Keys.Decimal) || (gamePadState.Buttons.RightShoulder == ButtonState.Pressed);
IsVideoMonochromeKeyDown = IsKeyDown(Keys.F9); IsResetKeyDown = (control && IsKeyDown(Keys.Back)) || (gamePadControl && (gamePadState.Buttons.Start == ButtonState.Pressed));
#endif
base.Update();
} }
private bool IsKeyDown(Keys key) private bool IsKeyDown(Keys key)
@ -101,17 +81,42 @@ private bool IsKeyDown(Keys key)
return _state.IsKeyDown(key); return _state.IsKeyDown(key);
} }
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] private void OnKeyDown(Keys key, bool gamePadControl)
[SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode")]
#if XBOX
private int GetAsciiKey(Keys key, ref GamePadState gamePadState)
{ {
bool control = IsKeyDown(Keys.LeftControl) || IsKeyDown(Keys.RightControl) || (gamePadState.Buttons.LeftStick == ButtonState.Pressed); int asciiKey = GetAsciiKey(key, gamePadControl);
#else if (asciiKey >= 0)
private int GetAsciiKey(Keys key) {
OnAsciiKeyDown(asciiKey);
}
}
private void OnKeyUp(Keys key, bool gamePadControl)
{ {
bool control = IsKeyDown(Keys.LeftControl) || IsKeyDown(Keys.RightControl); bool control = IsKeyDown(Keys.LeftControl) || IsKeyDown(Keys.RightControl);
#endif
if (key == Keys.CapsLock)
{
_capsLock ^= true;
}
else if ((control && (key == Keys.Divide)) || (gamePadControl && (key == Keys.D8)))
{
Machine.Cpu.ToggleThrottle();
}
else if ((control && (key == Keys.Multiply)) || (gamePadControl && (key == Keys.D9)))
{
Machine.Video.ToggleMonochrome();
}
else if ((control && (key == Keys.Subtract)) || (gamePadControl && (key == Keys.D0)))
{
Machine.Video.ToggleFullScreen();
}
}
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
[SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode")]
private int GetAsciiKey(Keys key, bool gamePadControl)
{
bool control = IsKeyDown(Keys.LeftControl) || IsKeyDown(Keys.RightControl) || gamePadControl;
bool shift = IsKeyDown(Keys.LeftShift) || IsKeyDown(Keys.RightShift); bool shift = IsKeyDown(Keys.LeftShift) || IsKeyDown(Keys.RightShift);
bool capsLock = shift ^ _capsLock; bool capsLock = shift ^ _capsLock;
bool green = IsKeyDown(Keys.ChatPadGreen); bool green = IsKeyDown(Keys.ChatPadGreen);
@ -141,7 +146,7 @@ private int GetAsciiKey(Keys key)
return 0x1B; return 0x1B;
case Keys.Back: case Keys.Back:
return 0x7F; return control ? -1 : 0x7F;
case Keys.Space: case Keys.Space:
return ' '; return ' ';
@ -168,13 +173,13 @@ private int GetAsciiKey(Keys key)
return shift ? '&' : '7'; return shift ? '&' : '7';
case Keys.D8: case Keys.D8:
return shift ? '*' : '8'; return gamePadControl ? -1 : shift ? '*' : '8';
case Keys.D9: case Keys.D9:
return shift ? '(' : '9'; return gamePadControl ? -1 : shift ? '(' : '9';
case Keys.D0: case Keys.D0:
return shift ? ')' : '0'; return gamePadControl ? -1 : shift ? ')' : '0';
case Keys.A: case Keys.A:
return control ? 0x01 : green ? '~' : capsLock ? 'A' : 'a'; return control ? 0x01 : green ? '~' : capsLock ? 'A' : 'a';
@ -287,51 +292,6 @@ private int GetAsciiKey(Keys key)
case Keys.OemPeriod: case Keys.OemPeriod:
return shift ? '>' : green ? '?' : '.'; return shift ? '>' : green ? '?' : '.';
case Keys.NumPad1:
return '1';
case Keys.NumPad2:
return '2';
case Keys.NumPad3:
return '3';
case Keys.NumPad4:
return '4';
case Keys.NumPad5:
return '5';
case Keys.NumPad6:
return '6';
case Keys.NumPad7:
return '7';
case Keys.NumPad8:
return '8';
case Keys.NumPad9:
return '9';
case Keys.NumPad0:
return '0';
case Keys.Decimal:
return '.';
case Keys.Divide:
return '/';
case Keys.Multiply:
return '*';
case Keys.Subtract:
return '-';
case Keys.Add:
return '+';
} }
return -1; return -1;

View File

@ -30,7 +30,7 @@ public override void SetPixel(int x, int y, uint color)
_pixelsDirty = true; _pixelsDirty = true;
} }
public override void Update() public override void Update() // main thread
{ {
if (_game.GraphicsDeviceManager.IsFullScreen != IsFullScreen) if (_game.GraphicsDeviceManager.IsFullScreen != IsFullScreen)
{ {