Deleted all svn:eol-style properties on files.
--HG-- extra : convert_revision : svn%3Affd33b8c-2492-42e0-bdc5-587b920b7d6d/trunk%4050811
This commit is contained in:
parent
ee4c69dddf
commit
365e5723c1
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Dictionary>
|
||||
<Words>
|
||||
<Recognized>
|
||||
<Word>Alloc</Word>
|
||||
</Recognized>
|
||||
</Words>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Dictionary>
|
||||
<Words>
|
||||
<Recognized>
|
||||
<Word>Alloc</Word>
|
||||
</Recognized>
|
||||
</Words>
|
||||
</Dictionary>
|
|
@ -1,173 +1,173 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Threading;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public sealed partial class DirectSound : IDisposable
|
||||
{
|
||||
[SecurityCritical]
|
||||
public DirectSound(int sampleRate, int sampleChannels, int sampleBits, int sampleSize, Action<IntPtr, int> updater)
|
||||
{
|
||||
_sampleRate = sampleRate;
|
||||
_sampleChannels = sampleChannels;
|
||||
_sampleBits = sampleBits;
|
||||
_sampleSize = sampleSize;
|
||||
|
||||
_thread = new Thread(Run) { Name = "DirectSound" };
|
||||
_updater = updater;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_position1Event.Close();
|
||||
_position2Event.Close();
|
||||
_stopEvent.Close();
|
||||
}
|
||||
|
||||
public void SetVolume(double volume)
|
||||
{
|
||||
int attenuation = (volume < 0.01) ? (int)BufferVolume.Min : (int)Math.Floor(100 * 20 * Math.Log10(volume)); // 100 db
|
||||
lock (_bufferLock)
|
||||
{
|
||||
if (_buffer != null)
|
||||
{
|
||||
_buffer.SetVolume(attenuation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Start(IntPtr window)
|
||||
{
|
||||
_window = window;
|
||||
_thread.Start();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_stopEvent.Set();
|
||||
_thread.Join();
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
private void Initialize()
|
||||
{
|
||||
int hresult = NativeMethods.DirectSoundCreate(IntPtr.Zero, out _device, IntPtr.Zero);
|
||||
if (hresult < 0)
|
||||
{
|
||||
Marshal.ThrowExceptionForHR(hresult);
|
||||
}
|
||||
|
||||
_device.SetCooperativeLevel(_window, CooperativeLevel.Normal);
|
||||
|
||||
GCHandleHelpers.Pin(new WaveFormat(_sampleRate, _sampleChannels, _sampleBits), waveFormat =>
|
||||
{
|
||||
var description = new BufferDescription(BufferCapabilities.CtrlPositionNotify | BufferCapabilities.CtrlVolume, BlockCount * _sampleSize, waveFormat);
|
||||
_device.CreateSoundBuffer(description, out _buffer, IntPtr.Zero);
|
||||
});
|
||||
ClearBuffer();
|
||||
|
||||
var positionEvents = new BufferPositionNotify[BlockCount]
|
||||
{
|
||||
new BufferPositionNotify(0 * _sampleSize, _position1Event), new BufferPositionNotify(1 * _sampleSize, _position2Event)
|
||||
};
|
||||
((IDirectSoundNotify)_buffer).SetNotificationPositions(positionEvents.Length, positionEvents);
|
||||
|
||||
_buffer.Play(0, 0, BufferPlay.Looping);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
private void ClearBuffer()
|
||||
{
|
||||
UpdateBuffer(0, 0, BufferLock.EntireBuffer, (buffer, bufferSize) => MarshalHelpers.ZeroMemory(buffer, bufferSize));
|
||||
}
|
||||
|
||||
private void RestoreBuffer()
|
||||
{
|
||||
BufferStatus status;
|
||||
_buffer.GetStatus(out status);
|
||||
if ((status & BufferStatus.BufferLost) != 0)
|
||||
{
|
||||
_buffer.Restore();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateBuffer(int offset, int count, BufferLock flags, Action<IntPtr, int> updater)
|
||||
{
|
||||
RestoreBuffer();
|
||||
|
||||
IntPtr buffer1, buffer2;
|
||||
int buffer1Size, buffer2Size;
|
||||
_buffer.Lock(offset, count, out buffer1, out buffer1Size, out buffer2, out buffer2Size, flags);
|
||||
try
|
||||
{
|
||||
if (buffer1 != IntPtr.Zero)
|
||||
{
|
||||
updater(buffer1, buffer1Size);
|
||||
}
|
||||
if (buffer2 != IntPtr.Zero)
|
||||
{
|
||||
updater(buffer2, buffer2Size);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_buffer.Unlock(buffer1, buffer1Size, buffer2, buffer2Size);
|
||||
}
|
||||
}
|
||||
|
||||
private void Uninitialize()
|
||||
{
|
||||
lock (_bufferLock)
|
||||
{
|
||||
if (_buffer != null)
|
||||
{
|
||||
_buffer.Stop();
|
||||
Marshal.ReleaseComObject(_buffer);
|
||||
_buffer = null;
|
||||
}
|
||||
}
|
||||
if (_device != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(_device);
|
||||
_device = null;
|
||||
}
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
private void Run() // com mta thread
|
||||
{
|
||||
Initialize();
|
||||
|
||||
var eventHandles = new EventWaitHandle[] { _position1Event, _position2Event, _stopEvent };
|
||||
int index = WaitHandle.WaitAny(eventHandles);
|
||||
|
||||
while (index < BlockCount)
|
||||
{
|
||||
UpdateBuffer(((index + 1) % BlockCount) * _sampleSize, _sampleSize, BufferLock.None, _updater); // update next block in circular buffer
|
||||
index = WaitHandle.WaitAny(eventHandles);
|
||||
}
|
||||
|
||||
Uninitialize();
|
||||
}
|
||||
|
||||
private const int BlockCount = 2;
|
||||
|
||||
private int _sampleRate;
|
||||
private int _sampleChannels;
|
||||
private int _sampleBits;
|
||||
private int _sampleSize;
|
||||
|
||||
private Thread _thread;
|
||||
private IntPtr _window;
|
||||
private IDirectSound _device;
|
||||
private IDirectSoundBuffer _buffer;
|
||||
private object _bufferLock = new object();
|
||||
private Action<IntPtr, int> _updater;
|
||||
|
||||
private AutoResetEvent _position1Event = new AutoResetEvent(false);
|
||||
private AutoResetEvent _position2Event = new AutoResetEvent(false);
|
||||
private ManualResetEvent _stopEvent = new ManualResetEvent(false);
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Threading;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public sealed partial class DirectSound : IDisposable
|
||||
{
|
||||
[SecurityCritical]
|
||||
public DirectSound(int sampleRate, int sampleChannels, int sampleBits, int sampleSize, Action<IntPtr, int> updater)
|
||||
{
|
||||
_sampleRate = sampleRate;
|
||||
_sampleChannels = sampleChannels;
|
||||
_sampleBits = sampleBits;
|
||||
_sampleSize = sampleSize;
|
||||
|
||||
_thread = new Thread(Run) { Name = "DirectSound" };
|
||||
_updater = updater;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_position1Event.Close();
|
||||
_position2Event.Close();
|
||||
_stopEvent.Close();
|
||||
}
|
||||
|
||||
public void SetVolume(double volume)
|
||||
{
|
||||
int attenuation = (volume < 0.01) ? (int)BufferVolume.Min : (int)Math.Floor(100 * 20 * Math.Log10(volume)); // 100 db
|
||||
lock (_bufferLock)
|
||||
{
|
||||
if (_buffer != null)
|
||||
{
|
||||
_buffer.SetVolume(attenuation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Start(IntPtr window)
|
||||
{
|
||||
_window = window;
|
||||
_thread.Start();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_stopEvent.Set();
|
||||
_thread.Join();
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
private void Initialize()
|
||||
{
|
||||
int hresult = NativeMethods.DirectSoundCreate(IntPtr.Zero, out _device, IntPtr.Zero);
|
||||
if (hresult < 0)
|
||||
{
|
||||
Marshal.ThrowExceptionForHR(hresult);
|
||||
}
|
||||
|
||||
_device.SetCooperativeLevel(_window, CooperativeLevel.Normal);
|
||||
|
||||
GCHandleHelpers.Pin(new WaveFormat(_sampleRate, _sampleChannels, _sampleBits), waveFormat =>
|
||||
{
|
||||
var description = new BufferDescription(BufferCapabilities.CtrlPositionNotify | BufferCapabilities.CtrlVolume, BlockCount * _sampleSize, waveFormat);
|
||||
_device.CreateSoundBuffer(description, out _buffer, IntPtr.Zero);
|
||||
});
|
||||
ClearBuffer();
|
||||
|
||||
var positionEvents = new BufferPositionNotify[BlockCount]
|
||||
{
|
||||
new BufferPositionNotify(0 * _sampleSize, _position1Event), new BufferPositionNotify(1 * _sampleSize, _position2Event)
|
||||
};
|
||||
((IDirectSoundNotify)_buffer).SetNotificationPositions(positionEvents.Length, positionEvents);
|
||||
|
||||
_buffer.Play(0, 0, BufferPlay.Looping);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
private void ClearBuffer()
|
||||
{
|
||||
UpdateBuffer(0, 0, BufferLock.EntireBuffer, (buffer, bufferSize) => MarshalHelpers.ZeroMemory(buffer, bufferSize));
|
||||
}
|
||||
|
||||
private void RestoreBuffer()
|
||||
{
|
||||
BufferStatus status;
|
||||
_buffer.GetStatus(out status);
|
||||
if ((status & BufferStatus.BufferLost) != 0)
|
||||
{
|
||||
_buffer.Restore();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateBuffer(int offset, int count, BufferLock flags, Action<IntPtr, int> updater)
|
||||
{
|
||||
RestoreBuffer();
|
||||
|
||||
IntPtr buffer1, buffer2;
|
||||
int buffer1Size, buffer2Size;
|
||||
_buffer.Lock(offset, count, out buffer1, out buffer1Size, out buffer2, out buffer2Size, flags);
|
||||
try
|
||||
{
|
||||
if (buffer1 != IntPtr.Zero)
|
||||
{
|
||||
updater(buffer1, buffer1Size);
|
||||
}
|
||||
if (buffer2 != IntPtr.Zero)
|
||||
{
|
||||
updater(buffer2, buffer2Size);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_buffer.Unlock(buffer1, buffer1Size, buffer2, buffer2Size);
|
||||
}
|
||||
}
|
||||
|
||||
private void Uninitialize()
|
||||
{
|
||||
lock (_bufferLock)
|
||||
{
|
||||
if (_buffer != null)
|
||||
{
|
||||
_buffer.Stop();
|
||||
Marshal.ReleaseComObject(_buffer);
|
||||
_buffer = null;
|
||||
}
|
||||
}
|
||||
if (_device != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(_device);
|
||||
_device = null;
|
||||
}
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
private void Run() // com mta thread
|
||||
{
|
||||
Initialize();
|
||||
|
||||
var eventHandles = new EventWaitHandle[] { _position1Event, _position2Event, _stopEvent };
|
||||
int index = WaitHandle.WaitAny(eventHandles);
|
||||
|
||||
while (index < BlockCount)
|
||||
{
|
||||
UpdateBuffer(((index + 1) % BlockCount) * _sampleSize, _sampleSize, BufferLock.None, _updater); // update next block in circular buffer
|
||||
index = WaitHandle.WaitAny(eventHandles);
|
||||
}
|
||||
|
||||
Uninitialize();
|
||||
}
|
||||
|
||||
private const int BlockCount = 2;
|
||||
|
||||
private int _sampleRate;
|
||||
private int _sampleChannels;
|
||||
private int _sampleBits;
|
||||
private int _sampleSize;
|
||||
|
||||
private Thread _thread;
|
||||
private IntPtr _window;
|
||||
private IDirectSound _device;
|
||||
private IDirectSoundBuffer _buffer;
|
||||
private object _bufferLock = new object();
|
||||
private Action<IntPtr, int> _updater;
|
||||
|
||||
private AutoResetEvent _position1Event = new AutoResetEvent(false);
|
||||
private AutoResetEvent _position2Event = new AutoResetEvent(false);
|
||||
private ManualResetEvent _stopEvent = new ManualResetEvent(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,110 +1,110 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Threading;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public sealed partial class DirectSound
|
||||
{
|
||||
[Flags]
|
||||
private enum BufferCapabilities { PrimaryBuffer = 0x00000001, CtrlVolume = 0x00000080, CtrlPositionNotify = 0x00000100, StickyFocus = 0x00004000, GlobalFocus = 0x00008000 }
|
||||
|
||||
[Flags]
|
||||
private enum BufferLock { None = 0x00000000, FromWriteCursor = 0x00000001, EntireBuffer = 0x00000002 }
|
||||
|
||||
[Flags]
|
||||
private enum BufferPlay { Looping = 0x00000001 }
|
||||
|
||||
[Flags]
|
||||
private enum BufferStatus { Playing = 0x00000001, BufferLost = 0x00000002, Looping = 0x00000004, Terminated = 0x00000020 }
|
||||
|
||||
private enum BufferVolume { Min = -10000, Max = 0 }
|
||||
|
||||
private enum CooperativeLevel { Normal = 1, Priority = 2 }
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private sealed class BufferDescription
|
||||
{
|
||||
public BufferDescription(BufferCapabilities capabilities, int size, IntPtr format)
|
||||
{
|
||||
dwSize = Marshal.SizeOf(typeof(BufferDescription));
|
||||
dwFlags = capabilities;
|
||||
dwBufferBytes = size;
|
||||
lpwfxFormat = format;
|
||||
}
|
||||
|
||||
public int dwSize;
|
||||
public BufferCapabilities dwFlags;
|
||||
public int dwBufferBytes;
|
||||
public int dwReserved;
|
||||
public IntPtr lpwfxFormat;
|
||||
public Guid guid3DAlgorithm;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct BufferPositionNotify
|
||||
{
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Runtime.InteropServices.SafeHandle.DangerousGetHandle")]
|
||||
public BufferPositionNotify(int offset, EventWaitHandle notifyEvent)
|
||||
{
|
||||
dwOffset = offset;
|
||||
hEventNotify = notifyEvent.SafeWaitHandle.DangerousGetHandle();
|
||||
}
|
||||
|
||||
public int dwOffset;
|
||||
public IntPtr hEventNotify;
|
||||
}
|
||||
|
||||
[ComImport, Guid("279AFA83-4981-11CE-A521-0020AF0BE560"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
private interface IDirectSound
|
||||
{
|
||||
void CreateSoundBuffer(BufferDescription pcDSBufferDesc, [MarshalAs(UnmanagedType.Interface)] out IDirectSoundBuffer pDSBuffer, IntPtr pUnkOuter);
|
||||
void GetCaps(IntPtr pDSCaps);
|
||||
void DuplicateSoundBuffer([MarshalAs(UnmanagedType.Interface)] IDirectSoundBuffer pDSBufferOriginal, [MarshalAs(UnmanagedType.Interface)] out IDirectSoundBuffer pDSBufferDuplicate);
|
||||
void SetCooperativeLevel(IntPtr hwnd, CooperativeLevel dwLevel);
|
||||
void Compact();
|
||||
void GetSpeakerConfig(out int dwSpeakerConfig);
|
||||
void SetSpeakerConfig(int dwSpeakerConfig);
|
||||
void Initialize([MarshalAs(UnmanagedType.LPStruct)] Guid pcGuidDevice);
|
||||
}
|
||||
|
||||
[ComImport, Guid("279AFA85-4981-11CE-A521-0020AF0BE560"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
private interface IDirectSoundBuffer
|
||||
{
|
||||
void GetCaps(IntPtr pDSBufferCaps);
|
||||
void GetCurrentPosition(out int dwCurrentPlayCursor, out int dwCurrentWriteCursor);
|
||||
void GetFormat(IntPtr pwfxFormat, int dwSizeAllocated, out int dwSizeWritten);
|
||||
void GetVolume(out int lVolume);
|
||||
void GetPan(out int lPan);
|
||||
void GetFrequency(out int dwFrequency);
|
||||
void GetStatus(out BufferStatus dwStatus);
|
||||
void Initialize([MarshalAs(UnmanagedType.Interface)] IDirectSound pDirectSound, BufferDescription pcDSBufferDesc);
|
||||
void Lock(int dwOffset, int dwBytes, out IntPtr pvAudioPtr1, out int dwAudioBytes1, out IntPtr pvAudioPtr2, out int dwAudioBytes2, BufferLock dwFlags);
|
||||
void Play(int dwReserved1, int dwPriority, BufferPlay dwFlags);
|
||||
void SetCurrentPosition(int dwNewPosition);
|
||||
void SetFormat(WaveFormat pcfxFormat);
|
||||
void SetVolume(int lVolume);
|
||||
void SetPan(int lPan);
|
||||
void SetFrequency(int dwFrequency);
|
||||
void Stop();
|
||||
void Unlock(IntPtr pvAudioPtr1, int dwAudioBytes1, IntPtr pvAudioPtr2, int dwAudioBytes2);
|
||||
void Restore();
|
||||
}
|
||||
|
||||
[ComImport, Guid("B0210783-89CD-11D0-AF08-00A0C925CD16"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
private interface IDirectSoundNotify
|
||||
{
|
||||
void SetNotificationPositions(int dwPositionNotifies, [MarshalAs(UnmanagedType.LPArray)] BufferPositionNotify[] pcPositionNotifies);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
private static class NativeMethods
|
||||
{
|
||||
[DllImport("dsound.dll")]
|
||||
public static extern int DirectSoundCreate(IntPtr pcGuidDevice, [MarshalAs(UnmanagedType.Interface)] out IDirectSound pDS, IntPtr pUnkOuter);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Threading;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public sealed partial class DirectSound
|
||||
{
|
||||
[Flags]
|
||||
private enum BufferCapabilities { PrimaryBuffer = 0x00000001, CtrlVolume = 0x00000080, CtrlPositionNotify = 0x00000100, StickyFocus = 0x00004000, GlobalFocus = 0x00008000 }
|
||||
|
||||
[Flags]
|
||||
private enum BufferLock { None = 0x00000000, FromWriteCursor = 0x00000001, EntireBuffer = 0x00000002 }
|
||||
|
||||
[Flags]
|
||||
private enum BufferPlay { Looping = 0x00000001 }
|
||||
|
||||
[Flags]
|
||||
private enum BufferStatus { Playing = 0x00000001, BufferLost = 0x00000002, Looping = 0x00000004, Terminated = 0x00000020 }
|
||||
|
||||
private enum BufferVolume { Min = -10000, Max = 0 }
|
||||
|
||||
private enum CooperativeLevel { Normal = 1, Priority = 2 }
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private sealed class BufferDescription
|
||||
{
|
||||
public BufferDescription(BufferCapabilities capabilities, int size, IntPtr format)
|
||||
{
|
||||
dwSize = Marshal.SizeOf(typeof(BufferDescription));
|
||||
dwFlags = capabilities;
|
||||
dwBufferBytes = size;
|
||||
lpwfxFormat = format;
|
||||
}
|
||||
|
||||
public int dwSize;
|
||||
public BufferCapabilities dwFlags;
|
||||
public int dwBufferBytes;
|
||||
public int dwReserved;
|
||||
public IntPtr lpwfxFormat;
|
||||
public Guid guid3DAlgorithm;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct BufferPositionNotify
|
||||
{
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Runtime.InteropServices.SafeHandle.DangerousGetHandle")]
|
||||
public BufferPositionNotify(int offset, EventWaitHandle notifyEvent)
|
||||
{
|
||||
dwOffset = offset;
|
||||
hEventNotify = notifyEvent.SafeWaitHandle.DangerousGetHandle();
|
||||
}
|
||||
|
||||
public int dwOffset;
|
||||
public IntPtr hEventNotify;
|
||||
}
|
||||
|
||||
[ComImport, Guid("279AFA83-4981-11CE-A521-0020AF0BE560"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
private interface IDirectSound
|
||||
{
|
||||
void CreateSoundBuffer(BufferDescription pcDSBufferDesc, [MarshalAs(UnmanagedType.Interface)] out IDirectSoundBuffer pDSBuffer, IntPtr pUnkOuter);
|
||||
void GetCaps(IntPtr pDSCaps);
|
||||
void DuplicateSoundBuffer([MarshalAs(UnmanagedType.Interface)] IDirectSoundBuffer pDSBufferOriginal, [MarshalAs(UnmanagedType.Interface)] out IDirectSoundBuffer pDSBufferDuplicate);
|
||||
void SetCooperativeLevel(IntPtr hwnd, CooperativeLevel dwLevel);
|
||||
void Compact();
|
||||
void GetSpeakerConfig(out int dwSpeakerConfig);
|
||||
void SetSpeakerConfig(int dwSpeakerConfig);
|
||||
void Initialize([MarshalAs(UnmanagedType.LPStruct)] Guid pcGuidDevice);
|
||||
}
|
||||
|
||||
[ComImport, Guid("279AFA85-4981-11CE-A521-0020AF0BE560"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
private interface IDirectSoundBuffer
|
||||
{
|
||||
void GetCaps(IntPtr pDSBufferCaps);
|
||||
void GetCurrentPosition(out int dwCurrentPlayCursor, out int dwCurrentWriteCursor);
|
||||
void GetFormat(IntPtr pwfxFormat, int dwSizeAllocated, out int dwSizeWritten);
|
||||
void GetVolume(out int lVolume);
|
||||
void GetPan(out int lPan);
|
||||
void GetFrequency(out int dwFrequency);
|
||||
void GetStatus(out BufferStatus dwStatus);
|
||||
void Initialize([MarshalAs(UnmanagedType.Interface)] IDirectSound pDirectSound, BufferDescription pcDSBufferDesc);
|
||||
void Lock(int dwOffset, int dwBytes, out IntPtr pvAudioPtr1, out int dwAudioBytes1, out IntPtr pvAudioPtr2, out int dwAudioBytes2, BufferLock dwFlags);
|
||||
void Play(int dwReserved1, int dwPriority, BufferPlay dwFlags);
|
||||
void SetCurrentPosition(int dwNewPosition);
|
||||
void SetFormat(WaveFormat pcfxFormat);
|
||||
void SetVolume(int lVolume);
|
||||
void SetPan(int lPan);
|
||||
void SetFrequency(int dwFrequency);
|
||||
void Stop();
|
||||
void Unlock(IntPtr pvAudioPtr1, int dwAudioBytes1, IntPtr pvAudioPtr2, int dwAudioBytes2);
|
||||
void Restore();
|
||||
}
|
||||
|
||||
[ComImport, Guid("B0210783-89CD-11D0-AF08-00A0C925CD16"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
private interface IDirectSoundNotify
|
||||
{
|
||||
void SetNotificationPositions(int dwPositionNotifies, [MarshalAs(UnmanagedType.LPArray)] BufferPositionNotify[] pcPositionNotifies);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
private static class NativeMethods
|
||||
{
|
||||
[DllImport("dsound.dll")]
|
||||
public static extern int DirectSoundCreate(IntPtr pcGuidDevice, [MarshalAs(UnmanagedType.Interface)] out IDirectSound pDS, IntPtr pUnkOuter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,52 +1,52 @@
|
|||
using System;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class DispatcherExtensions
|
||||
{
|
||||
public static void CheckBeginInvoke(this Dispatcher dispatcher, Action action)
|
||||
{
|
||||
if (dispatcher == null)
|
||||
{
|
||||
throw new ArgumentNullException("dispatcher");
|
||||
}
|
||||
if (action == null)
|
||||
{
|
||||
throw new ArgumentNullException("action");
|
||||
}
|
||||
|
||||
if (dispatcher.CheckAccess())
|
||||
{
|
||||
action();
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatcher.BeginInvoke(action);
|
||||
}
|
||||
}
|
||||
|
||||
#if WINDOWS
|
||||
public static void CheckInvoke(this Dispatcher dispatcher, Action action)
|
||||
{
|
||||
if (dispatcher == null)
|
||||
{
|
||||
throw new ArgumentNullException("dispatcher");
|
||||
}
|
||||
if (action == null)
|
||||
{
|
||||
throw new ArgumentNullException("action");
|
||||
}
|
||||
|
||||
if (dispatcher.CheckAccess())
|
||||
{
|
||||
action();
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatcher.Invoke(action);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class DispatcherExtensions
|
||||
{
|
||||
public static void CheckBeginInvoke(this Dispatcher dispatcher, Action action)
|
||||
{
|
||||
if (dispatcher == null)
|
||||
{
|
||||
throw new ArgumentNullException("dispatcher");
|
||||
}
|
||||
if (action == null)
|
||||
{
|
||||
throw new ArgumentNullException("action");
|
||||
}
|
||||
|
||||
if (dispatcher.CheckAccess())
|
||||
{
|
||||
action();
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatcher.BeginInvoke(action);
|
||||
}
|
||||
}
|
||||
|
||||
#if WINDOWS
|
||||
public static void CheckInvoke(this Dispatcher dispatcher, Action action)
|
||||
{
|
||||
if (dispatcher == null)
|
||||
{
|
||||
throw new ArgumentNullException("dispatcher");
|
||||
}
|
||||
if (action == null)
|
||||
{
|
||||
throw new ArgumentNullException("action");
|
||||
}
|
||||
|
||||
if (dispatcher.CheckAccess())
|
||||
{
|
||||
action();
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatcher.Invoke(action);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class GCHandleHelpers
|
||||
{
|
||||
[SecurityCritical]
|
||||
public static void Pin(object value, Action<IntPtr> action)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
throw new ArgumentNullException("action");
|
||||
}
|
||||
|
||||
var gcHandle = new GCHandle();
|
||||
try
|
||||
{
|
||||
gcHandle = GCHandle.Alloc(value, GCHandleType.Pinned);
|
||||
action(gcHandle.AddrOfPinnedObject());
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (gcHandle.IsAllocated)
|
||||
{
|
||||
gcHandle.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class GCHandleHelpers
|
||||
{
|
||||
[SecurityCritical]
|
||||
public static void Pin(object value, Action<IntPtr> action)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
throw new ArgumentNullException("action");
|
||||
}
|
||||
|
||||
var gcHandle = new GCHandle();
|
||||
try
|
||||
{
|
||||
gcHandle = GCHandle.Alloc(value, GCHandleType.Pinned);
|
||||
action(gcHandle.AddrOfPinnedObject());
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (gcHandle.IsAllocated)
|
||||
{
|
||||
gcHandle.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,266 +1,266 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.AccessControl;
|
||||
using System.Security.Principal;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class SecurityAttributes
|
||||
{
|
||||
public SecurityAttributes()
|
||||
{
|
||||
_length = Marshal.SizeOf(typeof(SecurityAttributes));
|
||||
}
|
||||
|
||||
public int Length { get { return _length; } }
|
||||
public IntPtr SecurityDescriptor { get { return _securityDescriptor; } set { _securityDescriptor = value; } }
|
||||
public bool InheritHandle { get { return _inheritHandle; } set { _inheritHandle = value; } }
|
||||
|
||||
private int _length;
|
||||
private IntPtr _securityDescriptor;
|
||||
private bool _inheritHandle;
|
||||
}
|
||||
|
||||
public sealed class GeneralAccessRule : AccessRule
|
||||
{
|
||||
public GeneralAccessRule(IdentityReference identity, int rights, AccessControlType type) :
|
||||
base(identity, rights, false, InheritanceFlags.None, PropagationFlags.None, type)
|
||||
{
|
||||
}
|
||||
|
||||
public GeneralAccessRule(IdentityReference identity, int rights, InheritanceFlags inheritance, PropagationFlags propagation, AccessControlType type) :
|
||||
base(identity, rights, false, inheritance, propagation, type)
|
||||
{
|
||||
}
|
||||
|
||||
public GeneralAccessRule(IdentityReference identity, int rights, bool isInherited, InheritanceFlags inheritance, PropagationFlags propagation, AccessControlType type) :
|
||||
base(identity, rights, isInherited, inheritance, propagation, type)
|
||||
{
|
||||
}
|
||||
|
||||
public int AccessRights { get { return AccessMask; } }
|
||||
}
|
||||
|
||||
public sealed class GeneralAuditRule : AuditRule
|
||||
{
|
||||
public GeneralAuditRule(IdentityReference identity, int rights, AuditFlags audit) :
|
||||
base(identity, rights, false, InheritanceFlags.None, PropagationFlags.None, audit)
|
||||
{
|
||||
}
|
||||
|
||||
public GeneralAuditRule(IdentityReference identity, int rights, InheritanceFlags inheritance, PropagationFlags propagation, AuditFlags audit) :
|
||||
base(identity, rights, false, inheritance, propagation, audit)
|
||||
{
|
||||
}
|
||||
|
||||
public GeneralAuditRule(IdentityReference identity, int rights, bool isInherited, InheritanceFlags inheritance, PropagationFlags propagation, AuditFlags audit) :
|
||||
base(identity, rights, isInherited, inheritance, propagation, audit)
|
||||
{
|
||||
}
|
||||
|
||||
public int AccessRights { get { return AccessMask; } }
|
||||
}
|
||||
|
||||
public sealed class GeneralSecurity : NativeObjectSecurity
|
||||
{
|
||||
public GeneralSecurity(bool isContainer, ResourceType resourceType) :
|
||||
base(isContainer, resourceType)
|
||||
{
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
public GeneralSecurity(bool isContainer, ResourceType resourceType, SafeHandle handle, AccessControlSections includeSections = AccessControlSections.Access | AccessControlSections.Group | AccessControlSections.Owner) :
|
||||
base(isContainer, resourceType, handle, includeSections)
|
||||
{
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
public GeneralSecurity(bool isContainer, ResourceType resourceType, string name, AccessControlSections includeSections = AccessControlSections.Access | AccessControlSections.Group | AccessControlSections.Owner) :
|
||||
base(isContainer, resourceType, name, includeSections)
|
||||
{
|
||||
}
|
||||
|
||||
public override AccessRule AccessRuleFactory(IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type)
|
||||
{
|
||||
return new GeneralAccessRule(identityReference, accessMask, isInherited, inheritanceFlags, propagationFlags, type);
|
||||
}
|
||||
|
||||
public override AuditRule AuditRuleFactory(IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags)
|
||||
{
|
||||
return new GeneralAuditRule(identityReference, accessMask, isInherited, inheritanceFlags, propagationFlags, flags);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void AddAccessRule(GeneralAccessRule rule)
|
||||
{
|
||||
base.AddAccessRule(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void AddAuditRule(GeneralAuditRule rule)
|
||||
{
|
||||
base.AddAuditRule(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
[SecurityCritical]
|
||||
public void GetSecurityAttributes(Action<SecurityAttributes> action, bool inheritable = false)
|
||||
{
|
||||
GetSecurityAttributes(this, action, inheritable);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
[SecurityCritical]
|
||||
public static void GetSecurityAttributes(ObjectSecurity security, Action<SecurityAttributes> action, bool inheritable = false)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
throw new ArgumentNullException("action");
|
||||
}
|
||||
|
||||
if (security != null)
|
||||
{
|
||||
GCHandleHelpers.Pin(security.GetSecurityDescriptorBinaryForm(), securityDescriptor =>
|
||||
{
|
||||
action(new SecurityAttributes() { SecurityDescriptor = securityDescriptor, InheritHandle = inheritable });
|
||||
});
|
||||
}
|
||||
else if (inheritable)
|
||||
{
|
||||
action(new SecurityAttributes() { InheritHandle = inheritable });
|
||||
}
|
||||
else
|
||||
{
|
||||
action(null);
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public bool RemoveAccessRule(GeneralAccessRule rule)
|
||||
{
|
||||
return base.RemoveAccessRule(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void RemoveAccessRuleAll(GeneralAccessRule rule)
|
||||
{
|
||||
base.RemoveAccessRuleAll(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void RemoveAccessRuleSpecific(GeneralAccessRule rule)
|
||||
{
|
||||
base.RemoveAccessRuleSpecific(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public bool RemoveAuditRule(GeneralAuditRule rule)
|
||||
{
|
||||
return base.RemoveAuditRule(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void RemoveAuditRuleAll(GeneralAuditRule rule)
|
||||
{
|
||||
base.RemoveAuditRuleAll(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void RemoveAuditRuleSpecific(GeneralAuditRule rule)
|
||||
{
|
||||
base.RemoveAuditRuleSpecific(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void ResetAccessRule(GeneralAccessRule rule)
|
||||
{
|
||||
base.ResetAccessRule(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void SetAccessRule(GeneralAccessRule rule)
|
||||
{
|
||||
base.SetAccessRule(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void SetAuditRule(GeneralAuditRule rule)
|
||||
{
|
||||
base.SetAuditRule(rule);
|
||||
}
|
||||
|
||||
public void Persist(SafeHandle handle)
|
||||
{
|
||||
WriteLock();
|
||||
try
|
||||
{
|
||||
var sectionsModified = GetAccessControlSectionsModified();
|
||||
if (sectionsModified != AccessControlSections.None)
|
||||
{
|
||||
Persist(handle, sectionsModified);
|
||||
ResetAccessControlSectionsModified();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
WriteUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void Persist(string name)
|
||||
{
|
||||
WriteLock();
|
||||
try
|
||||
{
|
||||
var sectionsModified = GetAccessControlSectionsModified();
|
||||
if (sectionsModified != AccessControlSections.None)
|
||||
{
|
||||
Persist(name, sectionsModified);
|
||||
ResetAccessControlSectionsModified();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
WriteUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
private AccessControlSections GetAccessControlSectionsModified()
|
||||
{
|
||||
var sectionsModified = AccessControlSections.None;
|
||||
if (AccessRulesModified)
|
||||
{
|
||||
sectionsModified = AccessControlSections.Access;
|
||||
}
|
||||
if (AuditRulesModified)
|
||||
{
|
||||
sectionsModified |= AccessControlSections.Audit;
|
||||
}
|
||||
if (OwnerModified)
|
||||
{
|
||||
sectionsModified |= AccessControlSections.Owner;
|
||||
}
|
||||
if (GroupModified)
|
||||
{
|
||||
sectionsModified |= AccessControlSections.Group;
|
||||
}
|
||||
|
||||
return sectionsModified;
|
||||
}
|
||||
|
||||
private void ResetAccessControlSectionsModified()
|
||||
{
|
||||
AccessRulesModified = false;
|
||||
AuditRulesModified = false;
|
||||
OwnerModified = false;
|
||||
GroupModified = false;
|
||||
}
|
||||
|
||||
public override Type AccessRightType { get { return typeof(int); } }
|
||||
public override Type AccessRuleType { get { return typeof(GeneralAccessRule); } }
|
||||
public override Type AuditRuleType { get { return typeof(GeneralAuditRule); } }
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.AccessControl;
|
||||
using System.Security.Principal;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class SecurityAttributes
|
||||
{
|
||||
public SecurityAttributes()
|
||||
{
|
||||
_length = Marshal.SizeOf(typeof(SecurityAttributes));
|
||||
}
|
||||
|
||||
public int Length { get { return _length; } }
|
||||
public IntPtr SecurityDescriptor { get { return _securityDescriptor; } set { _securityDescriptor = value; } }
|
||||
public bool InheritHandle { get { return _inheritHandle; } set { _inheritHandle = value; } }
|
||||
|
||||
private int _length;
|
||||
private IntPtr _securityDescriptor;
|
||||
private bool _inheritHandle;
|
||||
}
|
||||
|
||||
public sealed class GeneralAccessRule : AccessRule
|
||||
{
|
||||
public GeneralAccessRule(IdentityReference identity, int rights, AccessControlType type) :
|
||||
base(identity, rights, false, InheritanceFlags.None, PropagationFlags.None, type)
|
||||
{
|
||||
}
|
||||
|
||||
public GeneralAccessRule(IdentityReference identity, int rights, InheritanceFlags inheritance, PropagationFlags propagation, AccessControlType type) :
|
||||
base(identity, rights, false, inheritance, propagation, type)
|
||||
{
|
||||
}
|
||||
|
||||
public GeneralAccessRule(IdentityReference identity, int rights, bool isInherited, InheritanceFlags inheritance, PropagationFlags propagation, AccessControlType type) :
|
||||
base(identity, rights, isInherited, inheritance, propagation, type)
|
||||
{
|
||||
}
|
||||
|
||||
public int AccessRights { get { return AccessMask; } }
|
||||
}
|
||||
|
||||
public sealed class GeneralAuditRule : AuditRule
|
||||
{
|
||||
public GeneralAuditRule(IdentityReference identity, int rights, AuditFlags audit) :
|
||||
base(identity, rights, false, InheritanceFlags.None, PropagationFlags.None, audit)
|
||||
{
|
||||
}
|
||||
|
||||
public GeneralAuditRule(IdentityReference identity, int rights, InheritanceFlags inheritance, PropagationFlags propagation, AuditFlags audit) :
|
||||
base(identity, rights, false, inheritance, propagation, audit)
|
||||
{
|
||||
}
|
||||
|
||||
public GeneralAuditRule(IdentityReference identity, int rights, bool isInherited, InheritanceFlags inheritance, PropagationFlags propagation, AuditFlags audit) :
|
||||
base(identity, rights, isInherited, inheritance, propagation, audit)
|
||||
{
|
||||
}
|
||||
|
||||
public int AccessRights { get { return AccessMask; } }
|
||||
}
|
||||
|
||||
public sealed class GeneralSecurity : NativeObjectSecurity
|
||||
{
|
||||
public GeneralSecurity(bool isContainer, ResourceType resourceType) :
|
||||
base(isContainer, resourceType)
|
||||
{
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
public GeneralSecurity(bool isContainer, ResourceType resourceType, SafeHandle handle, AccessControlSections includeSections = AccessControlSections.Access | AccessControlSections.Group | AccessControlSections.Owner) :
|
||||
base(isContainer, resourceType, handle, includeSections)
|
||||
{
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
public GeneralSecurity(bool isContainer, ResourceType resourceType, string name, AccessControlSections includeSections = AccessControlSections.Access | AccessControlSections.Group | AccessControlSections.Owner) :
|
||||
base(isContainer, resourceType, name, includeSections)
|
||||
{
|
||||
}
|
||||
|
||||
public override AccessRule AccessRuleFactory(IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type)
|
||||
{
|
||||
return new GeneralAccessRule(identityReference, accessMask, isInherited, inheritanceFlags, propagationFlags, type);
|
||||
}
|
||||
|
||||
public override AuditRule AuditRuleFactory(IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags)
|
||||
{
|
||||
return new GeneralAuditRule(identityReference, accessMask, isInherited, inheritanceFlags, propagationFlags, flags);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void AddAccessRule(GeneralAccessRule rule)
|
||||
{
|
||||
base.AddAccessRule(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void AddAuditRule(GeneralAuditRule rule)
|
||||
{
|
||||
base.AddAuditRule(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
[SecurityCritical]
|
||||
public void GetSecurityAttributes(Action<SecurityAttributes> action, bool inheritable = false)
|
||||
{
|
||||
GetSecurityAttributes(this, action, inheritable);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
[SecurityCritical]
|
||||
public static void GetSecurityAttributes(ObjectSecurity security, Action<SecurityAttributes> action, bool inheritable = false)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
throw new ArgumentNullException("action");
|
||||
}
|
||||
|
||||
if (security != null)
|
||||
{
|
||||
GCHandleHelpers.Pin(security.GetSecurityDescriptorBinaryForm(), securityDescriptor =>
|
||||
{
|
||||
action(new SecurityAttributes() { SecurityDescriptor = securityDescriptor, InheritHandle = inheritable });
|
||||
});
|
||||
}
|
||||
else if (inheritable)
|
||||
{
|
||||
action(new SecurityAttributes() { InheritHandle = inheritable });
|
||||
}
|
||||
else
|
||||
{
|
||||
action(null);
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public bool RemoveAccessRule(GeneralAccessRule rule)
|
||||
{
|
||||
return base.RemoveAccessRule(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void RemoveAccessRuleAll(GeneralAccessRule rule)
|
||||
{
|
||||
base.RemoveAccessRuleAll(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void RemoveAccessRuleSpecific(GeneralAccessRule rule)
|
||||
{
|
||||
base.RemoveAccessRuleSpecific(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public bool RemoveAuditRule(GeneralAuditRule rule)
|
||||
{
|
||||
return base.RemoveAuditRule(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void RemoveAuditRuleAll(GeneralAuditRule rule)
|
||||
{
|
||||
base.RemoveAuditRuleAll(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void RemoveAuditRuleSpecific(GeneralAuditRule rule)
|
||||
{
|
||||
base.RemoveAuditRuleSpecific(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void ResetAccessRule(GeneralAccessRule rule)
|
||||
{
|
||||
base.ResetAccessRule(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void SetAccessRule(GeneralAccessRule rule)
|
||||
{
|
||||
base.SetAccessRule(rule);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public void SetAuditRule(GeneralAuditRule rule)
|
||||
{
|
||||
base.SetAuditRule(rule);
|
||||
}
|
||||
|
||||
public void Persist(SafeHandle handle)
|
||||
{
|
||||
WriteLock();
|
||||
try
|
||||
{
|
||||
var sectionsModified = GetAccessControlSectionsModified();
|
||||
if (sectionsModified != AccessControlSections.None)
|
||||
{
|
||||
Persist(handle, sectionsModified);
|
||||
ResetAccessControlSectionsModified();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
WriteUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void Persist(string name)
|
||||
{
|
||||
WriteLock();
|
||||
try
|
||||
{
|
||||
var sectionsModified = GetAccessControlSectionsModified();
|
||||
if (sectionsModified != AccessControlSections.None)
|
||||
{
|
||||
Persist(name, sectionsModified);
|
||||
ResetAccessControlSectionsModified();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
WriteUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
private AccessControlSections GetAccessControlSectionsModified()
|
||||
{
|
||||
var sectionsModified = AccessControlSections.None;
|
||||
if (AccessRulesModified)
|
||||
{
|
||||
sectionsModified = AccessControlSections.Access;
|
||||
}
|
||||
if (AuditRulesModified)
|
||||
{
|
||||
sectionsModified |= AccessControlSections.Audit;
|
||||
}
|
||||
if (OwnerModified)
|
||||
{
|
||||
sectionsModified |= AccessControlSections.Owner;
|
||||
}
|
||||
if (GroupModified)
|
||||
{
|
||||
sectionsModified |= AccessControlSections.Group;
|
||||
}
|
||||
|
||||
return sectionsModified;
|
||||
}
|
||||
|
||||
private void ResetAccessControlSectionsModified()
|
||||
{
|
||||
AccessRulesModified = false;
|
||||
AuditRulesModified = false;
|
||||
OwnerModified = false;
|
||||
GroupModified = false;
|
||||
}
|
||||
|
||||
public override Type AccessRightType { get { return typeof(int); } }
|
||||
public override Type AccessRuleType { get { return typeof(GeneralAccessRule); } }
|
||||
public override Type AuditRuleType { get { return typeof(GeneralAuditRule); } }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
[assembly: SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames")]
|
||||
[assembly: SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Scope = "member", Target = "Jellyfish.Library.FrameRateCounter.#frameRateControl")]
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
[assembly: SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames")]
|
||||
[assembly: SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Scope = "member", Target = "Jellyfish.Library.FrameRateCounter.#frameRateControl")]
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class IEnumerableExtensions
|
||||
{
|
||||
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException("source");
|
||||
}
|
||||
if (action == null)
|
||||
{
|
||||
throw new ArgumentNullException("action");
|
||||
}
|
||||
|
||||
foreach (T item in source)
|
||||
{
|
||||
action(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class IEnumerableExtensions
|
||||
{
|
||||
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException("source");
|
||||
}
|
||||
if (action == null)
|
||||
{
|
||||
throw new ArgumentNullException("action");
|
||||
}
|
||||
|
||||
foreach (T item in source)
|
||||
{
|
||||
action(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +1,37 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public sealed class Lazy<T> where T : class
|
||||
{
|
||||
public Lazy(Func<T> initializer)
|
||||
{
|
||||
_initializer = initializer;
|
||||
}
|
||||
|
||||
public T Value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_value == null)
|
||||
{
|
||||
T value = _initializer();
|
||||
if (Interlocked.CompareExchange(ref _value, value, null) != null)
|
||||
{
|
||||
var disposable = value as IDisposable; // dispose preempted instance
|
||||
if (disposable != null)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
|
||||
private Func<T> _initializer;
|
||||
private T _value;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public sealed class Lazy<T> where T : class
|
||||
{
|
||||
public Lazy(Func<T> initializer)
|
||||
{
|
||||
_initializer = initializer;
|
||||
}
|
||||
|
||||
public T Value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_value == null)
|
||||
{
|
||||
T value = _initializer();
|
||||
if (Interlocked.CompareExchange(ref _value, value, null) != null)
|
||||
{
|
||||
var disposable = value as IDisposable; // dispose preempted instance
|
||||
if (disposable != null)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
|
||||
private Func<T> _initializer;
|
||||
private T _value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,35 +1,35 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class MarshalHelpers
|
||||
{
|
||||
[SecurityCritical]
|
||||
public static void FillMemory(IntPtr buffer, int bufferSize, byte value)
|
||||
{
|
||||
NativeMethods.FillMemory(buffer, (IntPtr)bufferSize, value);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static void ZeroMemory(IntPtr buffer, int bufferSize)
|
||||
{
|
||||
NativeMethods.ZeroMemory(buffer, (IntPtr)bufferSize);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
private static class NativeMethods
|
||||
{
|
||||
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern void FillMemory(IntPtr destination, IntPtr length, byte fill);
|
||||
|
||||
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern void ZeroMemory(IntPtr destination, IntPtr length);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class MarshalHelpers
|
||||
{
|
||||
[SecurityCritical]
|
||||
public static void FillMemory(IntPtr buffer, int bufferSize, byte value)
|
||||
{
|
||||
NativeMethods.FillMemory(buffer, (IntPtr)bufferSize, value);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static void ZeroMemory(IntPtr buffer, int bufferSize)
|
||||
{
|
||||
NativeMethods.ZeroMemory(buffer, (IntPtr)bufferSize);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
private static class NativeMethods
|
||||
{
|
||||
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern void FillMemory(IntPtr destination, IntPtr length, byte fill);
|
||||
|
||||
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern void ZeroMemory(IntPtr destination, IntPtr length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class MathHelpers
|
||||
{
|
||||
public static int Clamp(int value, int min, int max)
|
||||
{
|
||||
return (value < min) ? min : (value > max) ? max : value;
|
||||
}
|
||||
|
||||
public static double Clamp(double value, double min, double max)
|
||||
{
|
||||
return (value < min) ? min : (value > max) ? max : value;
|
||||
}
|
||||
|
||||
public static int ClampByte(int value)
|
||||
{
|
||||
return Clamp(value, byte.MinValue, byte.MaxValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class MathHelpers
|
||||
{
|
||||
public static int Clamp(int value, int min, int max)
|
||||
{
|
||||
return (value < min) ? min : (value > max) ? max : value;
|
||||
}
|
||||
|
||||
public static double Clamp(double value, double min, double max)
|
||||
{
|
||||
return (value < min) ? min : (value > max) ? max : value;
|
||||
}
|
||||
|
||||
public static int ClampByte(int value)
|
||||
{
|
||||
return Clamp(value, byte.MinValue, byte.MaxValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,149 +1,149 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
[SecurityCritical]
|
||||
public abstract class SafeAllocHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
protected SafeAllocHandle(bool ownsHandle) :
|
||||
base(ownsHandle)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public sealed class SafeGlobalAllocHandle : SafeAllocHandle
|
||||
{
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
public SafeGlobalAllocHandle() :
|
||||
base(ownsHandle: true)
|
||||
{
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
public SafeGlobalAllocHandle(IntPtr existingHandle, bool ownsHandle) :
|
||||
base(ownsHandle)
|
||||
{
|
||||
SetHandle(existingHandle);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static SafeGlobalAllocHandle Allocate(byte[] value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
|
||||
var alloc = Allocate(value.Length);
|
||||
Marshal.Copy(value, 0, alloc.DangerousGetHandle(), value.Length);
|
||||
|
||||
return alloc;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
[SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "flags")]
|
||||
[SecurityCritical]
|
||||
public static SafeGlobalAllocHandle Allocate(int size, uint flags = 0x0)
|
||||
{
|
||||
var alloc = NativeMethods.GlobalAlloc(flags, (IntPtr)size);
|
||||
if (alloc.IsInvalid)
|
||||
{
|
||||
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
|
||||
}
|
||||
|
||||
return alloc;
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
[SecurityCritical]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return (NativeMethods.GlobalFree(handle) == IntPtr.Zero);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
private static class NativeMethods
|
||||
{
|
||||
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern SafeGlobalAllocHandle GlobalAlloc(uint dwFlags, IntPtr sizetBytes);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
public static extern IntPtr GlobalFree(IntPtr hMem);
|
||||
}
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public sealed class SafeLocalAllocHandle : SafeAllocHandle
|
||||
{
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
public SafeLocalAllocHandle() :
|
||||
base(ownsHandle: true)
|
||||
{
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
public SafeLocalAllocHandle(IntPtr existingHandle, bool ownsHandle) :
|
||||
base(ownsHandle)
|
||||
{
|
||||
SetHandle(existingHandle);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static SafeLocalAllocHandle Allocate(byte[] value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
|
||||
var alloc = Allocate(value.Length);
|
||||
Marshal.Copy(value, 0, alloc.DangerousGetHandle(), value.Length);
|
||||
|
||||
return alloc;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
[SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "flags")]
|
||||
[SecurityCritical]
|
||||
public static SafeLocalAllocHandle Allocate(int size, uint flags = 0x0)
|
||||
{
|
||||
var alloc = NativeMethods.LocalAlloc(flags, (IntPtr)size);
|
||||
if (alloc.IsInvalid)
|
||||
{
|
||||
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
|
||||
}
|
||||
|
||||
return alloc;
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
[SecurityCritical]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return (NativeMethods.LocalFree(handle) == IntPtr.Zero);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
private static class NativeMethods
|
||||
{
|
||||
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern SafeLocalAllocHandle LocalAlloc(uint dwFlags, IntPtr sizetBytes);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
public static extern IntPtr LocalFree(IntPtr hMem);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
[SecurityCritical]
|
||||
public abstract class SafeAllocHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
protected SafeAllocHandle(bool ownsHandle) :
|
||||
base(ownsHandle)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public sealed class SafeGlobalAllocHandle : SafeAllocHandle
|
||||
{
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
public SafeGlobalAllocHandle() :
|
||||
base(ownsHandle: true)
|
||||
{
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
public SafeGlobalAllocHandle(IntPtr existingHandle, bool ownsHandle) :
|
||||
base(ownsHandle)
|
||||
{
|
||||
SetHandle(existingHandle);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static SafeGlobalAllocHandle Allocate(byte[] value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
|
||||
var alloc = Allocate(value.Length);
|
||||
Marshal.Copy(value, 0, alloc.DangerousGetHandle(), value.Length);
|
||||
|
||||
return alloc;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
[SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "flags")]
|
||||
[SecurityCritical]
|
||||
public static SafeGlobalAllocHandle Allocate(int size, uint flags = 0x0)
|
||||
{
|
||||
var alloc = NativeMethods.GlobalAlloc(flags, (IntPtr)size);
|
||||
if (alloc.IsInvalid)
|
||||
{
|
||||
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
|
||||
}
|
||||
|
||||
return alloc;
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
[SecurityCritical]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return (NativeMethods.GlobalFree(handle) == IntPtr.Zero);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
private static class NativeMethods
|
||||
{
|
||||
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern SafeGlobalAllocHandle GlobalAlloc(uint dwFlags, IntPtr sizetBytes);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
public static extern IntPtr GlobalFree(IntPtr hMem);
|
||||
}
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public sealed class SafeLocalAllocHandle : SafeAllocHandle
|
||||
{
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
public SafeLocalAllocHandle() :
|
||||
base(ownsHandle: true)
|
||||
{
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
public SafeLocalAllocHandle(IntPtr existingHandle, bool ownsHandle) :
|
||||
base(ownsHandle)
|
||||
{
|
||||
SetHandle(existingHandle);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static SafeLocalAllocHandle Allocate(byte[] value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
|
||||
var alloc = Allocate(value.Length);
|
||||
Marshal.Copy(value, 0, alloc.DangerousGetHandle(), value.Length);
|
||||
|
||||
return alloc;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
[SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "flags")]
|
||||
[SecurityCritical]
|
||||
public static SafeLocalAllocHandle Allocate(int size, uint flags = 0x0)
|
||||
{
|
||||
var alloc = NativeMethods.LocalAlloc(flags, (IntPtr)size);
|
||||
if (alloc.IsInvalid)
|
||||
{
|
||||
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
|
||||
}
|
||||
|
||||
return alloc;
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
[SecurityCritical]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return (NativeMethods.LocalFree(handle) == IntPtr.Zero);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
private static class NativeMethods
|
||||
{
|
||||
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern SafeLocalAllocHandle LocalAlloc(uint dwFlags, IntPtr sizetBytes);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
public static extern IntPtr LocalFree(IntPtr hMem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,97 +1,97 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.AccessControl;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
[SecurityCritical]
|
||||
public sealed class SafeFileHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
public SafeFileHandle() :
|
||||
base(ownsHandle: true)
|
||||
{
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
public SafeFileHandle(IntPtr existingHandle, bool ownsHandle) :
|
||||
base(ownsHandle)
|
||||
{
|
||||
SetHandle(existingHandle);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static SafeFileHandle CreateFile(string fileName, FileAccess fileAccess, FileShare fileShare, FileMode fileMode, GeneralSecurity fileSecurity)
|
||||
{
|
||||
if (fileMode == FileMode.Append)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
bool inheritable = ((fileShare & FileShare.Inheritable) != 0);
|
||||
fileShare &= ~FileShare.Inheritable;
|
||||
|
||||
return CreateFile(fileName, (uint)fileAccess, (uint)fileShare, (uint)fileMode, 0x0, fileSecurity, inheritable);
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
[SecurityCritical]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return NativeMethods.CloseHandle(handle);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
|
||||
public GeneralSecurity GetAccessControl()
|
||||
{
|
||||
return new GeneralSecurity(false, ResourceType.FileObject, this);
|
||||
}
|
||||
|
||||
public void SetAccessControl(GeneralSecurity fileSecurity)
|
||||
{
|
||||
if (fileSecurity == null)
|
||||
{
|
||||
throw new ArgumentNullException("fileSecurity");
|
||||
}
|
||||
|
||||
fileSecurity.Persist(this);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
private static SafeFileHandle CreateFile(string fileName, uint fileAccess, uint fileShare, uint fileMode, uint fileOptions, GeneralSecurity fileSecurity,
|
||||
bool inheritable = false)
|
||||
{
|
||||
var file = new SafeFileHandle();
|
||||
|
||||
GeneralSecurity.GetSecurityAttributes(fileSecurity, securityAttributes =>
|
||||
{
|
||||
file = NativeMethods.CreateFile(fileName, fileAccess, fileShare, securityAttributes, fileMode, fileOptions, IntPtr.Zero);
|
||||
if (file.IsInvalid)
|
||||
{
|
||||
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
|
||||
}
|
||||
}, inheritable);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
private static class NativeMethods
|
||||
{
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, SecurityAttributes lpSecurityAttributes,
|
||||
uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.AccessControl;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
[SecurityCritical]
|
||||
public sealed class SafeFileHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
public SafeFileHandle() :
|
||||
base(ownsHandle: true)
|
||||
{
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
public SafeFileHandle(IntPtr existingHandle, bool ownsHandle) :
|
||||
base(ownsHandle)
|
||||
{
|
||||
SetHandle(existingHandle);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static SafeFileHandle CreateFile(string fileName, FileAccess fileAccess, FileShare fileShare, FileMode fileMode, GeneralSecurity fileSecurity)
|
||||
{
|
||||
if (fileMode == FileMode.Append)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
bool inheritable = ((fileShare & FileShare.Inheritable) != 0);
|
||||
fileShare &= ~FileShare.Inheritable;
|
||||
|
||||
return CreateFile(fileName, (uint)fileAccess, (uint)fileShare, (uint)fileMode, 0x0, fileSecurity, inheritable);
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
[SecurityCritical]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return NativeMethods.CloseHandle(handle);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
|
||||
public GeneralSecurity GetAccessControl()
|
||||
{
|
||||
return new GeneralSecurity(false, ResourceType.FileObject, this);
|
||||
}
|
||||
|
||||
public void SetAccessControl(GeneralSecurity fileSecurity)
|
||||
{
|
||||
if (fileSecurity == null)
|
||||
{
|
||||
throw new ArgumentNullException("fileSecurity");
|
||||
}
|
||||
|
||||
fileSecurity.Persist(this);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
private static SafeFileHandle CreateFile(string fileName, uint fileAccess, uint fileShare, uint fileMode, uint fileOptions, GeneralSecurity fileSecurity,
|
||||
bool inheritable = false)
|
||||
{
|
||||
var file = new SafeFileHandle();
|
||||
|
||||
GeneralSecurity.GetSecurityAttributes(fileSecurity, securityAttributes =>
|
||||
{
|
||||
file = NativeMethods.CreateFile(fileName, fileAccess, fileShare, securityAttributes, fileMode, fileOptions, IntPtr.Zero);
|
||||
if (file.IsInvalid)
|
||||
{
|
||||
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
|
||||
}
|
||||
}, inheritable);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
private static class NativeMethods
|
||||
{
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, SecurityAttributes lpSecurityAttributes,
|
||||
uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,133 +1,133 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
#if WINDOWS_PHONE
|
||||
using System.Windows.Navigation;
|
||||
using Microsoft.Phone.Controls;
|
||||
using Microsoft.Phone.Shell;
|
||||
#endif
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public class ApplicationBase : Application
|
||||
{
|
||||
public ApplicationBase() :
|
||||
this(null)
|
||||
{
|
||||
}
|
||||
|
||||
public ApplicationBase(string name)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
UnhandledException += OnApplicationUnhandledException;
|
||||
//AppDomain.CurrentDomain.UnhandledException += OnAppDomainUnhandledException;
|
||||
}
|
||||
|
||||
#if !WINDOWS_PHONE
|
||||
protected void InitializeOutOfBrowserUpdate()
|
||||
{
|
||||
if (IsRunningOutOfBrowser)
|
||||
{
|
||||
CheckAndDownloadUpdateCompleted += OnApplicationCheckAndDownloadUpdateCompleted;
|
||||
CheckAndDownloadUpdateAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WINDOWS_PHONE
|
||||
protected void InitializePhoneApplication()
|
||||
{
|
||||
if (!_phoneApplicationInitialized)
|
||||
{
|
||||
RootFrame = new PhoneApplicationFrame();
|
||||
RootFrame.Navigated += OnRootFrameNavigated;
|
||||
RootFrame.NavigationFailed += OnRootFrameNavigationFailed;
|
||||
_phoneApplicationInitialized = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private string GetExceptionCaption(string title, bool isTerminating = false)
|
||||
{
|
||||
var caption = new StringBuilder();
|
||||
if (!string.IsNullOrEmpty(Name))
|
||||
{
|
||||
caption.Append(Name).Append(' ');
|
||||
}
|
||||
caption.Append(title);
|
||||
if (isTerminating)
|
||||
{
|
||||
caption.Append(" (Terminating)");
|
||||
}
|
||||
|
||||
return caption.ToString();
|
||||
}
|
||||
|
||||
#if !WINDOWS_PHONE
|
||||
private void OnApplicationCheckAndDownloadUpdateCompleted(object sender, CheckAndDownloadUpdateCompletedEventArgs e)
|
||||
{
|
||||
if (e.Error != null)
|
||||
{
|
||||
if (e.Error is PlatformNotSupportedException)
|
||||
{
|
||||
MessageBox.Show("An application update is available, but it requires the latest version of Silverlight.");
|
||||
}
|
||||
else if (Debugger.IsAttached)
|
||||
{
|
||||
Debugger.Break();
|
||||
}
|
||||
}
|
||||
else if (e.UpdateAvailable)
|
||||
{
|
||||
MessageBox.Show("An application update was downloaded. Restart the application to run the latest version.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private void OnApplicationUnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
|
||||
{
|
||||
MessageBox.Show(e.ExceptionObject.ToString(), GetExceptionCaption("Application Exception"), MessageBoxButton.OK);
|
||||
if (Debugger.IsAttached)
|
||||
{
|
||||
Debugger.Break();
|
||||
}
|
||||
}
|
||||
|
||||
//private void OnAppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
//{
|
||||
// MessageBox.Show(e.ExceptionObject.ToString(), GetExceptionCaption("AppDomain Exception", e.IsTerminating), MessageBoxButton.OK);
|
||||
// if (Debugger.IsAttached)
|
||||
// {
|
||||
// Debugger.Break();
|
||||
// }
|
||||
//}
|
||||
|
||||
#if WINDOWS_PHONE
|
||||
private void OnRootFrameNavigated(object sender, NavigationEventArgs e)
|
||||
{
|
||||
if (RootVisual != RootFrame)
|
||||
{
|
||||
RootVisual = RootFrame;
|
||||
}
|
||||
RootFrame.Navigated -= OnRootFrameNavigated;
|
||||
}
|
||||
|
||||
private void OnRootFrameNavigationFailed(object sender, NavigationFailedEventArgs e)
|
||||
{
|
||||
if (Debugger.IsAttached)
|
||||
{
|
||||
Debugger.Break();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public string Name { get; private set; }
|
||||
#if WINDOWS_PHONE
|
||||
public PhoneApplicationFrame RootFrame { get; private set; }
|
||||
|
||||
private bool _phoneApplicationInitialized;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
#if WINDOWS_PHONE
|
||||
using System.Windows.Navigation;
|
||||
using Microsoft.Phone.Controls;
|
||||
using Microsoft.Phone.Shell;
|
||||
#endif
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public class ApplicationBase : Application
|
||||
{
|
||||
public ApplicationBase() :
|
||||
this(null)
|
||||
{
|
||||
}
|
||||
|
||||
public ApplicationBase(string name)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
UnhandledException += OnApplicationUnhandledException;
|
||||
//AppDomain.CurrentDomain.UnhandledException += OnAppDomainUnhandledException;
|
||||
}
|
||||
|
||||
#if !WINDOWS_PHONE
|
||||
protected void InitializeOutOfBrowserUpdate()
|
||||
{
|
||||
if (IsRunningOutOfBrowser)
|
||||
{
|
||||
CheckAndDownloadUpdateCompleted += OnApplicationCheckAndDownloadUpdateCompleted;
|
||||
CheckAndDownloadUpdateAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WINDOWS_PHONE
|
||||
protected void InitializePhoneApplication()
|
||||
{
|
||||
if (!_phoneApplicationInitialized)
|
||||
{
|
||||
RootFrame = new PhoneApplicationFrame();
|
||||
RootFrame.Navigated += OnRootFrameNavigated;
|
||||
RootFrame.NavigationFailed += OnRootFrameNavigationFailed;
|
||||
_phoneApplicationInitialized = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private string GetExceptionCaption(string title, bool isTerminating = false)
|
||||
{
|
||||
var caption = new StringBuilder();
|
||||
if (!string.IsNullOrEmpty(Name))
|
||||
{
|
||||
caption.Append(Name).Append(' ');
|
||||
}
|
||||
caption.Append(title);
|
||||
if (isTerminating)
|
||||
{
|
||||
caption.Append(" (Terminating)");
|
||||
}
|
||||
|
||||
return caption.ToString();
|
||||
}
|
||||
|
||||
#if !WINDOWS_PHONE
|
||||
private void OnApplicationCheckAndDownloadUpdateCompleted(object sender, CheckAndDownloadUpdateCompletedEventArgs e)
|
||||
{
|
||||
if (e.Error != null)
|
||||
{
|
||||
if (e.Error is PlatformNotSupportedException)
|
||||
{
|
||||
MessageBox.Show("An application update is available, but it requires the latest version of Silverlight.");
|
||||
}
|
||||
else if (Debugger.IsAttached)
|
||||
{
|
||||
Debugger.Break();
|
||||
}
|
||||
}
|
||||
else if (e.UpdateAvailable)
|
||||
{
|
||||
MessageBox.Show("An application update was downloaded. Restart the application to run the latest version.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private void OnApplicationUnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
|
||||
{
|
||||
MessageBox.Show(e.ExceptionObject.ToString(), GetExceptionCaption("Application Exception"), MessageBoxButton.OK);
|
||||
if (Debugger.IsAttached)
|
||||
{
|
||||
Debugger.Break();
|
||||
}
|
||||
}
|
||||
|
||||
//private void OnAppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
//{
|
||||
// MessageBox.Show(e.ExceptionObject.ToString(), GetExceptionCaption("AppDomain Exception", e.IsTerminating), MessageBoxButton.OK);
|
||||
// if (Debugger.IsAttached)
|
||||
// {
|
||||
// Debugger.Break();
|
||||
// }
|
||||
//}
|
||||
|
||||
#if WINDOWS_PHONE
|
||||
private void OnRootFrameNavigated(object sender, NavigationEventArgs e)
|
||||
{
|
||||
if (RootVisual != RootFrame)
|
||||
{
|
||||
RootVisual = RootFrame;
|
||||
}
|
||||
RootFrame.Navigated -= OnRootFrameNavigated;
|
||||
}
|
||||
|
||||
private void OnRootFrameNavigationFailed(object sender, NavigationFailedEventArgs e)
|
||||
{
|
||||
if (Debugger.IsAttached)
|
||||
{
|
||||
Debugger.Break();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public string Name { get; private set; }
|
||||
#if WINDOWS_PHONE
|
||||
public PhoneApplicationFrame RootFrame { get; private set; }
|
||||
|
||||
private bool _phoneApplicationInitialized;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using Jellyfish.Library;
|
||||
|
||||
[assembly: AssemblyTitle("Library")]
|
||||
[assembly: AssemblyDescription("Common Library")]
|
||||
[assembly: AssemblyProduct("Jellyfish.Library.Silverlight.Phone")]
|
||||
[assembly: AssemblyCompany("Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2009-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett")]
|
||||
|
||||
[assembly: AssemblyVersion("0.1.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.1.3.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("66034b9e-9f0b-47b0-aac4-cade9a748891")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using Jellyfish.Library;
|
||||
|
||||
[assembly: AssemblyTitle("Library")]
|
||||
[assembly: AssemblyDescription("Common Library")]
|
||||
[assembly: AssemblyProduct("Jellyfish.Library.Silverlight.Phone")]
|
||||
[assembly: AssemblyCompany("Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2009-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett")]
|
||||
|
||||
[assembly: AssemblyVersion("0.1.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.1.3.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("66034b9e-9f0b-47b0-aac4-cade9a748891")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using Jellyfish.Library;
|
||||
|
||||
[assembly: AssemblyTitle("Library")]
|
||||
[assembly: AssemblyDescription("Common Library")]
|
||||
[assembly: AssemblyProduct("Jellyfish.Library.Silverlight")]
|
||||
[assembly: AssemblyCompany("Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2009-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett")]
|
||||
|
||||
[assembly: AssemblyVersion("0.1.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.1.3.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("66034b9e-9f0b-47b0-aac4-cade9a748891")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using Jellyfish.Library;
|
||||
|
||||
[assembly: AssemblyTitle("Library")]
|
||||
[assembly: AssemblyDescription("Common Library")]
|
||||
[assembly: AssemblyProduct("Jellyfish.Library.Silverlight")]
|
||||
[assembly: AssemblyCompany("Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2009-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett")]
|
||||
|
||||
[assembly: AssemblyVersion("0.1.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.1.3.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("66034b9e-9f0b-47b0-aac4-cade9a748891")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
|
|
|
@ -1,76 +1,76 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public sealed class WaveMediaStreamSource : MediaStreamSource, IDisposable
|
||||
{
|
||||
public WaveMediaStreamSource(int sampleRate, int sampleChannels, int sampleBits, int sampleSize, int sampleLatency, Action<byte[], int> updater)
|
||||
{
|
||||
_bufferSize = sampleSize;
|
||||
_buffer = new byte[_bufferSize];
|
||||
_bufferStream = new MemoryStream(_buffer);
|
||||
_waveFormat = new WaveFormat(sampleRate, sampleChannels, sampleBits);
|
||||
AudioBufferLength = sampleLatency; // ms; avoids audio delay
|
||||
_updater = updater;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_bufferStream.Dispose();
|
||||
}
|
||||
|
||||
protected override void CloseMedia()
|
||||
{
|
||||
_audioDescription = null;
|
||||
}
|
||||
|
||||
protected override void GetDiagnosticAsync(MediaStreamSourceDiagnosticKind diagnosticKind)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void GetSampleAsync(MediaStreamType mediaStreamType)
|
||||
{
|
||||
_updater(_buffer, _bufferSize);
|
||||
|
||||
var sample = new MediaStreamSample(_audioDescription, _bufferStream, 0, _bufferSize, _timestamp, _emptySampleDict);
|
||||
_timestamp += _bufferSize * 10000000L / _waveFormat.AverageBytesPerSec; // 100 ns
|
||||
|
||||
ReportGetSampleCompleted(sample);
|
||||
}
|
||||
|
||||
protected override void OpenMediaAsync()
|
||||
{
|
||||
_timestamp = 0;
|
||||
|
||||
var sourceAttributes = new Dictionary<MediaSourceAttributesKeys, string>() { { MediaSourceAttributesKeys.Duration, "0" }, { MediaSourceAttributesKeys.CanSeek, "false" } };
|
||||
var streamAttributes = new Dictionary<MediaStreamAttributeKeys, string>() { { MediaStreamAttributeKeys.CodecPrivateData, _waveFormat.ToHexString() } };
|
||||
_audioDescription = new MediaStreamDescription(MediaStreamType.Audio, streamAttributes);
|
||||
var availableStreams = new List<MediaStreamDescription>() { _audioDescription };
|
||||
|
||||
ReportOpenMediaCompleted(sourceAttributes, availableStreams);
|
||||
}
|
||||
|
||||
protected override void SeekAsync(long seekToTime)
|
||||
{
|
||||
ReportSeekCompleted(seekToTime);
|
||||
}
|
||||
|
||||
protected override void SwitchMediaStreamAsync(MediaStreamDescription mediaStreamDescription)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private byte[] _buffer;
|
||||
private int _bufferSize;
|
||||
private MemoryStream _bufferStream;
|
||||
private Action<byte[], int> _updater;
|
||||
private WaveFormat _waveFormat;
|
||||
private long _timestamp;
|
||||
private MediaStreamDescription _audioDescription;
|
||||
private Dictionary<MediaSampleAttributeKeys, string> _emptySampleDict = new Dictionary<MediaSampleAttributeKeys, string>();
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public sealed class WaveMediaStreamSource : MediaStreamSource, IDisposable
|
||||
{
|
||||
public WaveMediaStreamSource(int sampleRate, int sampleChannels, int sampleBits, int sampleSize, int sampleLatency, Action<byte[], int> updater)
|
||||
{
|
||||
_bufferSize = sampleSize;
|
||||
_buffer = new byte[_bufferSize];
|
||||
_bufferStream = new MemoryStream(_buffer);
|
||||
_waveFormat = new WaveFormat(sampleRate, sampleChannels, sampleBits);
|
||||
AudioBufferLength = sampleLatency; // ms; avoids audio delay
|
||||
_updater = updater;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_bufferStream.Dispose();
|
||||
}
|
||||
|
||||
protected override void CloseMedia()
|
||||
{
|
||||
_audioDescription = null;
|
||||
}
|
||||
|
||||
protected override void GetDiagnosticAsync(MediaStreamSourceDiagnosticKind diagnosticKind)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void GetSampleAsync(MediaStreamType mediaStreamType)
|
||||
{
|
||||
_updater(_buffer, _bufferSize);
|
||||
|
||||
var sample = new MediaStreamSample(_audioDescription, _bufferStream, 0, _bufferSize, _timestamp, _emptySampleDict);
|
||||
_timestamp += _bufferSize * 10000000L / _waveFormat.AverageBytesPerSec; // 100 ns
|
||||
|
||||
ReportGetSampleCompleted(sample);
|
||||
}
|
||||
|
||||
protected override void OpenMediaAsync()
|
||||
{
|
||||
_timestamp = 0;
|
||||
|
||||
var sourceAttributes = new Dictionary<MediaSourceAttributesKeys, string>() { { MediaSourceAttributesKeys.Duration, "0" }, { MediaSourceAttributesKeys.CanSeek, "false" } };
|
||||
var streamAttributes = new Dictionary<MediaStreamAttributeKeys, string>() { { MediaStreamAttributeKeys.CodecPrivateData, _waveFormat.ToHexString() } };
|
||||
_audioDescription = new MediaStreamDescription(MediaStreamType.Audio, streamAttributes);
|
||||
var availableStreams = new List<MediaStreamDescription>() { _audioDescription };
|
||||
|
||||
ReportOpenMediaCompleted(sourceAttributes, availableStreams);
|
||||
}
|
||||
|
||||
protected override void SeekAsync(long seekToTime)
|
||||
{
|
||||
ReportSeekCompleted(seekToTime);
|
||||
}
|
||||
|
||||
protected override void SwitchMediaStreamAsync(MediaStreamDescription mediaStreamDescription)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private byte[] _buffer;
|
||||
private int _bufferSize;
|
||||
private MemoryStream _bufferStream;
|
||||
private Action<byte[], int> _updater;
|
||||
private WaveFormat _waveFormat;
|
||||
private long _timestamp;
|
||||
private MediaStreamDescription _audioDescription;
|
||||
private Dictionary<MediaSampleAttributeKeys, string> _emptySampleDict = new Dictionary<MediaSampleAttributeKeys, string>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class SingletonFactory<T> where T : class, new()
|
||||
{
|
||||
[SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
|
||||
public static T Create()
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
|
||||
public static T Instance { get { return _instance; } }
|
||||
|
||||
private static readonly T _instance = new T();
|
||||
}
|
||||
}
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class SingletonFactory<T> where T : class, new()
|
||||
{
|
||||
[SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
|
||||
public static T Create()
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
|
||||
public static T Instance { get { return _instance; } }
|
||||
|
||||
private static readonly T _instance = new T();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class StreamExtensions
|
||||
{
|
||||
public static byte[] ReadAllBytes(this Stream stream)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentNullException("stream");
|
||||
}
|
||||
|
||||
int count = (int)stream.Length;
|
||||
byte[] buffer = new byte[count];
|
||||
ReadBlock(stream, buffer, 0, count);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static int ReadBlock(this Stream stream, byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentNullException("stream");
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
int read;
|
||||
do
|
||||
{
|
||||
total += read = stream.Read(buffer, offset + total, count - total);
|
||||
}
|
||||
while ((read > 0) && (total < count));
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class StreamExtensions
|
||||
{
|
||||
public static byte[] ReadAllBytes(this Stream stream)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentNullException("stream");
|
||||
}
|
||||
|
||||
int count = (int)stream.Length;
|
||||
byte[] buffer = new byte[count];
|
||||
ReadBlock(stream, buffer, 0, count);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static int ReadBlock(this Stream stream, byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentNullException("stream");
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
int read;
|
||||
do
|
||||
{
|
||||
total += read = stream.Read(buffer, offset + total, count - total);
|
||||
}
|
||||
while ((read > 0) && (total < count));
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,68 +1,68 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class StringBuilderExtensions
|
||||
{
|
||||
public static StringBuilder AppendHex(this StringBuilder builder, short value) // little endian
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException("builder");
|
||||
}
|
||||
|
||||
return builder.AppendFormat(CultureInfo.InvariantCulture, "{0:X2}{1:X2}", value & 0xFF, value >> 8);
|
||||
}
|
||||
|
||||
public static StringBuilder AppendHex(this StringBuilder builder, int value) // little endian
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException("builder");
|
||||
}
|
||||
|
||||
return builder.AppendFormat(CultureInfo.InvariantCulture, "{0:X2}{1:X2}{2:X2}{3:X2}", value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF, value >> 24);
|
||||
}
|
||||
|
||||
public static StringBuilder AppendWithoutGarbage(this StringBuilder builder, int value)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException("builder");
|
||||
}
|
||||
|
||||
if (value < 0)
|
||||
{
|
||||
builder.Append('-');
|
||||
}
|
||||
|
||||
int index = builder.Length;
|
||||
do
|
||||
{
|
||||
builder.Insert(index, Digits, (value % 10) + 9, 1);
|
||||
value /= 10;
|
||||
}
|
||||
while (value != 0);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
#if WINDOWS_PHONE || XBOX
|
||||
public static StringBuilder Clear(this StringBuilder builder)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException("builder");
|
||||
}
|
||||
|
||||
builder.Length = 0;
|
||||
|
||||
return builder;
|
||||
}
|
||||
#endif
|
||||
|
||||
private static readonly char[] Digits = new char[] { '9', '8', '7', '6', '5', '4', '3', '2', '1', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class StringBuilderExtensions
|
||||
{
|
||||
public static StringBuilder AppendHex(this StringBuilder builder, short value) // little endian
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException("builder");
|
||||
}
|
||||
|
||||
return builder.AppendFormat(CultureInfo.InvariantCulture, "{0:X2}{1:X2}", value & 0xFF, value >> 8);
|
||||
}
|
||||
|
||||
public static StringBuilder AppendHex(this StringBuilder builder, int value) // little endian
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException("builder");
|
||||
}
|
||||
|
||||
return builder.AppendFormat(CultureInfo.InvariantCulture, "{0:X2}{1:X2}{2:X2}{3:X2}", value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF, value >> 24);
|
||||
}
|
||||
|
||||
public static StringBuilder AppendWithoutGarbage(this StringBuilder builder, int value)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException("builder");
|
||||
}
|
||||
|
||||
if (value < 0)
|
||||
{
|
||||
builder.Append('-');
|
||||
}
|
||||
|
||||
int index = builder.Length;
|
||||
do
|
||||
{
|
||||
builder.Insert(index, Digits, (value % 10) + 9, 1);
|
||||
value /= 10;
|
||||
}
|
||||
while (value != 0);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
#if WINDOWS_PHONE || XBOX
|
||||
public static StringBuilder Clear(this StringBuilder builder)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException("builder");
|
||||
}
|
||||
|
||||
builder.Length = 0;
|
||||
|
||||
return builder;
|
||||
}
|
||||
#endif
|
||||
|
||||
private static readonly char[] Digits = new char[] { '9', '8', '7', '6', '5', '4', '3', '2', '1', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class ThreadExtensions
|
||||
{
|
||||
public static void IsAliveJoin(this Thread thread)
|
||||
{
|
||||
if (thread == null)
|
||||
{
|
||||
throw new ArgumentNullException("thread");
|
||||
}
|
||||
|
||||
#if !XBOX
|
||||
if (thread.IsAlive)
|
||||
#endif
|
||||
{
|
||||
thread.Join();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class ThreadExtensions
|
||||
{
|
||||
public static void IsAliveJoin(this Thread thread)
|
||||
{
|
||||
if (thread == null)
|
||||
{
|
||||
throw new ArgumentNullException("thread");
|
||||
}
|
||||
|
||||
#if !XBOX
|
||||
if (thread.IsAlive)
|
||||
#endif
|
||||
{
|
||||
thread.Join();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class WaitHandleExtensions
|
||||
{
|
||||
#if XBOX
|
||||
public static bool WaitOne(this WaitHandle waitHandle, int millisecondsTimeout)
|
||||
{
|
||||
if (waitHandle == null)
|
||||
{
|
||||
throw new ArgumentNullException("waitHandle");
|
||||
}
|
||||
|
||||
return waitHandle.WaitOne(millisecondsTimeout, false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class WaitHandleExtensions
|
||||
{
|
||||
#if XBOX
|
||||
public static bool WaitOne(this WaitHandle waitHandle, int millisecondsTimeout)
|
||||
{
|
||||
if (waitHandle == null)
|
||||
{
|
||||
throw new ArgumentNullException("waitHandle");
|
||||
}
|
||||
|
||||
return waitHandle.WaitOne(millisecondsTimeout, false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +1,49 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class WaveFormat
|
||||
{
|
||||
public WaveFormat(int sampleRate, int sampleChannels, int sampleBits)
|
||||
{
|
||||
_formatTag = WaveFormatPcm;
|
||||
_samplesPerSec = sampleRate;
|
||||
_channels = (short)sampleChannels;
|
||||
_bitsPerSample = (short)sampleBits;
|
||||
_blockAlign = (short)(sampleChannels * sampleBits / 8);
|
||||
_averageBytesPerSec = sampleRate * _blockAlign;
|
||||
}
|
||||
|
||||
public string ToHexString() // little endian
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendHex(_formatTag);
|
||||
builder.AppendHex(_channels);
|
||||
builder.AppendHex(_samplesPerSec);
|
||||
builder.AppendHex(_averageBytesPerSec);
|
||||
builder.AppendHex(_blockAlign);
|
||||
builder.AppendHex(_bitsPerSample);
|
||||
builder.AppendHex(_size);
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public int SamplesPerSec { get { return _samplesPerSec; } } // no auto props
|
||||
public int Channels { get { return _channels; } }
|
||||
public int BitsPerSample { get { return _bitsPerSample; } }
|
||||
public int AverageBytesPerSec { get { return _averageBytesPerSec; } }
|
||||
|
||||
private const int WaveFormatPcm = 1;
|
||||
|
||||
private short _formatTag;
|
||||
private short _channels;
|
||||
private int _samplesPerSec;
|
||||
private int _averageBytesPerSec;
|
||||
private short _blockAlign;
|
||||
private short _bitsPerSample;
|
||||
private short _size;
|
||||
}
|
||||
}
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class WaveFormat
|
||||
{
|
||||
public WaveFormat(int sampleRate, int sampleChannels, int sampleBits)
|
||||
{
|
||||
_formatTag = WaveFormatPcm;
|
||||
_samplesPerSec = sampleRate;
|
||||
_channels = (short)sampleChannels;
|
||||
_bitsPerSample = (short)sampleBits;
|
||||
_blockAlign = (short)(sampleChannels * sampleBits / 8);
|
||||
_averageBytesPerSec = sampleRate * _blockAlign;
|
||||
}
|
||||
|
||||
public string ToHexString() // little endian
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendHex(_formatTag);
|
||||
builder.AppendHex(_channels);
|
||||
builder.AppendHex(_samplesPerSec);
|
||||
builder.AppendHex(_averageBytesPerSec);
|
||||
builder.AppendHex(_blockAlign);
|
||||
builder.AppendHex(_bitsPerSample);
|
||||
builder.AppendHex(_size);
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public int SamplesPerSec { get { return _samplesPerSec; } } // no auto props
|
||||
public int Channels { get { return _channels; } }
|
||||
public int BitsPerSample { get { return _bitsPerSample; } }
|
||||
public int AverageBytesPerSec { get { return _averageBytesPerSec; } }
|
||||
|
||||
private const int WaveFormatPcm = 1;
|
||||
|
||||
private short _formatTag;
|
||||
private short _channels;
|
||||
private int _samplesPerSec;
|
||||
private int _averageBytesPerSec;
|
||||
private short _blockAlign;
|
||||
private short _bitsPerSample;
|
||||
private short _size;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,65 +1,65 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public class ApplicationBase : Application
|
||||
{
|
||||
[SecurityCritical]
|
||||
public ApplicationBase() :
|
||||
this(null)
|
||||
{
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public ApplicationBase(string name)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
DispatcherUnhandledException += OnApplicationDispatcherUnhandledException;
|
||||
AppDomain.CurrentDomain.UnhandledException += OnAppDomainUnhandledException;
|
||||
}
|
||||
|
||||
private string GetExceptionCaption(string title, bool isTerminating = false)
|
||||
{
|
||||
var caption = new StringBuilder();
|
||||
if (!string.IsNullOrEmpty(Name))
|
||||
{
|
||||
caption.Append(Name).Append(' ');
|
||||
}
|
||||
caption.Append(title);
|
||||
if (isTerminating)
|
||||
{
|
||||
caption.Append(" (Terminating)");
|
||||
}
|
||||
|
||||
return caption.ToString();
|
||||
}
|
||||
|
||||
private void OnApplicationDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
||||
{
|
||||
MessageBox.Show(e.Exception.ToString(), GetExceptionCaption("Application Dispatcher Exception", isTerminating: true));
|
||||
if (Debugger.IsAttached)
|
||||
{
|
||||
Debugger.Break();
|
||||
}
|
||||
e.Handled = true;
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
private void OnAppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
MessageBox.Show(e.ExceptionObject.ToString(), GetExceptionCaption("AppDomain Exception", e.IsTerminating));
|
||||
if (Debugger.IsAttached)
|
||||
{
|
||||
Debugger.Break();
|
||||
}
|
||||
}
|
||||
|
||||
public string Name { get; private set; }
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public class ApplicationBase : Application
|
||||
{
|
||||
[SecurityCritical]
|
||||
public ApplicationBase() :
|
||||
this(null)
|
||||
{
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public ApplicationBase(string name)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
DispatcherUnhandledException += OnApplicationDispatcherUnhandledException;
|
||||
AppDomain.CurrentDomain.UnhandledException += OnAppDomainUnhandledException;
|
||||
}
|
||||
|
||||
private string GetExceptionCaption(string title, bool isTerminating = false)
|
||||
{
|
||||
var caption = new StringBuilder();
|
||||
if (!string.IsNullOrEmpty(Name))
|
||||
{
|
||||
caption.Append(Name).Append(' ');
|
||||
}
|
||||
caption.Append(title);
|
||||
if (isTerminating)
|
||||
{
|
||||
caption.Append(" (Terminating)");
|
||||
}
|
||||
|
||||
return caption.ToString();
|
||||
}
|
||||
|
||||
private void OnApplicationDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
||||
{
|
||||
MessageBox.Show(e.Exception.ToString(), GetExceptionCaption("Application Dispatcher Exception", isTerminating: true));
|
||||
if (Debugger.IsAttached)
|
||||
{
|
||||
Debugger.Break();
|
||||
}
|
||||
e.Handled = true;
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
private void OnAppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
MessageBox.Show(e.ExceptionObject.ToString(), GetExceptionCaption("AppDomain Exception", e.IsTerminating));
|
||||
if (Debugger.IsAttached)
|
||||
{
|
||||
Debugger.Break();
|
||||
}
|
||||
}
|
||||
|
||||
public string Name { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using Jellyfish.Library;
|
||||
|
||||
[assembly: AssemblyTitle("Library")]
|
||||
[assembly: AssemblyDescription("Common Library")]
|
||||
[assembly: AssemblyProduct("Jellyfish.Library.Wpf")]
|
||||
[assembly: AssemblyCompany("Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2009-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett")]
|
||||
|
||||
[assembly: AssemblyVersion("0.1.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.1.3.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("66034b9e-9f0b-47b0-aac4-cade9a748891")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using Jellyfish.Library;
|
||||
|
||||
[assembly: AssemblyTitle("Library")]
|
||||
[assembly: AssemblyDescription("Common Library")]
|
||||
[assembly: AssemblyProduct("Jellyfish.Library.Wpf")]
|
||||
[assembly: AssemblyCompany("Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2009-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett")]
|
||||
|
||||
[assembly: AssemblyVersion("0.1.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.1.3.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("66034b9e-9f0b-47b0-aac4-cade9a748891")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class WindowExtensions
|
||||
{
|
||||
public static IntPtr GetHandle(this Window window)
|
||||
{
|
||||
return new WindowInteropHelper(window).Handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class WindowExtensions
|
||||
{
|
||||
public static IntPtr GetHandle(this Window window)
|
||||
{
|
||||
return new WindowInteropHelper(window).Handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class XmlSerializerHelpers
|
||||
{
|
||||
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
public static T Deserialize<T>(Stream stream, string defaultNamespace = null)
|
||||
{
|
||||
using (var reader = XmlReader.Create(stream))
|
||||
{
|
||||
var serializer = new XmlSerializer(typeof(T), defaultNamespace);
|
||||
return (T)serializer.Deserialize(reader);
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
public static void Serialize<T>(Stream stream, T instance, string defaultNamespace = null)
|
||||
{
|
||||
using (var writer = XmlWriter.Create(stream))
|
||||
{
|
||||
var serializer = new XmlSerializer(typeof(T), defaultNamespace);
|
||||
serializer.Serialize(writer, instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public static class XmlSerializerHelpers
|
||||
{
|
||||
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
public static T Deserialize<T>(Stream stream, string defaultNamespace = null)
|
||||
{
|
||||
using (var reader = XmlReader.Create(stream))
|
||||
{
|
||||
var serializer = new XmlSerializer(typeof(T), defaultNamespace);
|
||||
return (T)serializer.Deserialize(reader);
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
public static void Serialize<T>(Stream stream, T instance, string defaultNamespace = null)
|
||||
{
|
||||
using (var writer = XmlWriter.Create(stream))
|
||||
{
|
||||
var serializer = new XmlSerializer(typeof(T), defaultNamespace);
|
||||
serializer.Serialize(writer, instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,72 +1,72 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public sealed class FrameRateCounter : DrawableGameComponent
|
||||
{
|
||||
public FrameRateCounter(GameBase game) :
|
||||
base(game)
|
||||
{
|
||||
FontColor = Color.White;
|
||||
FontName = "Default";
|
||||
}
|
||||
|
||||
protected override void LoadContent()
|
||||
{
|
||||
_spriteBatch = new SpriteBatch(GraphicsDevice);
|
||||
_spriteFont = Game.Content.Load<SpriteFont>(FontName);
|
||||
|
||||
var titleSafeArea = Game.GraphicsDevice.DisplayMode.TitleSafeArea;
|
||||
Position = new Vector2(titleSafeArea.X, titleSafeArea.Y);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
|
||||
public override void Draw(GameTime gameTime)
|
||||
{
|
||||
_frameCount++;
|
||||
|
||||
_frameRateBuilder.Clear().AppendWithoutGarbage(_frameRate).Append(" fps");
|
||||
|
||||
_spriteBatch.Begin();
|
||||
//_spriteBatch.DrawString(_spriteFont, _frameRateBuilder, Position - Vector2.UnitX, Color.Black); // rough outline
|
||||
//_spriteBatch.DrawString(_spriteFont, _frameRateBuilder, Position + Vector2.UnitX, Color.Black);
|
||||
//_spriteBatch.DrawString(_spriteFont, _frameRateBuilder, Position - Vector2.UnitY, Color.Black);
|
||||
//_spriteBatch.DrawString(_spriteFont, _frameRateBuilder, Position + Vector2.UnitY, Color.Black);
|
||||
_spriteBatch.DrawString(_spriteFont, _frameRateBuilder, Position, FontColor);
|
||||
_spriteBatch.End();
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
|
||||
public override void Update(GameTime gameTime)
|
||||
{
|
||||
if (gameTime == null)
|
||||
{
|
||||
throw new ArgumentNullException("gameTime");
|
||||
}
|
||||
|
||||
_elapsedTime += gameTime.ElapsedGameTime.Ticks;
|
||||
|
||||
if (_elapsedTime >= TimeSpan.TicksPerSecond)
|
||||
{
|
||||
_elapsedTime -= TimeSpan.TicksPerSecond;
|
||||
_frameRate = _frameCount;
|
||||
_frameCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public Color FontColor { get; set; }
|
||||
public string FontName { get; set; }
|
||||
public Vector2 Position { get; set; }
|
||||
|
||||
private SpriteBatch _spriteBatch;
|
||||
private SpriteFont _spriteFont;
|
||||
private long _elapsedTime;
|
||||
private int _frameCount;
|
||||
private int _frameRate;
|
||||
private StringBuilder _frameRateBuilder = new StringBuilder(); // cache builder; avoids garbage
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public sealed class FrameRateCounter : DrawableGameComponent
|
||||
{
|
||||
public FrameRateCounter(GameBase game) :
|
||||
base(game)
|
||||
{
|
||||
FontColor = Color.White;
|
||||
FontName = "Default";
|
||||
}
|
||||
|
||||
protected override void LoadContent()
|
||||
{
|
||||
_spriteBatch = new SpriteBatch(GraphicsDevice);
|
||||
_spriteFont = Game.Content.Load<SpriteFont>(FontName);
|
||||
|
||||
var titleSafeArea = Game.GraphicsDevice.DisplayMode.TitleSafeArea;
|
||||
Position = new Vector2(titleSafeArea.X, titleSafeArea.Y);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
|
||||
public override void Draw(GameTime gameTime)
|
||||
{
|
||||
_frameCount++;
|
||||
|
||||
_frameRateBuilder.Clear().AppendWithoutGarbage(_frameRate).Append(" fps");
|
||||
|
||||
_spriteBatch.Begin();
|
||||
//_spriteBatch.DrawString(_spriteFont, _frameRateBuilder, Position - Vector2.UnitX, Color.Black); // rough outline
|
||||
//_spriteBatch.DrawString(_spriteFont, _frameRateBuilder, Position + Vector2.UnitX, Color.Black);
|
||||
//_spriteBatch.DrawString(_spriteFont, _frameRateBuilder, Position - Vector2.UnitY, Color.Black);
|
||||
//_spriteBatch.DrawString(_spriteFont, _frameRateBuilder, Position + Vector2.UnitY, Color.Black);
|
||||
_spriteBatch.DrawString(_spriteFont, _frameRateBuilder, Position, FontColor);
|
||||
_spriteBatch.End();
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
|
||||
public override void Update(GameTime gameTime)
|
||||
{
|
||||
if (gameTime == null)
|
||||
{
|
||||
throw new ArgumentNullException("gameTime");
|
||||
}
|
||||
|
||||
_elapsedTime += gameTime.ElapsedGameTime.Ticks;
|
||||
|
||||
if (_elapsedTime >= TimeSpan.TicksPerSecond)
|
||||
{
|
||||
_elapsedTime -= TimeSpan.TicksPerSecond;
|
||||
_frameRate = _frameCount;
|
||||
_frameCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public Color FontColor { get; set; }
|
||||
public string FontName { get; set; }
|
||||
public Vector2 Position { get; set; }
|
||||
|
||||
private SpriteBatch _spriteBatch;
|
||||
private SpriteFont _spriteFont;
|
||||
private long _elapsedTime;
|
||||
private int _frameCount;
|
||||
private int _frameRate;
|
||||
private StringBuilder _frameRateBuilder = new StringBuilder(); // cache builder; avoids garbage
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,50 +1,50 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public class GameBase : Game
|
||||
{
|
||||
public GameBase() :
|
||||
this(null)
|
||||
{
|
||||
}
|
||||
|
||||
public GameBase(string name)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
Content.RootDirectory = "Content";
|
||||
GraphicsDeviceManager = new GraphicsDeviceManager(this);
|
||||
#if WINDOWS_PHONE
|
||||
GraphicsDeviceManager.IsFullScreen = true;
|
||||
TargetElapsedTime = TimeSpan.FromTicks(333333); // 30 fps
|
||||
#endif
|
||||
GraphicsDeviceService = (IGraphicsDeviceService)Services.GetService(typeof(IGraphicsDeviceService));
|
||||
|
||||
if (!string.IsNullOrEmpty(Name))
|
||||
{
|
||||
Window.Title = Name;
|
||||
}
|
||||
}
|
||||
|
||||
[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; }
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace Jellyfish.Library
|
||||
{
|
||||
public class GameBase : Game
|
||||
{
|
||||
public GameBase() :
|
||||
this(null)
|
||||
{
|
||||
}
|
||||
|
||||
public GameBase(string name)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
Content.RootDirectory = "Content";
|
||||
GraphicsDeviceManager = new GraphicsDeviceManager(this);
|
||||
#if WINDOWS_PHONE
|
||||
GraphicsDeviceManager.IsFullScreen = true;
|
||||
TargetElapsedTime = TimeSpan.FromTicks(333333); // 30 fps
|
||||
#endif
|
||||
GraphicsDeviceService = (IGraphicsDeviceService)Services.GetService(typeof(IGraphicsDeviceService));
|
||||
|
||||
if (!string.IsNullOrEmpty(Name))
|
||||
{
|
||||
Window.Title = Name;
|
||||
}
|
||||
}
|
||||
|
||||
[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; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using Jellyfish.Library;
|
||||
|
||||
[assembly: AssemblyTitle("Library")]
|
||||
[assembly: AssemblyDescription("Common Library")]
|
||||
#if WINDOWS_PHONE
|
||||
[assembly: AssemblyProduct("Jellyfish.Library.Xna.Phone")]
|
||||
#elif XBOX
|
||||
[assembly: AssemblyProduct("Jellyfish.Library.Xna.Xbox")]
|
||||
#else
|
||||
[assembly: AssemblyProduct("Jellyfish.Library.Xna")]
|
||||
#endif
|
||||
[assembly: AssemblyCompany("Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2009-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett")]
|
||||
|
||||
[assembly: AssemblyVersion("0.1.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.1.3.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("66034b9e-9f0b-47b0-aac4-cade9a748891")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using Jellyfish.Library;
|
||||
|
||||
[assembly: AssemblyTitle("Library")]
|
||||
[assembly: AssemblyDescription("Common Library")]
|
||||
#if WINDOWS_PHONE
|
||||
[assembly: AssemblyProduct("Jellyfish.Library.Xna.Phone")]
|
||||
#elif XBOX
|
||||
[assembly: AssemblyProduct("Jellyfish.Library.Xna.Xbox")]
|
||||
#else
|
||||
[assembly: AssemblyProduct("Jellyfish.Library.Xna")]
|
||||
#endif
|
||||
[assembly: AssemblyCompany("Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2009-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett")]
|
||||
|
||||
[assembly: AssemblyVersion("0.1.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.1.3.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("66034b9e-9f0b-47b0-aac4-cade9a748891")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
|
|
678
License.txt
678
License.txt
|
@ -1,339 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class Cassette : MachineComponent
|
||||
{
|
||||
public Cassette(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
|
||||
public bool ReadInput()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
|
||||
public void ToggleOutput()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class Cassette : MachineComponent
|
||||
{
|
||||
public Cassette(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
|
||||
public bool ReadInput()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
|
||||
public void ToggleOutput()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
6452
Virtu/Cpu.cs
6452
Virtu/Cpu.cs
File diff suppressed because it is too large
Load Diff
166
Virtu/CpuData.cs
166
Virtu/CpuData.cs
|
@ -1,83 +1,83 @@
|
|||
using System;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public partial class Cpu
|
||||
{
|
||||
private const int OpCodeCount = 256;
|
||||
|
||||
private readonly Action[] ExecuteOpCode65N02;
|
||||
private readonly Action[] ExecuteOpCode65C02;
|
||||
|
||||
private const int PC = 0x01;
|
||||
private const int PZ = 0x02;
|
||||
private const int PI = 0x04;
|
||||
private const int PD = 0x08;
|
||||
private const int PB = 0x10;
|
||||
private const int PR = 0x20;
|
||||
private const int PV = 0x40;
|
||||
private const int PN = 0x80;
|
||||
|
||||
private const int DataCount = 256;
|
||||
|
||||
private static readonly int[] DataPN = new int[DataCount]
|
||||
{
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN
|
||||
};
|
||||
|
||||
private static readonly int[] DataPZ = new int[DataCount]
|
||||
{
|
||||
PZ, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
|
||||
};
|
||||
|
||||
private static readonly int[] DataPNZ = new int[DataCount]
|
||||
{
|
||||
PZ, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN
|
||||
};
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public partial class Cpu
|
||||
{
|
||||
private const int OpCodeCount = 256;
|
||||
|
||||
private readonly Action[] ExecuteOpCode65N02;
|
||||
private readonly Action[] ExecuteOpCode65C02;
|
||||
|
||||
private const int PC = 0x01;
|
||||
private const int PZ = 0x02;
|
||||
private const int PI = 0x04;
|
||||
private const int PD = 0x08;
|
||||
private const int PB = 0x10;
|
||||
private const int PR = 0x20;
|
||||
private const int PV = 0x40;
|
||||
private const int PN = 0x80;
|
||||
|
||||
private const int DataCount = 256;
|
||||
|
||||
private static readonly int[] DataPN = new int[DataCount]
|
||||
{
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN
|
||||
};
|
||||
|
||||
private static readonly int[] DataPZ = new int[DataCount]
|
||||
{
|
||||
PZ, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
|
||||
};
|
||||
|
||||
private static readonly int[] DataPNZ = new int[DataCount]
|
||||
{
|
||||
PZ, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN,
|
||||
PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN, PN
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Dictionary>
|
||||
<Acronyms>
|
||||
<CasingExceptions>
|
||||
<Acronym>Io</Acronym>
|
||||
<Acronym>RPC</Acronym>
|
||||
</CasingExceptions>
|
||||
</Acronyms>
|
||||
<Words>
|
||||
<Recognized>
|
||||
<Word>Annunciator</Word>
|
||||
<Word>Dsk</Word>
|
||||
<Word>Unpause</Word>
|
||||
<Word>Virtu</Word>
|
||||
<Word>Xna</Word>
|
||||
<Word>x</Word>
|
||||
<Word>y</Word>
|
||||
</Recognized>
|
||||
<Unrecognized>
|
||||
<Word>DownRight</Word>
|
||||
<Word>UpRight</Word>
|
||||
</Unrecognized>
|
||||
</Words>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Dictionary>
|
||||
<Acronyms>
|
||||
<CasingExceptions>
|
||||
<Acronym>Io</Acronym>
|
||||
<Acronym>RPC</Acronym>
|
||||
</CasingExceptions>
|
||||
</Acronyms>
|
||||
<Words>
|
||||
<Recognized>
|
||||
<Word>Annunciator</Word>
|
||||
<Word>Dsk</Word>
|
||||
<Word>Unpause</Word>
|
||||
<Word>Virtu</Word>
|
||||
<Word>Xna</Word>
|
||||
<Word>x</Word>
|
||||
<Word>y</Word>
|
||||
</Recognized>
|
||||
<Unrecognized>
|
||||
<Word>DownRight</Word>
|
||||
<Word>UpRight</Word>
|
||||
</Unrecognized>
|
||||
</Words>
|
||||
</Dictionary>
|
104
Virtu/Disk525.cs
104
Virtu/Disk525.cs
|
@ -1,52 +1,52 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public abstract class Disk525
|
||||
{
|
||||
protected Disk525(string name, byte[] data, bool isWriteProtected)
|
||||
{
|
||||
Name = name;
|
||||
Data = data;
|
||||
IsWriteProtected = isWriteProtected;
|
||||
}
|
||||
|
||||
public static Disk525 CreateDisk(string name, byte[] data, bool isWriteProtected)
|
||||
{
|
||||
if (name == null)
|
||||
{
|
||||
throw new ArgumentNullException("name");
|
||||
}
|
||||
if (data == null)
|
||||
{
|
||||
throw new ArgumentNullException("data");
|
||||
}
|
||||
|
||||
if (name.EndsWith(".nib", StringComparison.OrdinalIgnoreCase) && (data.Length == TrackCount * TrackSize))
|
||||
{
|
||||
return new DiskNib(name, data, isWriteProtected);
|
||||
}
|
||||
else if (name.EndsWith(".dsk", StringComparison.OrdinalIgnoreCase) && (data.Length == TrackCount * SectorCount * SectorSize))
|
||||
{
|
||||
return new DiskDsk(name, data, isWriteProtected);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract void ReadTrack(int number, int fraction, byte[] buffer);
|
||||
public abstract void WriteTrack(int number, int fraction, byte[] buffer);
|
||||
|
||||
public string Name { get; private set; }
|
||||
public bool IsWriteProtected { get; private set; }
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
protected byte[] Data { get; private set; }
|
||||
|
||||
public const int SectorCount = 16;
|
||||
public const int SectorSize = 0x100;
|
||||
public const int TrackCount = 35;
|
||||
public const int TrackSize = 0x1A00;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public abstract class Disk525
|
||||
{
|
||||
protected Disk525(string name, byte[] data, bool isWriteProtected)
|
||||
{
|
||||
Name = name;
|
||||
Data = data;
|
||||
IsWriteProtected = isWriteProtected;
|
||||
}
|
||||
|
||||
public static Disk525 CreateDisk(string name, byte[] data, bool isWriteProtected)
|
||||
{
|
||||
if (name == null)
|
||||
{
|
||||
throw new ArgumentNullException("name");
|
||||
}
|
||||
if (data == null)
|
||||
{
|
||||
throw new ArgumentNullException("data");
|
||||
}
|
||||
|
||||
if (name.EndsWith(".nib", StringComparison.OrdinalIgnoreCase) && (data.Length == TrackCount * TrackSize))
|
||||
{
|
||||
return new DiskNib(name, data, isWriteProtected);
|
||||
}
|
||||
else if (name.EndsWith(".dsk", StringComparison.OrdinalIgnoreCase) && (data.Length == TrackCount * SectorCount * SectorSize))
|
||||
{
|
||||
return new DiskDsk(name, data, isWriteProtected);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract void ReadTrack(int number, int fraction, byte[] buffer);
|
||||
public abstract void WriteTrack(int number, int fraction, byte[] buffer);
|
||||
|
||||
public string Name { get; private set; }
|
||||
public bool IsWriteProtected { get; private set; }
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
protected byte[] Data { get; private set; }
|
||||
|
||||
public const int SectorCount = 16;
|
||||
public const int SectorSize = 0x100;
|
||||
public const int TrackCount = 35;
|
||||
public const int TrackSize = 0x1A00;
|
||||
}
|
||||
}
|
||||
|
|
578
Virtu/DiskDsk.cs
578
Virtu/DiskDsk.cs
|
@ -1,289 +1,289 @@
|
|||
using System;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class DiskDsk : Disk525
|
||||
{
|
||||
public DiskDsk(string name, byte[] data, bool isWriteProtected) :
|
||||
base(name, data, isWriteProtected)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ReadTrack(int number, int fraction, byte[] buffer)
|
||||
{
|
||||
int track = number / 2;
|
||||
|
||||
_trackBuffer = buffer;
|
||||
_trackOffset = 0;
|
||||
|
||||
WriteNibble(0xFF, 48); // gap 0
|
||||
|
||||
for (int sector = 0; sector < SectorCount; sector++)
|
||||
{
|
||||
WriteNibble(0xD5); // address prologue
|
||||
WriteNibble(0xAA);
|
||||
WriteNibble(0x96);
|
||||
|
||||
WriteNibble44(Volume);
|
||||
WriteNibble44(track);
|
||||
WriteNibble44(sector);
|
||||
WriteNibble44(Volume ^ track ^ sector);
|
||||
|
||||
WriteNibble(0xDE); // address epilogue
|
||||
WriteNibble(0xAA);
|
||||
WriteNibble(0xEB);
|
||||
WriteNibble(0xFF, 8);
|
||||
|
||||
WriteNibble(0xD5); // data prologue
|
||||
WriteNibble(0xAA);
|
||||
WriteNibble(0xAD);
|
||||
|
||||
WriteDataNibbles((track * SectorCount + DosOrderToLogicalSector[sector]) * SectorSize);
|
||||
|
||||
WriteNibble(0xDE); // data epilogue
|
||||
WriteNibble(0xAA);
|
||||
WriteNibble(0xEB);
|
||||
WriteNibble(0xFF, 16);
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteTrack(int number, int fraction, byte[] buffer)
|
||||
{
|
||||
if (IsWriteProtected)
|
||||
return;
|
||||
|
||||
int track = number / 2;
|
||||
|
||||
_trackBuffer = buffer;
|
||||
_trackOffset = 0;
|
||||
int sectorsDone = 0;
|
||||
|
||||
for (int sector = 0; sector < SectorCount; sector++)
|
||||
{
|
||||
if (!Read3Nibbles(0xD5, 0xAA, 0x96, 0x304))
|
||||
break; // no address prologue
|
||||
|
||||
/*int readVolume = */ReadNibble44();
|
||||
|
||||
int readTrack = ReadNibble44();
|
||||
if (readTrack != track)
|
||||
break; // bad track number
|
||||
|
||||
int readSector = ReadNibble44();
|
||||
if (readSector > SectorCount)
|
||||
break; // bad sector number
|
||||
if ((sectorsDone & (0x1 << readSector)) != 0)
|
||||
break; // already done this sector
|
||||
|
||||
if (ReadNibble44() != (Volume ^ readTrack ^ readSector))
|
||||
break; // bad address checksum
|
||||
|
||||
if ((ReadNibble() != 0xDE) || (ReadNibble() != 0xAA))
|
||||
break; // bad address epilogue
|
||||
|
||||
if (!Read3Nibbles(0xD5, 0xAA, 0xAD, 0x20))
|
||||
break; // no data prologue
|
||||
|
||||
if (!ReadDataNibbles((track * SectorCount + DosOrderToLogicalSector[sector]) * SectorSize))
|
||||
break; // bad data checksum
|
||||
|
||||
if ((ReadNibble() != 0xDE) || (ReadNibble() != 0xAA))
|
||||
break; // bad data epilogue
|
||||
|
||||
sectorsDone |= 0x1 << sector;
|
||||
}
|
||||
|
||||
if (sectorsDone != 0xFFFF)
|
||||
throw new InvalidOperationException("disk error"); // TODO: we should alert the user and "dump" a NIB
|
||||
}
|
||||
|
||||
private byte ReadNibble()
|
||||
{
|
||||
byte data = _trackBuffer[_trackOffset];
|
||||
if (_trackOffset++ == TrackSize)
|
||||
{
|
||||
_trackOffset = 0;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private bool Read3Nibbles(byte data1, byte data2, byte data3, int maxReads)
|
||||
{
|
||||
bool result = false;
|
||||
while (--maxReads > 0)
|
||||
{
|
||||
if (ReadNibble() != data1)
|
||||
continue;
|
||||
|
||||
if (ReadNibble() != data2)
|
||||
continue;
|
||||
|
||||
if (ReadNibble() != data3)
|
||||
continue;
|
||||
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ReadNibble44()
|
||||
{
|
||||
return (((ReadNibble() << 1) | 0x1) & ReadNibble());
|
||||
}
|
||||
|
||||
private byte ReadTranslatedNibble()
|
||||
{
|
||||
byte data = NibbleToByte[ReadNibble()];
|
||||
// TODO: check that invalid nibbles aren't used
|
||||
// (put 0xFFs for invalid nibbles in the table)
|
||||
//if (data == 0xFF)
|
||||
//{
|
||||
//throw an exception
|
||||
//}
|
||||
return data;
|
||||
}
|
||||
|
||||
private bool ReadDataNibbles(int sectorOffset)
|
||||
{
|
||||
byte a, x, y;
|
||||
|
||||
y = SecondaryBufferLength;
|
||||
a = 0;
|
||||
do // fill and de-nibblize secondary buffer
|
||||
{
|
||||
a = _secondaryBuffer[--y] = (byte)(a ^ ReadTranslatedNibble());
|
||||
}
|
||||
while (y > 0);
|
||||
|
||||
do // fill and de-nibblize secondary buffer
|
||||
{
|
||||
a = _primaryBuffer[y++] = (byte)(a ^ ReadTranslatedNibble());
|
||||
}
|
||||
while (y != 0);
|
||||
|
||||
int checksum = a ^ ReadTranslatedNibble(); // should be 0
|
||||
|
||||
x = y = 0;
|
||||
do // decode data
|
||||
{
|
||||
if (x == 0)
|
||||
{
|
||||
x = SecondaryBufferLength;
|
||||
}
|
||||
a = (byte)((_primaryBuffer[y] << 2) | SwapBits[_secondaryBuffer[--x] & 0x03]);
|
||||
_secondaryBuffer[x] >>= 2;
|
||||
Data[sectorOffset + y] = a;
|
||||
}
|
||||
while (++y != 0);
|
||||
|
||||
return (checksum == 0);
|
||||
}
|
||||
|
||||
private void WriteNibble(int data)
|
||||
{
|
||||
_trackBuffer[_trackOffset++] = (byte)data;
|
||||
}
|
||||
|
||||
private void WriteNibble(int data, int count)
|
||||
{
|
||||
while (count-- > 0)
|
||||
{
|
||||
WriteNibble(data);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteNibble44(int data)
|
||||
{
|
||||
WriteNibble((data >> 1) | 0xAA);
|
||||
WriteNibble(data | 0xAA);
|
||||
}
|
||||
|
||||
private void WriteDataNibbles(int sectorOffset)
|
||||
{
|
||||
byte a, x, y;
|
||||
|
||||
for (x = 0; x < SecondaryBufferLength; x++)
|
||||
{
|
||||
_secondaryBuffer[x] = 0; // zero secondary buffer
|
||||
}
|
||||
|
||||
y = 2;
|
||||
do // fill buffers
|
||||
{
|
||||
x = 0;
|
||||
do
|
||||
{
|
||||
a = Data[sectorOffset + --y];
|
||||
_secondaryBuffer[x] = (byte)((_secondaryBuffer[x] << 2) | SwapBits[a & 0x03]); // b1,b0 -> secondary buffer
|
||||
_primaryBuffer[y] = (byte)(a >> 2); // b7-b2 -> primary buffer
|
||||
}
|
||||
while (++x < SecondaryBufferLength);
|
||||
}
|
||||
while (y != 0);
|
||||
|
||||
y = SecondaryBufferLength;
|
||||
do // write secondary buffer
|
||||
{
|
||||
WriteNibble(ByteToNibble[_secondaryBuffer[y] ^ _secondaryBuffer[y - 1]]);
|
||||
}
|
||||
while (--y != 0);
|
||||
|
||||
a = _secondaryBuffer[0];
|
||||
do // write primary buffer
|
||||
{
|
||||
WriteNibble(ByteToNibble[a ^ _primaryBuffer[y]]);
|
||||
a = _primaryBuffer[y];
|
||||
}
|
||||
while (++y != 0);
|
||||
|
||||
WriteNibble(ByteToNibble[a]); // data checksum
|
||||
}
|
||||
|
||||
private byte[] _trackBuffer;
|
||||
private int _trackOffset;
|
||||
private byte[] _primaryBuffer = new byte[0x100];
|
||||
private const int SecondaryBufferLength = 0x56;
|
||||
private byte[] _secondaryBuffer = new byte[SecondaryBufferLength + 1];
|
||||
private const int Volume = 0xFE;
|
||||
|
||||
private static readonly byte[] SwapBits = { 0, 2, 1, 3 };
|
||||
|
||||
private static readonly int[] DosOrderToLogicalSector = new int[]
|
||||
{
|
||||
0x0, 0x7, 0xE, 0x6, 0xD, 0x5, 0xC, 0x4, 0xB, 0x3, 0xA, 0x2, 0x9, 0x1, 0x8, 0xF
|
||||
};
|
||||
|
||||
private static readonly byte[] ByteToNibble = new byte[]
|
||||
{
|
||||
0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6, 0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3,
|
||||
0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xCB, 0xCD, 0xCE, 0xCF, 0xD3,
|
||||
0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC,
|
||||
0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
|
||||
};
|
||||
|
||||
private static readonly byte[] NibbleToByte = new byte[]
|
||||
{
|
||||
// padding for offset (not used)
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
|
||||
|
||||
// nibble translate table
|
||||
0x00, 0x01, 0x98, 0x99, 0x02, 0x03, 0x9C, 0x04, 0x05, 0x06,
|
||||
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x07, 0x08, 0xA8, 0xA9, 0xAA, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
|
||||
0xB0, 0xB1, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0xB8, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
|
||||
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0x1B, 0xCC, 0x1C, 0x1D, 0x1E,
|
||||
0xD0, 0xD1, 0xD2, 0x1F, 0xD4, 0xD5, 0x20, 0x21, 0xD8, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
||||
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0x29, 0x2A, 0x2B, 0xE8, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32,
|
||||
0xF0, 0xF1, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0xF8, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
|
||||
};
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class DiskDsk : Disk525
|
||||
{
|
||||
public DiskDsk(string name, byte[] data, bool isWriteProtected) :
|
||||
base(name, data, isWriteProtected)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ReadTrack(int number, int fraction, byte[] buffer)
|
||||
{
|
||||
int track = number / 2;
|
||||
|
||||
_trackBuffer = buffer;
|
||||
_trackOffset = 0;
|
||||
|
||||
WriteNibble(0xFF, 48); // gap 0
|
||||
|
||||
for (int sector = 0; sector < SectorCount; sector++)
|
||||
{
|
||||
WriteNibble(0xD5); // address prologue
|
||||
WriteNibble(0xAA);
|
||||
WriteNibble(0x96);
|
||||
|
||||
WriteNibble44(Volume);
|
||||
WriteNibble44(track);
|
||||
WriteNibble44(sector);
|
||||
WriteNibble44(Volume ^ track ^ sector);
|
||||
|
||||
WriteNibble(0xDE); // address epilogue
|
||||
WriteNibble(0xAA);
|
||||
WriteNibble(0xEB);
|
||||
WriteNibble(0xFF, 8);
|
||||
|
||||
WriteNibble(0xD5); // data prologue
|
||||
WriteNibble(0xAA);
|
||||
WriteNibble(0xAD);
|
||||
|
||||
WriteDataNibbles((track * SectorCount + DosOrderToLogicalSector[sector]) * SectorSize);
|
||||
|
||||
WriteNibble(0xDE); // data epilogue
|
||||
WriteNibble(0xAA);
|
||||
WriteNibble(0xEB);
|
||||
WriteNibble(0xFF, 16);
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteTrack(int number, int fraction, byte[] buffer)
|
||||
{
|
||||
if (IsWriteProtected)
|
||||
return;
|
||||
|
||||
int track = number / 2;
|
||||
|
||||
_trackBuffer = buffer;
|
||||
_trackOffset = 0;
|
||||
int sectorsDone = 0;
|
||||
|
||||
for (int sector = 0; sector < SectorCount; sector++)
|
||||
{
|
||||
if (!Read3Nibbles(0xD5, 0xAA, 0x96, 0x304))
|
||||
break; // no address prologue
|
||||
|
||||
/*int readVolume = */ReadNibble44();
|
||||
|
||||
int readTrack = ReadNibble44();
|
||||
if (readTrack != track)
|
||||
break; // bad track number
|
||||
|
||||
int readSector = ReadNibble44();
|
||||
if (readSector > SectorCount)
|
||||
break; // bad sector number
|
||||
if ((sectorsDone & (0x1 << readSector)) != 0)
|
||||
break; // already done this sector
|
||||
|
||||
if (ReadNibble44() != (Volume ^ readTrack ^ readSector))
|
||||
break; // bad address checksum
|
||||
|
||||
if ((ReadNibble() != 0xDE) || (ReadNibble() != 0xAA))
|
||||
break; // bad address epilogue
|
||||
|
||||
if (!Read3Nibbles(0xD5, 0xAA, 0xAD, 0x20))
|
||||
break; // no data prologue
|
||||
|
||||
if (!ReadDataNibbles((track * SectorCount + DosOrderToLogicalSector[sector]) * SectorSize))
|
||||
break; // bad data checksum
|
||||
|
||||
if ((ReadNibble() != 0xDE) || (ReadNibble() != 0xAA))
|
||||
break; // bad data epilogue
|
||||
|
||||
sectorsDone |= 0x1 << sector;
|
||||
}
|
||||
|
||||
if (sectorsDone != 0xFFFF)
|
||||
throw new InvalidOperationException("disk error"); // TODO: we should alert the user and "dump" a NIB
|
||||
}
|
||||
|
||||
private byte ReadNibble()
|
||||
{
|
||||
byte data = _trackBuffer[_trackOffset];
|
||||
if (_trackOffset++ == TrackSize)
|
||||
{
|
||||
_trackOffset = 0;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private bool Read3Nibbles(byte data1, byte data2, byte data3, int maxReads)
|
||||
{
|
||||
bool result = false;
|
||||
while (--maxReads > 0)
|
||||
{
|
||||
if (ReadNibble() != data1)
|
||||
continue;
|
||||
|
||||
if (ReadNibble() != data2)
|
||||
continue;
|
||||
|
||||
if (ReadNibble() != data3)
|
||||
continue;
|
||||
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ReadNibble44()
|
||||
{
|
||||
return (((ReadNibble() << 1) | 0x1) & ReadNibble());
|
||||
}
|
||||
|
||||
private byte ReadTranslatedNibble()
|
||||
{
|
||||
byte data = NibbleToByte[ReadNibble()];
|
||||
// TODO: check that invalid nibbles aren't used
|
||||
// (put 0xFFs for invalid nibbles in the table)
|
||||
//if (data == 0xFF)
|
||||
//{
|
||||
//throw an exception
|
||||
//}
|
||||
return data;
|
||||
}
|
||||
|
||||
private bool ReadDataNibbles(int sectorOffset)
|
||||
{
|
||||
byte a, x, y;
|
||||
|
||||
y = SecondaryBufferLength;
|
||||
a = 0;
|
||||
do // fill and de-nibblize secondary buffer
|
||||
{
|
||||
a = _secondaryBuffer[--y] = (byte)(a ^ ReadTranslatedNibble());
|
||||
}
|
||||
while (y > 0);
|
||||
|
||||
do // fill and de-nibblize secondary buffer
|
||||
{
|
||||
a = _primaryBuffer[y++] = (byte)(a ^ ReadTranslatedNibble());
|
||||
}
|
||||
while (y != 0);
|
||||
|
||||
int checksum = a ^ ReadTranslatedNibble(); // should be 0
|
||||
|
||||
x = y = 0;
|
||||
do // decode data
|
||||
{
|
||||
if (x == 0)
|
||||
{
|
||||
x = SecondaryBufferLength;
|
||||
}
|
||||
a = (byte)((_primaryBuffer[y] << 2) | SwapBits[_secondaryBuffer[--x] & 0x03]);
|
||||
_secondaryBuffer[x] >>= 2;
|
||||
Data[sectorOffset + y] = a;
|
||||
}
|
||||
while (++y != 0);
|
||||
|
||||
return (checksum == 0);
|
||||
}
|
||||
|
||||
private void WriteNibble(int data)
|
||||
{
|
||||
_trackBuffer[_trackOffset++] = (byte)data;
|
||||
}
|
||||
|
||||
private void WriteNibble(int data, int count)
|
||||
{
|
||||
while (count-- > 0)
|
||||
{
|
||||
WriteNibble(data);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteNibble44(int data)
|
||||
{
|
||||
WriteNibble((data >> 1) | 0xAA);
|
||||
WriteNibble(data | 0xAA);
|
||||
}
|
||||
|
||||
private void WriteDataNibbles(int sectorOffset)
|
||||
{
|
||||
byte a, x, y;
|
||||
|
||||
for (x = 0; x < SecondaryBufferLength; x++)
|
||||
{
|
||||
_secondaryBuffer[x] = 0; // zero secondary buffer
|
||||
}
|
||||
|
||||
y = 2;
|
||||
do // fill buffers
|
||||
{
|
||||
x = 0;
|
||||
do
|
||||
{
|
||||
a = Data[sectorOffset + --y];
|
||||
_secondaryBuffer[x] = (byte)((_secondaryBuffer[x] << 2) | SwapBits[a & 0x03]); // b1,b0 -> secondary buffer
|
||||
_primaryBuffer[y] = (byte)(a >> 2); // b7-b2 -> primary buffer
|
||||
}
|
||||
while (++x < SecondaryBufferLength);
|
||||
}
|
||||
while (y != 0);
|
||||
|
||||
y = SecondaryBufferLength;
|
||||
do // write secondary buffer
|
||||
{
|
||||
WriteNibble(ByteToNibble[_secondaryBuffer[y] ^ _secondaryBuffer[y - 1]]);
|
||||
}
|
||||
while (--y != 0);
|
||||
|
||||
a = _secondaryBuffer[0];
|
||||
do // write primary buffer
|
||||
{
|
||||
WriteNibble(ByteToNibble[a ^ _primaryBuffer[y]]);
|
||||
a = _primaryBuffer[y];
|
||||
}
|
||||
while (++y != 0);
|
||||
|
||||
WriteNibble(ByteToNibble[a]); // data checksum
|
||||
}
|
||||
|
||||
private byte[] _trackBuffer;
|
||||
private int _trackOffset;
|
||||
private byte[] _primaryBuffer = new byte[0x100];
|
||||
private const int SecondaryBufferLength = 0x56;
|
||||
private byte[] _secondaryBuffer = new byte[SecondaryBufferLength + 1];
|
||||
private const int Volume = 0xFE;
|
||||
|
||||
private static readonly byte[] SwapBits = { 0, 2, 1, 3 };
|
||||
|
||||
private static readonly int[] DosOrderToLogicalSector = new int[]
|
||||
{
|
||||
0x0, 0x7, 0xE, 0x6, 0xD, 0x5, 0xC, 0x4, 0xB, 0x3, 0xA, 0x2, 0x9, 0x1, 0x8, 0xF
|
||||
};
|
||||
|
||||
private static readonly byte[] ByteToNibble = new byte[]
|
||||
{
|
||||
0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6, 0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3,
|
||||
0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xCB, 0xCD, 0xCE, 0xCF, 0xD3,
|
||||
0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC,
|
||||
0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
|
||||
};
|
||||
|
||||
private static readonly byte[] NibbleToByte = new byte[]
|
||||
{
|
||||
// padding for offset (not used)
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
|
||||
|
||||
// nibble translate table
|
||||
0x00, 0x01, 0x98, 0x99, 0x02, 0x03, 0x9C, 0x04, 0x05, 0x06,
|
||||
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x07, 0x08, 0xA8, 0xA9, 0xAA, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
|
||||
0xB0, 0xB1, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0xB8, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
|
||||
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0x1B, 0xCC, 0x1C, 0x1D, 0x1E,
|
||||
0xD0, 0xD1, 0xD2, 0x1F, 0xD4, 0xD5, 0x20, 0x21, 0xD8, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
||||
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0x29, 0x2A, 0x2B, 0xE8, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32,
|
||||
0xF0, 0xF1, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0xF8, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,251 +1,251 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using Jellyfish.Library;
|
||||
using Jellyfish.Virtu.Services;
|
||||
using Jellyfish.Virtu.Settings;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class DiskIIController : PeripheralCard
|
||||
{
|
||||
public DiskIIController(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
var romStream = StorageService.GetResourceStream("Roms/DiskII.rom", 0x0100);
|
||||
romStream.ReadBlock(_romRegionC1C7, 0x0000, 0x0100);
|
||||
|
||||
_drives[0].InsertDisk("Default.dsk", StorageService.GetResourceStream("Disks/Default.dsk", 0x23000), false);
|
||||
#if WINDOWS
|
||||
var settings = Machine.Settings.DiskII;
|
||||
if (settings.Disk1.Name.Length > 0)
|
||||
{
|
||||
_drives[0].InsertDisk(settings.Disk1.Name, settings.Disk1.IsWriteProtected);
|
||||
}
|
||||
if (settings.Disk2.Name.Length > 0)
|
||||
{
|
||||
_drives[1].InsertDisk(settings.Disk2.Name, settings.Disk2.IsWriteProtected);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_phaseStates = 0;
|
||||
SetMotorOn(false);
|
||||
SetDriveNumber(0);
|
||||
_loadMode = false;
|
||||
_writeMode = false;
|
||||
}
|
||||
|
||||
public override void Uninitialize()
|
||||
{
|
||||
Flush();
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
|
||||
public override int ReadIoRegionC0C0(int address)
|
||||
{
|
||||
switch (address & 0xF)
|
||||
{
|
||||
case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
|
||||
SetPhase(address);
|
||||
break;
|
||||
|
||||
case 0x8:
|
||||
SetMotorOn(false);
|
||||
break;
|
||||
|
||||
case 0x9:
|
||||
SetMotorOn(true);
|
||||
break;
|
||||
|
||||
case 0xA:
|
||||
SetDriveNumber(0);
|
||||
break;
|
||||
|
||||
case 0xB:
|
||||
SetDriveNumber(1);
|
||||
break;
|
||||
|
||||
case 0xC:
|
||||
_loadMode = false;
|
||||
if (_motorOn)
|
||||
{
|
||||
if (!_writeMode)
|
||||
{
|
||||
return _latch = _drives[_driveNumber].Read();
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLatch();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD:
|
||||
_loadMode = true;
|
||||
if (_motorOn && !_writeMode)
|
||||
{
|
||||
// write protect is forced if phase 1 is on [F9.7]
|
||||
_latch &= 0x7F;
|
||||
if (_drives[_driveNumber].IsWriteProtected ||
|
||||
(_phaseStates & Phase1On) != 0)
|
||||
{
|
||||
_latch |= 0x80;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE:
|
||||
_writeMode = false;
|
||||
break;
|
||||
|
||||
case 0xF:
|
||||
_writeMode = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((address & 1) == 0)
|
||||
{
|
||||
// only even addresses return the latch
|
||||
if (_motorOn)
|
||||
{
|
||||
return _latch;
|
||||
}
|
||||
|
||||
// simple hack to fool DOS SAMESLOT drive spin check (usually at $BD34)
|
||||
_driveSpin = !_driveSpin;
|
||||
return _driveSpin ? 0x7E : 0x7F;
|
||||
}
|
||||
|
||||
return ReadFloatingBus();
|
||||
}
|
||||
|
||||
public override int ReadIoRegionC1C7(int address)
|
||||
{
|
||||
return _romRegionC1C7[address & 0xFF];
|
||||
}
|
||||
|
||||
public override void WriteIoRegionC0C0(int address, int data)
|
||||
{
|
||||
switch (address & 0xF)
|
||||
{
|
||||
case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
|
||||
SetPhase(address);
|
||||
break;
|
||||
|
||||
case 0x8:
|
||||
SetMotorOn(false);
|
||||
break;
|
||||
|
||||
case 0x9:
|
||||
SetMotorOn(true);
|
||||
break;
|
||||
|
||||
case 0xA:
|
||||
SetDriveNumber(0);
|
||||
break;
|
||||
|
||||
case 0xB:
|
||||
SetDriveNumber(1);
|
||||
break;
|
||||
|
||||
case 0xC:
|
||||
_loadMode = false;
|
||||
if (_writeMode)
|
||||
{
|
||||
WriteLatch();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD:
|
||||
_loadMode = true;
|
||||
break;
|
||||
|
||||
case 0xE:
|
||||
_writeMode = false;
|
||||
break;
|
||||
|
||||
case 0xF:
|
||||
_writeMode = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_motorOn && _writeMode)
|
||||
{
|
||||
if (_loadMode)
|
||||
{
|
||||
// any address writes latch for sequencer LD; OE1/2 irrelevant ['323 datasheet]
|
||||
_latch = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteLatch()
|
||||
{
|
||||
// write protect is forced if phase 1 is on [F9.7]
|
||||
if ((_phaseStates & Phase1On) == 0)
|
||||
{
|
||||
_drives[_driveNumber].Write(_latch);
|
||||
}
|
||||
}
|
||||
|
||||
private void Flush()
|
||||
{
|
||||
_drives[_driveNumber].FlushTrack();
|
||||
}
|
||||
|
||||
private void SetDriveNumber(int driveNumber)
|
||||
{
|
||||
if (_driveNumber != driveNumber)
|
||||
{
|
||||
Flush();
|
||||
_driveNumber = driveNumber;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetMotorOn(bool state)
|
||||
{
|
||||
if (_motorOn && !state)
|
||||
{
|
||||
Flush();
|
||||
}
|
||||
_motorOn = state;
|
||||
}
|
||||
|
||||
private void SetPhase(int address)
|
||||
{
|
||||
int phase = (address >> 1) & 0x3;
|
||||
int state = address & 1;
|
||||
_phaseStates &= ~(1 << phase);
|
||||
_phaseStates |= (state << phase);
|
||||
|
||||
if (_motorOn)
|
||||
{
|
||||
_drives[_driveNumber].ApplyPhaseChange(_phaseStates);
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public DiskIIDrive[] Drives { get { return _drives; } }
|
||||
|
||||
private const int Phase0On = 1 << 0;
|
||||
private const int Phase1On = 1 << 1;
|
||||
private const int Phase2On = 1 << 2;
|
||||
private const int Phase3On = 1 << 3;
|
||||
|
||||
private DiskIIDrive[] _drives = new DiskIIDrive[] { new DiskIIDrive(), new DiskIIDrive() };
|
||||
private int _latch;
|
||||
private int _phaseStates;
|
||||
private bool _motorOn;
|
||||
private int _driveNumber;
|
||||
private bool _loadMode;
|
||||
private bool _writeMode;
|
||||
private bool _driveSpin;
|
||||
|
||||
private byte[] _romRegionC1C7 = new byte[0x0100];
|
||||
}
|
||||
}
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Jellyfish.Library;
|
||||
using Jellyfish.Virtu.Services;
|
||||
using Jellyfish.Virtu.Settings;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class DiskIIController : PeripheralCard
|
||||
{
|
||||
public DiskIIController(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
var romStream = StorageService.GetResourceStream("Roms/DiskII.rom", 0x0100);
|
||||
romStream.ReadBlock(_romRegionC1C7, 0x0000, 0x0100);
|
||||
|
||||
_drives[0].InsertDisk("Default.dsk", StorageService.GetResourceStream("Disks/Default.dsk", 0x23000), false);
|
||||
#if WINDOWS
|
||||
var settings = Machine.Settings.DiskII;
|
||||
if (settings.Disk1.Name.Length > 0)
|
||||
{
|
||||
_drives[0].InsertDisk(settings.Disk1.Name, settings.Disk1.IsWriteProtected);
|
||||
}
|
||||
if (settings.Disk2.Name.Length > 0)
|
||||
{
|
||||
_drives[1].InsertDisk(settings.Disk2.Name, settings.Disk2.IsWriteProtected);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_phaseStates = 0;
|
||||
SetMotorOn(false);
|
||||
SetDriveNumber(0);
|
||||
_loadMode = false;
|
||||
_writeMode = false;
|
||||
}
|
||||
|
||||
public override void Uninitialize()
|
||||
{
|
||||
Flush();
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
|
||||
public override int ReadIoRegionC0C0(int address)
|
||||
{
|
||||
switch (address & 0xF)
|
||||
{
|
||||
case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
|
||||
SetPhase(address);
|
||||
break;
|
||||
|
||||
case 0x8:
|
||||
SetMotorOn(false);
|
||||
break;
|
||||
|
||||
case 0x9:
|
||||
SetMotorOn(true);
|
||||
break;
|
||||
|
||||
case 0xA:
|
||||
SetDriveNumber(0);
|
||||
break;
|
||||
|
||||
case 0xB:
|
||||
SetDriveNumber(1);
|
||||
break;
|
||||
|
||||
case 0xC:
|
||||
_loadMode = false;
|
||||
if (_motorOn)
|
||||
{
|
||||
if (!_writeMode)
|
||||
{
|
||||
return _latch = _drives[_driveNumber].Read();
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLatch();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD:
|
||||
_loadMode = true;
|
||||
if (_motorOn && !_writeMode)
|
||||
{
|
||||
// write protect is forced if phase 1 is on [F9.7]
|
||||
_latch &= 0x7F;
|
||||
if (_drives[_driveNumber].IsWriteProtected ||
|
||||
(_phaseStates & Phase1On) != 0)
|
||||
{
|
||||
_latch |= 0x80;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE:
|
||||
_writeMode = false;
|
||||
break;
|
||||
|
||||
case 0xF:
|
||||
_writeMode = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((address & 1) == 0)
|
||||
{
|
||||
// only even addresses return the latch
|
||||
if (_motorOn)
|
||||
{
|
||||
return _latch;
|
||||
}
|
||||
|
||||
// simple hack to fool DOS SAMESLOT drive spin check (usually at $BD34)
|
||||
_driveSpin = !_driveSpin;
|
||||
return _driveSpin ? 0x7E : 0x7F;
|
||||
}
|
||||
|
||||
return ReadFloatingBus();
|
||||
}
|
||||
|
||||
public override int ReadIoRegionC1C7(int address)
|
||||
{
|
||||
return _romRegionC1C7[address & 0xFF];
|
||||
}
|
||||
|
||||
public override void WriteIoRegionC0C0(int address, int data)
|
||||
{
|
||||
switch (address & 0xF)
|
||||
{
|
||||
case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
|
||||
SetPhase(address);
|
||||
break;
|
||||
|
||||
case 0x8:
|
||||
SetMotorOn(false);
|
||||
break;
|
||||
|
||||
case 0x9:
|
||||
SetMotorOn(true);
|
||||
break;
|
||||
|
||||
case 0xA:
|
||||
SetDriveNumber(0);
|
||||
break;
|
||||
|
||||
case 0xB:
|
||||
SetDriveNumber(1);
|
||||
break;
|
||||
|
||||
case 0xC:
|
||||
_loadMode = false;
|
||||
if (_writeMode)
|
||||
{
|
||||
WriteLatch();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD:
|
||||
_loadMode = true;
|
||||
break;
|
||||
|
||||
case 0xE:
|
||||
_writeMode = false;
|
||||
break;
|
||||
|
||||
case 0xF:
|
||||
_writeMode = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_motorOn && _writeMode)
|
||||
{
|
||||
if (_loadMode)
|
||||
{
|
||||
// any address writes latch for sequencer LD; OE1/2 irrelevant ['323 datasheet]
|
||||
_latch = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteLatch()
|
||||
{
|
||||
// write protect is forced if phase 1 is on [F9.7]
|
||||
if ((_phaseStates & Phase1On) == 0)
|
||||
{
|
||||
_drives[_driveNumber].Write(_latch);
|
||||
}
|
||||
}
|
||||
|
||||
private void Flush()
|
||||
{
|
||||
_drives[_driveNumber].FlushTrack();
|
||||
}
|
||||
|
||||
private void SetDriveNumber(int driveNumber)
|
||||
{
|
||||
if (_driveNumber != driveNumber)
|
||||
{
|
||||
Flush();
|
||||
_driveNumber = driveNumber;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetMotorOn(bool state)
|
||||
{
|
||||
if (_motorOn && !state)
|
||||
{
|
||||
Flush();
|
||||
}
|
||||
_motorOn = state;
|
||||
}
|
||||
|
||||
private void SetPhase(int address)
|
||||
{
|
||||
int phase = (address >> 1) & 0x3;
|
||||
int state = address & 1;
|
||||
_phaseStates &= ~(1 << phase);
|
||||
_phaseStates |= (state << phase);
|
||||
|
||||
if (_motorOn)
|
||||
{
|
||||
_drives[_driveNumber].ApplyPhaseChange(_phaseStates);
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public DiskIIDrive[] Drives { get { return _drives; } }
|
||||
|
||||
private const int Phase0On = 1 << 0;
|
||||
private const int Phase1On = 1 << 1;
|
||||
private const int Phase2On = 1 << 2;
|
||||
private const int Phase3On = 1 << 3;
|
||||
|
||||
private DiskIIDrive[] _drives = new DiskIIDrive[] { new DiskIIDrive(), new DiskIIDrive() };
|
||||
private int _latch;
|
||||
private int _phaseStates;
|
||||
private bool _motorOn;
|
||||
private int _driveNumber;
|
||||
private bool _loadMode;
|
||||
private bool _writeMode;
|
||||
private bool _driveSpin;
|
||||
|
||||
private byte[] _romRegionC1C7 = new byte[0x0100];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,120 +1,120 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Security;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class DiskIIDrive
|
||||
{
|
||||
public DiskIIDrive()
|
||||
{
|
||||
DriveArmStepDelta[0] = new int[] { 0, 0, 1, 1, 0, 0, 1, 1, -1, -1, 0, 0, -1, -1, 0, 0 }; // phase 0
|
||||
DriveArmStepDelta[1] = new int[] { 0, -1, 0, -1, 1, 0, 1, 0, 0, -1, 0, -1, 1, 0, 1, 0 }; // phase 1
|
||||
DriveArmStepDelta[2] = new int[] { 0, 0, -1, -1, 0, 0, -1, -1, 1, 1, 0, 0, 1, 1, 0, 0 }; // phase 2
|
||||
DriveArmStepDelta[3] = new int[] { 0, 1, 0, 1, -1, 0, -1, 0, 0, 1, 0, 1, -1, 0, -1, 0 }; // phase 3
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public void InsertDisk(string fileName, bool isWriteProtected)
|
||||
{
|
||||
using (var stream = File.OpenRead(fileName))
|
||||
{
|
||||
InsertDisk(fileName, stream, isWriteProtected);
|
||||
}
|
||||
}
|
||||
|
||||
public void InsertDisk(string name, Stream stream, bool isWriteProtected)
|
||||
{
|
||||
FlushTrack();
|
||||
|
||||
// TODO handle null param/empty string for eject, or add Eject()
|
||||
|
||||
_disk = Disk525.CreateDisk(name, stream.ReadAllBytes(), isWriteProtected);
|
||||
_trackLoaded = false;
|
||||
}
|
||||
|
||||
public void ApplyPhaseChange(int phaseState)
|
||||
{
|
||||
// step the drive head according to stepper magnet changes
|
||||
int delta = DriveArmStepDelta[_trackNumber & 0x3][phaseState];
|
||||
if (delta != 0)
|
||||
{
|
||||
int newTrackNumber = MathHelpers.Clamp(_trackNumber + delta, 0, TrackNumberMax);
|
||||
if (newTrackNumber != _trackNumber)
|
||||
{
|
||||
FlushTrack();
|
||||
_trackNumber = newTrackNumber;
|
||||
_trackOffset = 0;
|
||||
_trackLoaded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Read()
|
||||
{
|
||||
if (LoadTrack())
|
||||
{
|
||||
int data = _trackData[_trackOffset++];
|
||||
if (_trackOffset >= Disk525.TrackSize)
|
||||
{
|
||||
_trackOffset = 0;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
return _random.Next(0x01, 0xFF);
|
||||
}
|
||||
|
||||
public void Write(int data)
|
||||
{
|
||||
if (LoadTrack())
|
||||
{
|
||||
_trackChanged = true;
|
||||
_trackData[_trackOffset++] = (byte)data;
|
||||
if (_trackOffset >= Disk525.TrackSize)
|
||||
{
|
||||
_trackOffset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool LoadTrack()
|
||||
{
|
||||
if (!_trackLoaded && (_disk != null))
|
||||
{
|
||||
_disk.ReadTrack(_trackNumber, 0, _trackData);
|
||||
_trackLoaded = true;
|
||||
}
|
||||
|
||||
return _trackLoaded;
|
||||
}
|
||||
|
||||
public void FlushTrack()
|
||||
{
|
||||
if (_trackChanged)
|
||||
{
|
||||
_disk.WriteTrack(_trackNumber, 0, _trackData);
|
||||
_trackChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsWriteProtected { get { return _disk.IsWriteProtected; } }
|
||||
|
||||
private const int TrackNumberMax = 0x44;
|
||||
|
||||
private const int PhaseCount = 4;
|
||||
|
||||
private readonly int[][] DriveArmStepDelta = new int[PhaseCount][];
|
||||
|
||||
private Disk525 _disk;
|
||||
private bool _trackLoaded;
|
||||
private bool _trackChanged;
|
||||
private int _trackNumber;
|
||||
private int _trackOffset;
|
||||
private byte[] _trackData = new byte[Disk525.TrackSize];
|
||||
|
||||
private Random _random = new Random();
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class DiskIIDrive
|
||||
{
|
||||
public DiskIIDrive()
|
||||
{
|
||||
DriveArmStepDelta[0] = new int[] { 0, 0, 1, 1, 0, 0, 1, 1, -1, -1, 0, 0, -1, -1, 0, 0 }; // phase 0
|
||||
DriveArmStepDelta[1] = new int[] { 0, -1, 0, -1, 1, 0, 1, 0, 0, -1, 0, -1, 1, 0, 1, 0 }; // phase 1
|
||||
DriveArmStepDelta[2] = new int[] { 0, 0, -1, -1, 0, 0, -1, -1, 1, 1, 0, 0, 1, 1, 0, 0 }; // phase 2
|
||||
DriveArmStepDelta[3] = new int[] { 0, 1, 0, 1, -1, 0, -1, 0, 0, 1, 0, 1, -1, 0, -1, 0 }; // phase 3
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public void InsertDisk(string fileName, bool isWriteProtected)
|
||||
{
|
||||
using (var stream = File.OpenRead(fileName))
|
||||
{
|
||||
InsertDisk(fileName, stream, isWriteProtected);
|
||||
}
|
||||
}
|
||||
|
||||
public void InsertDisk(string name, Stream stream, bool isWriteProtected)
|
||||
{
|
||||
FlushTrack();
|
||||
|
||||
// TODO handle null param/empty string for eject, or add Eject()
|
||||
|
||||
_disk = Disk525.CreateDisk(name, stream.ReadAllBytes(), isWriteProtected);
|
||||
_trackLoaded = false;
|
||||
}
|
||||
|
||||
public void ApplyPhaseChange(int phaseState)
|
||||
{
|
||||
// step the drive head according to stepper magnet changes
|
||||
int delta = DriveArmStepDelta[_trackNumber & 0x3][phaseState];
|
||||
if (delta != 0)
|
||||
{
|
||||
int newTrackNumber = MathHelpers.Clamp(_trackNumber + delta, 0, TrackNumberMax);
|
||||
if (newTrackNumber != _trackNumber)
|
||||
{
|
||||
FlushTrack();
|
||||
_trackNumber = newTrackNumber;
|
||||
_trackOffset = 0;
|
||||
_trackLoaded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Read()
|
||||
{
|
||||
if (LoadTrack())
|
||||
{
|
||||
int data = _trackData[_trackOffset++];
|
||||
if (_trackOffset >= Disk525.TrackSize)
|
||||
{
|
||||
_trackOffset = 0;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
return _random.Next(0x01, 0xFF);
|
||||
}
|
||||
|
||||
public void Write(int data)
|
||||
{
|
||||
if (LoadTrack())
|
||||
{
|
||||
_trackChanged = true;
|
||||
_trackData[_trackOffset++] = (byte)data;
|
||||
if (_trackOffset >= Disk525.TrackSize)
|
||||
{
|
||||
_trackOffset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool LoadTrack()
|
||||
{
|
||||
if (!_trackLoaded && (_disk != null))
|
||||
{
|
||||
_disk.ReadTrack(_trackNumber, 0, _trackData);
|
||||
_trackLoaded = true;
|
||||
}
|
||||
|
||||
return _trackLoaded;
|
||||
}
|
||||
|
||||
public void FlushTrack()
|
||||
{
|
||||
if (_trackChanged)
|
||||
{
|
||||
_disk.WriteTrack(_trackNumber, 0, _trackData);
|
||||
_trackChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsWriteProtected { get { return _disk.IsWriteProtected; } }
|
||||
|
||||
private const int TrackNumberMax = 0x44;
|
||||
|
||||
private const int PhaseCount = 4;
|
||||
|
||||
private readonly int[][] DriveArmStepDelta = new int[PhaseCount][];
|
||||
|
||||
private Disk525 _disk;
|
||||
private bool _trackLoaded;
|
||||
private bool _trackChanged;
|
||||
private int _trackNumber;
|
||||
private int _trackOffset;
|
||||
private byte[] _trackData = new byte[Disk525.TrackSize];
|
||||
|
||||
private Random _random = new Random();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
using System;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class DiskNib : Disk525
|
||||
{
|
||||
public DiskNib(string name, byte[] data, bool isWriteProtected) :
|
||||
base(name, data, isWriteProtected)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ReadTrack(int number, int fraction, byte[] buffer)
|
||||
{
|
||||
Buffer.BlockCopy(Data, (number / 2) * TrackSize, buffer, 0, TrackSize);
|
||||
}
|
||||
|
||||
public override void WriteTrack(int number, int fraction, byte[] buffer)
|
||||
{
|
||||
Buffer.BlockCopy(buffer, 0, Data, (number / 2) * TrackSize, TrackSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class DiskNib : Disk525
|
||||
{
|
||||
public DiskNib(string name, byte[] data, bool isWriteProtected) :
|
||||
base(name, data, isWriteProtected)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ReadTrack(int number, int fraction, byte[] buffer)
|
||||
{
|
||||
Buffer.BlockCopy(Data, (number / 2) * TrackSize, buffer, 0, TrackSize);
|
||||
}
|
||||
|
||||
public override void WriteTrack(int number, int fraction, byte[] buffer)
|
||||
{
|
||||
Buffer.BlockCopy(buffer, 0, Data, (number / 2) * TrackSize, TrackSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,157 +1,157 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Jellyfish.Library;
|
||||
using Jellyfish.Virtu.Services;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class GamePort : MachineComponent
|
||||
{
|
||||
public GamePort(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
_resetPaddle0StrobeEvent = ResetPaddle0StrobeEvent; // cache delegates; avoids garbage
|
||||
_resetPaddle1StrobeEvent = ResetPaddle1StrobeEvent;
|
||||
_resetPaddle2StrobeEvent = ResetPaddle2StrobeEvent;
|
||||
_resetPaddle3StrobeEvent = ResetPaddle3StrobeEvent;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
_keyboardService = Machine.Services.GetService<KeyboardService>();
|
||||
_gamePortService = Machine.Services.GetService<GamePortService>();
|
||||
}
|
||||
|
||||
public bool ReadButton0()
|
||||
{
|
||||
var settings = Machine.Settings.GamePort;
|
||||
|
||||
return (_gamePortService.IsButton0Down || _keyboardService.IsOpenAppleKeyDown ||
|
||||
(settings.UseKeyboard && (settings.Key.Button0 > 0) && _keyboardService.IsKeyDown(settings.Key.Button0)));
|
||||
}
|
||||
|
||||
public bool ReadButton1()
|
||||
{
|
||||
var settings = Machine.Settings.GamePort;
|
||||
|
||||
return (_gamePortService.IsButton1Down || _keyboardService.IsCloseAppleKeyDown ||
|
||||
(settings.UseKeyboard && (settings.Key.Button1 > 0) && _keyboardService.IsKeyDown(settings.Key.Button1)));
|
||||
}
|
||||
|
||||
public bool ReadButton2()
|
||||
{
|
||||
var settings = Machine.Settings.GamePort;
|
||||
|
||||
return (_gamePortService.IsButton2Down || _keyboardService.IsShiftKeyDown || // [TN9]
|
||||
(settings.UseKeyboard && (settings.Key.Button2 > 0) && _keyboardService.IsKeyDown(settings.Key.Button2)));
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
|
||||
public void TriggerTimers()
|
||||
{
|
||||
int paddle0 = _gamePortService.Paddle0;
|
||||
int paddle1 = _gamePortService.Paddle1;
|
||||
int paddle2 = _gamePortService.Paddle2;
|
||||
int paddle3 = _gamePortService.Paddle3;
|
||||
|
||||
var settings = Machine.Settings.GamePort;
|
||||
|
||||
if (settings.UseKeyboard) // override
|
||||
{
|
||||
if (((settings.Key.Joystick0.UpLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.UpLeft)) ||
|
||||
((settings.Key.Joystick0.Left > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.Left)) ||
|
||||
((settings.Key.Joystick0.DownLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.DownLeft)))
|
||||
{
|
||||
paddle0 -= 128;
|
||||
}
|
||||
if (((settings.Key.Joystick0.UpRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.UpRight)) ||
|
||||
((settings.Key.Joystick0.Right > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.Right)) ||
|
||||
((settings.Key.Joystick0.DownRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.DownRight)))
|
||||
{
|
||||
paddle0 += 128;
|
||||
}
|
||||
if (((settings.Key.Joystick0.UpLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.UpLeft)) ||
|
||||
((settings.Key.Joystick0.Up > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.Up)) ||
|
||||
((settings.Key.Joystick0.UpRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.UpRight)))
|
||||
{
|
||||
paddle1 -= 128;
|
||||
}
|
||||
if (((settings.Key.Joystick0.DownLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.DownLeft)) ||
|
||||
((settings.Key.Joystick0.Down > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.Down)) ||
|
||||
((settings.Key.Joystick0.DownRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.DownRight)))
|
||||
{
|
||||
paddle1 += 128;
|
||||
}
|
||||
if (((settings.Key.Joystick1.UpLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.UpLeft)) ||
|
||||
((settings.Key.Joystick1.Left > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.Left)) ||
|
||||
((settings.Key.Joystick1.DownLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.DownLeft)))
|
||||
{
|
||||
paddle2 -= 128;
|
||||
}
|
||||
if (((settings.Key.Joystick1.UpRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.UpRight)) ||
|
||||
((settings.Key.Joystick1.Right > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.Right)) ||
|
||||
((settings.Key.Joystick1.DownRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.DownRight)))
|
||||
{
|
||||
paddle2 += 128;
|
||||
}
|
||||
if (((settings.Key.Joystick1.UpLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.UpLeft)) ||
|
||||
((settings.Key.Joystick1.Up > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.Up)) ||
|
||||
((settings.Key.Joystick1.UpRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.UpRight)))
|
||||
{
|
||||
paddle3 -= 128;
|
||||
}
|
||||
if (((settings.Key.Joystick1.DownLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.DownLeft)) ||
|
||||
((settings.Key.Joystick1.Down > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.Down)) ||
|
||||
((settings.Key.Joystick1.DownRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.DownRight)))
|
||||
{
|
||||
paddle3 += 128;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private void ResetPaddle0StrobeEvent()
|
||||
{
|
||||
Paddle0Strobe = false;
|
||||
}
|
||||
|
||||
private void ResetPaddle1StrobeEvent()
|
||||
{
|
||||
Paddle1Strobe = false;
|
||||
}
|
||||
|
||||
private void ResetPaddle2StrobeEvent()
|
||||
{
|
||||
Paddle2Strobe = false;
|
||||
}
|
||||
|
||||
private void ResetPaddle3StrobeEvent()
|
||||
{
|
||||
Paddle3Strobe = false;
|
||||
}
|
||||
|
||||
public bool Paddle0Strobe { get; private set; }
|
||||
public bool Paddle1Strobe { get; private set; }
|
||||
public bool Paddle2Strobe { get; private set; }
|
||||
public bool Paddle3Strobe { get; private set; }
|
||||
|
||||
private const int CyclesPerValue = 11;
|
||||
|
||||
private Action _resetPaddle0StrobeEvent;
|
||||
private Action _resetPaddle1StrobeEvent;
|
||||
private Action _resetPaddle2StrobeEvent;
|
||||
private Action _resetPaddle3StrobeEvent;
|
||||
|
||||
private KeyboardService _keyboardService;
|
||||
private GamePortService _gamePortService;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Jellyfish.Library;
|
||||
using Jellyfish.Virtu.Services;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class GamePort : MachineComponent
|
||||
{
|
||||
public GamePort(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
_resetPaddle0StrobeEvent = ResetPaddle0StrobeEvent; // cache delegates; avoids garbage
|
||||
_resetPaddle1StrobeEvent = ResetPaddle1StrobeEvent;
|
||||
_resetPaddle2StrobeEvent = ResetPaddle2StrobeEvent;
|
||||
_resetPaddle3StrobeEvent = ResetPaddle3StrobeEvent;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
_keyboardService = Machine.Services.GetService<KeyboardService>();
|
||||
_gamePortService = Machine.Services.GetService<GamePortService>();
|
||||
}
|
||||
|
||||
public bool ReadButton0()
|
||||
{
|
||||
var settings = Machine.Settings.GamePort;
|
||||
|
||||
return (_gamePortService.IsButton0Down || _keyboardService.IsOpenAppleKeyDown ||
|
||||
(settings.UseKeyboard && (settings.Key.Button0 > 0) && _keyboardService.IsKeyDown(settings.Key.Button0)));
|
||||
}
|
||||
|
||||
public bool ReadButton1()
|
||||
{
|
||||
var settings = Machine.Settings.GamePort;
|
||||
|
||||
return (_gamePortService.IsButton1Down || _keyboardService.IsCloseAppleKeyDown ||
|
||||
(settings.UseKeyboard && (settings.Key.Button1 > 0) && _keyboardService.IsKeyDown(settings.Key.Button1)));
|
||||
}
|
||||
|
||||
public bool ReadButton2()
|
||||
{
|
||||
var settings = Machine.Settings.GamePort;
|
||||
|
||||
return (_gamePortService.IsButton2Down || _keyboardService.IsShiftKeyDown || // [TN9]
|
||||
(settings.UseKeyboard && (settings.Key.Button2 > 0) && _keyboardService.IsKeyDown(settings.Key.Button2)));
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
|
||||
public void TriggerTimers()
|
||||
{
|
||||
int paddle0 = _gamePortService.Paddle0;
|
||||
int paddle1 = _gamePortService.Paddle1;
|
||||
int paddle2 = _gamePortService.Paddle2;
|
||||
int paddle3 = _gamePortService.Paddle3;
|
||||
|
||||
var settings = Machine.Settings.GamePort;
|
||||
|
||||
if (settings.UseKeyboard) // override
|
||||
{
|
||||
if (((settings.Key.Joystick0.UpLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.UpLeft)) ||
|
||||
((settings.Key.Joystick0.Left > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.Left)) ||
|
||||
((settings.Key.Joystick0.DownLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.DownLeft)))
|
||||
{
|
||||
paddle0 -= 128;
|
||||
}
|
||||
if (((settings.Key.Joystick0.UpRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.UpRight)) ||
|
||||
((settings.Key.Joystick0.Right > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.Right)) ||
|
||||
((settings.Key.Joystick0.DownRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.DownRight)))
|
||||
{
|
||||
paddle0 += 128;
|
||||
}
|
||||
if (((settings.Key.Joystick0.UpLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.UpLeft)) ||
|
||||
((settings.Key.Joystick0.Up > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.Up)) ||
|
||||
((settings.Key.Joystick0.UpRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.UpRight)))
|
||||
{
|
||||
paddle1 -= 128;
|
||||
}
|
||||
if (((settings.Key.Joystick0.DownLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.DownLeft)) ||
|
||||
((settings.Key.Joystick0.Down > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.Down)) ||
|
||||
((settings.Key.Joystick0.DownRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick0.DownRight)))
|
||||
{
|
||||
paddle1 += 128;
|
||||
}
|
||||
if (((settings.Key.Joystick1.UpLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.UpLeft)) ||
|
||||
((settings.Key.Joystick1.Left > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.Left)) ||
|
||||
((settings.Key.Joystick1.DownLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.DownLeft)))
|
||||
{
|
||||
paddle2 -= 128;
|
||||
}
|
||||
if (((settings.Key.Joystick1.UpRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.UpRight)) ||
|
||||
((settings.Key.Joystick1.Right > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.Right)) ||
|
||||
((settings.Key.Joystick1.DownRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.DownRight)))
|
||||
{
|
||||
paddle2 += 128;
|
||||
}
|
||||
if (((settings.Key.Joystick1.UpLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.UpLeft)) ||
|
||||
((settings.Key.Joystick1.Up > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.Up)) ||
|
||||
((settings.Key.Joystick1.UpRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.UpRight)))
|
||||
{
|
||||
paddle3 -= 128;
|
||||
}
|
||||
if (((settings.Key.Joystick1.DownLeft > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.DownLeft)) ||
|
||||
((settings.Key.Joystick1.Down > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.Down)) ||
|
||||
((settings.Key.Joystick1.DownRight > 0) && _keyboardService.IsKeyDown(settings.Key.Joystick1.DownRight)))
|
||||
{
|
||||
paddle3 += 128;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private void ResetPaddle0StrobeEvent()
|
||||
{
|
||||
Paddle0Strobe = false;
|
||||
}
|
||||
|
||||
private void ResetPaddle1StrobeEvent()
|
||||
{
|
||||
Paddle1Strobe = false;
|
||||
}
|
||||
|
||||
private void ResetPaddle2StrobeEvent()
|
||||
{
|
||||
Paddle2Strobe = false;
|
||||
}
|
||||
|
||||
private void ResetPaddle3StrobeEvent()
|
||||
{
|
||||
Paddle3Strobe = false;
|
||||
}
|
||||
|
||||
public bool Paddle0Strobe { get; private set; }
|
||||
public bool Paddle1Strobe { get; private set; }
|
||||
public bool Paddle2Strobe { get; private set; }
|
||||
public bool Paddle3Strobe { get; private set; }
|
||||
|
||||
private const int CyclesPerValue = 11;
|
||||
|
||||
private Action _resetPaddle0StrobeEvent;
|
||||
private Action _resetPaddle1StrobeEvent;
|
||||
private Action _resetPaddle2StrobeEvent;
|
||||
private Action _resetPaddle3StrobeEvent;
|
||||
|
||||
private KeyboardService _keyboardService;
|
||||
private GamePortService _gamePortService;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
[assembly: SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames")]
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
[assembly: SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames")]
|
||||
|
|
|
@ -1,128 +1,128 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using Jellyfish.Virtu.Services;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class Keyboard : MachineComponent
|
||||
{
|
||||
public Keyboard(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
_keyboardService = Machine.Services.GetService<KeyboardService>();
|
||||
_gamePortService = Machine.Services.GetService<GamePortService>();
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
|
||||
public int ReadLatch()
|
||||
{
|
||||
if (Strobe)
|
||||
{
|
||||
return Latch;
|
||||
}
|
||||
|
||||
var settings = Machine.Settings.Keyboard;
|
||||
|
||||
if (settings.UseGamePort)
|
||||
{
|
||||
if ((settings.Key.Joystick0.UpLeft > 0) && _gamePortService.Joystick0.IsUp && _gamePortService.Joystick0.IsLeft)
|
||||
{
|
||||
Latch = settings.Key.Joystick0.UpLeft;
|
||||
}
|
||||
else if ((settings.Key.Joystick0.UpRight > 0) && _gamePortService.Joystick0.IsUp && _gamePortService.Joystick0.IsRight)
|
||||
{
|
||||
Latch = settings.Key.Joystick0.UpRight;
|
||||
}
|
||||
else if ((settings.Key.Joystick0.DownLeft > 0) && _gamePortService.Joystick0.IsDown && _gamePortService.Joystick0.IsLeft)
|
||||
{
|
||||
Latch = settings.Key.Joystick0.DownLeft;
|
||||
}
|
||||
else if ((settings.Key.Joystick0.DownRight > 0) && _gamePortService.Joystick0.IsDown && _gamePortService.Joystick0.IsRight)
|
||||
{
|
||||
Latch = settings.Key.Joystick0.DownRight;
|
||||
}
|
||||
else if ((settings.Key.Joystick0.Up > 0) && _gamePortService.Joystick0.IsUp)
|
||||
{
|
||||
Latch = settings.Key.Joystick0.Up;
|
||||
}
|
||||
else if ((settings.Key.Joystick0.Left > 0) && _gamePortService.Joystick0.IsLeft)
|
||||
{
|
||||
Latch = settings.Key.Joystick0.Left;
|
||||
}
|
||||
else if ((settings.Key.Joystick0.Right > 0) && _gamePortService.Joystick0.IsRight)
|
||||
{
|
||||
Latch = settings.Key.Joystick0.Right;
|
||||
}
|
||||
else if ((settings.Key.Joystick0.Down > 0) && _gamePortService.Joystick0.IsDown)
|
||||
{
|
||||
Latch = settings.Key.Joystick0.Down;
|
||||
}
|
||||
|
||||
if ((settings.Key.Joystick1.UpLeft > 0) && _gamePortService.Joystick1.IsUp && _gamePortService.Joystick1.IsLeft) // override
|
||||
{
|
||||
Latch = settings.Key.Joystick1.UpLeft;
|
||||
}
|
||||
else if ((settings.Key.Joystick1.UpRight > 0) && _gamePortService.Joystick1.IsUp && _gamePortService.Joystick1.IsRight)
|
||||
{
|
||||
Latch = settings.Key.Joystick1.UpRight;
|
||||
}
|
||||
else if ((settings.Key.Joystick1.DownLeft > 0) && _gamePortService.Joystick1.IsDown && _gamePortService.Joystick1.IsLeft)
|
||||
{
|
||||
Latch = settings.Key.Joystick1.DownLeft;
|
||||
}
|
||||
else if ((settings.Key.Joystick1.DownRight > 0) && _gamePortService.Joystick1.IsDown && _gamePortService.Joystick1.IsRight)
|
||||
{
|
||||
Latch = settings.Key.Joystick1.DownRight;
|
||||
}
|
||||
else if ((settings.Key.Joystick1.Up > 0) && _gamePortService.Joystick1.IsUp)
|
||||
{
|
||||
Latch = settings.Key.Joystick1.Up;
|
||||
}
|
||||
else if ((settings.Key.Joystick1.Left > 0) && _gamePortService.Joystick1.IsLeft)
|
||||
{
|
||||
Latch = settings.Key.Joystick1.Left;
|
||||
}
|
||||
else if ((settings.Key.Joystick1.Right > 0) && _gamePortService.Joystick1.IsRight)
|
||||
{
|
||||
Latch = settings.Key.Joystick1.Right;
|
||||
}
|
||||
else if ((settings.Key.Joystick1.Down > 0) && _gamePortService.Joystick1.IsDown)
|
||||
{
|
||||
Latch = settings.Key.Joystick1.Down;
|
||||
}
|
||||
|
||||
if ((settings.Key.Button0 > 0) && _gamePortService.IsButton0Down) // override
|
||||
{
|
||||
Latch = settings.Key.Button0;
|
||||
}
|
||||
else if ((settings.Key.Button1 > 0) && _gamePortService.IsButton1Down)
|
||||
{
|
||||
Latch = settings.Key.Button1;
|
||||
}
|
||||
else if ((settings.Key.Button2 > 0) && _gamePortService.IsButton2Down)
|
||||
{
|
||||
Latch = settings.Key.Button2;
|
||||
}
|
||||
}
|
||||
|
||||
return Latch;
|
||||
}
|
||||
|
||||
public void ResetStrobe()
|
||||
{
|
||||
Strobe = false;
|
||||
}
|
||||
|
||||
public bool IsAnyKeyDown { get { return _keyboardService.IsAnyKeyDown; } }
|
||||
public int Latch { get { return _latch; } set { _latch = value; Strobe = true; } }
|
||||
public bool Strobe { get; private set; }
|
||||
|
||||
private KeyboardService _keyboardService;
|
||||
private GamePortService _gamePortService;
|
||||
|
||||
private int _latch;
|
||||
}
|
||||
}
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Jellyfish.Virtu.Services;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class Keyboard : MachineComponent
|
||||
{
|
||||
public Keyboard(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
_keyboardService = Machine.Services.GetService<KeyboardService>();
|
||||
_gamePortService = Machine.Services.GetService<GamePortService>();
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
|
||||
public int ReadLatch()
|
||||
{
|
||||
if (Strobe)
|
||||
{
|
||||
return Latch;
|
||||
}
|
||||
|
||||
var settings = Machine.Settings.Keyboard;
|
||||
|
||||
if (settings.UseGamePort)
|
||||
{
|
||||
if ((settings.Key.Joystick0.UpLeft > 0) && _gamePortService.Joystick0.IsUp && _gamePortService.Joystick0.IsLeft)
|
||||
{
|
||||
Latch = settings.Key.Joystick0.UpLeft;
|
||||
}
|
||||
else if ((settings.Key.Joystick0.UpRight > 0) && _gamePortService.Joystick0.IsUp && _gamePortService.Joystick0.IsRight)
|
||||
{
|
||||
Latch = settings.Key.Joystick0.UpRight;
|
||||
}
|
||||
else if ((settings.Key.Joystick0.DownLeft > 0) && _gamePortService.Joystick0.IsDown && _gamePortService.Joystick0.IsLeft)
|
||||
{
|
||||
Latch = settings.Key.Joystick0.DownLeft;
|
||||
}
|
||||
else if ((settings.Key.Joystick0.DownRight > 0) && _gamePortService.Joystick0.IsDown && _gamePortService.Joystick0.IsRight)
|
||||
{
|
||||
Latch = settings.Key.Joystick0.DownRight;
|
||||
}
|
||||
else if ((settings.Key.Joystick0.Up > 0) && _gamePortService.Joystick0.IsUp)
|
||||
{
|
||||
Latch = settings.Key.Joystick0.Up;
|
||||
}
|
||||
else if ((settings.Key.Joystick0.Left > 0) && _gamePortService.Joystick0.IsLeft)
|
||||
{
|
||||
Latch = settings.Key.Joystick0.Left;
|
||||
}
|
||||
else if ((settings.Key.Joystick0.Right > 0) && _gamePortService.Joystick0.IsRight)
|
||||
{
|
||||
Latch = settings.Key.Joystick0.Right;
|
||||
}
|
||||
else if ((settings.Key.Joystick0.Down > 0) && _gamePortService.Joystick0.IsDown)
|
||||
{
|
||||
Latch = settings.Key.Joystick0.Down;
|
||||
}
|
||||
|
||||
if ((settings.Key.Joystick1.UpLeft > 0) && _gamePortService.Joystick1.IsUp && _gamePortService.Joystick1.IsLeft) // override
|
||||
{
|
||||
Latch = settings.Key.Joystick1.UpLeft;
|
||||
}
|
||||
else if ((settings.Key.Joystick1.UpRight > 0) && _gamePortService.Joystick1.IsUp && _gamePortService.Joystick1.IsRight)
|
||||
{
|
||||
Latch = settings.Key.Joystick1.UpRight;
|
||||
}
|
||||
else if ((settings.Key.Joystick1.DownLeft > 0) && _gamePortService.Joystick1.IsDown && _gamePortService.Joystick1.IsLeft)
|
||||
{
|
||||
Latch = settings.Key.Joystick1.DownLeft;
|
||||
}
|
||||
else if ((settings.Key.Joystick1.DownRight > 0) && _gamePortService.Joystick1.IsDown && _gamePortService.Joystick1.IsRight)
|
||||
{
|
||||
Latch = settings.Key.Joystick1.DownRight;
|
||||
}
|
||||
else if ((settings.Key.Joystick1.Up > 0) && _gamePortService.Joystick1.IsUp)
|
||||
{
|
||||
Latch = settings.Key.Joystick1.Up;
|
||||
}
|
||||
else if ((settings.Key.Joystick1.Left > 0) && _gamePortService.Joystick1.IsLeft)
|
||||
{
|
||||
Latch = settings.Key.Joystick1.Left;
|
||||
}
|
||||
else if ((settings.Key.Joystick1.Right > 0) && _gamePortService.Joystick1.IsRight)
|
||||
{
|
||||
Latch = settings.Key.Joystick1.Right;
|
||||
}
|
||||
else if ((settings.Key.Joystick1.Down > 0) && _gamePortService.Joystick1.IsDown)
|
||||
{
|
||||
Latch = settings.Key.Joystick1.Down;
|
||||
}
|
||||
|
||||
if ((settings.Key.Button0 > 0) && _gamePortService.IsButton0Down) // override
|
||||
{
|
||||
Latch = settings.Key.Button0;
|
||||
}
|
||||
else if ((settings.Key.Button1 > 0) && _gamePortService.IsButton1Down)
|
||||
{
|
||||
Latch = settings.Key.Button1;
|
||||
}
|
||||
else if ((settings.Key.Button2 > 0) && _gamePortService.IsButton2Down)
|
||||
{
|
||||
Latch = settings.Key.Button2;
|
||||
}
|
||||
}
|
||||
|
||||
return Latch;
|
||||
}
|
||||
|
||||
public void ResetStrobe()
|
||||
{
|
||||
Strobe = false;
|
||||
}
|
||||
|
||||
public bool IsAnyKeyDown { get { return _keyboardService.IsAnyKeyDown; } }
|
||||
public int Latch { get { return _latch; } set { _latch = value; Strobe = true; } }
|
||||
public bool Strobe { get; private set; }
|
||||
|
||||
private KeyboardService _keyboardService;
|
||||
private GamePortService _gamePortService;
|
||||
|
||||
private int _latch;
|
||||
}
|
||||
}
|
||||
|
|
322
Virtu/Machine.cs
322
Virtu/Machine.cs
|
@ -1,161 +1,161 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading;
|
||||
using Jellyfish.Library;
|
||||
using Jellyfish.Virtu.Services;
|
||||
using Jellyfish.Virtu.Settings;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public enum MachineState { Stopped = 0, Starting, Running, Pausing, Paused, Stopping }
|
||||
|
||||
public sealed class Machine : IDisposable
|
||||
{
|
||||
public Machine()
|
||||
{
|
||||
Events = new MachineEvents();
|
||||
Services = new MachineServices();
|
||||
Settings = new MachineSettings();
|
||||
|
||||
Cpu = new Cpu(this);
|
||||
Memory = new Memory(this);
|
||||
Keyboard = new Keyboard(this);
|
||||
GamePort = new GamePort(this);
|
||||
Cassette = new Cassette(this);
|
||||
Speaker = new Speaker(this);
|
||||
Video = new Video(this);
|
||||
NoSlotClock = new NoSlotClock();
|
||||
|
||||
var emptySlot = new PeripheralCard(this);
|
||||
Slot1 = emptySlot;
|
||||
Slot2 = emptySlot;
|
||||
Slot3 = emptySlot;
|
||||
Slot4 = emptySlot;
|
||||
Slot5 = emptySlot;
|
||||
Slot6 = new DiskIIController(this);
|
||||
Slot7 = emptySlot;
|
||||
|
||||
Slots = new Collection<PeripheralCard> { null, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 };
|
||||
Components = new Collection<MachineComponent> { Cpu, Memory, Keyboard, GamePort, Cassette, Speaker, Video, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 };
|
||||
|
||||
Thread = new Thread(Run) { Name = "Machine" };
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_pauseEvent.Close();
|
||||
_unpauseEvent.Close();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Components.ForEach(component => component.Reset()); // while machine starting or paused
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_storageService = Services.GetService<StorageService>();
|
||||
_storageService.Load(MachineSettings.FileName, stream => Settings.Deserialize(stream));
|
||||
|
||||
State = MachineState.Starting;
|
||||
Thread.Start();
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
State = MachineState.Pausing;
|
||||
_pauseEvent.WaitOne();
|
||||
State = MachineState.Paused;
|
||||
}
|
||||
|
||||
public void Unpause()
|
||||
{
|
||||
State = MachineState.Running;
|
||||
_unpauseEvent.Set();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
State = MachineState.Stopping;
|
||||
_unpauseEvent.Set();
|
||||
Thread.IsAliveJoin();
|
||||
State = MachineState.Stopped;
|
||||
|
||||
if (_storageService != null)
|
||||
{
|
||||
_storageService.Save(MachineSettings.FileName, stream => Settings.Serialize(stream));
|
||||
}
|
||||
}
|
||||
|
||||
public DiskIIController FindDiskIIController()
|
||||
{
|
||||
for (int i = 7; i >= 1; i--)
|
||||
{
|
||||
var diskII = Slots[i] as DiskIIController;
|
||||
if (diskII != null)
|
||||
{
|
||||
return diskII;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void Run() // machine thread
|
||||
{
|
||||
Components.ForEach(component => component.Initialize());
|
||||
Reset();
|
||||
|
||||
State = MachineState.Running;
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
Events.HandleEvents(Cpu.Execute());
|
||||
}
|
||||
while (State == MachineState.Running);
|
||||
|
||||
if (State == MachineState.Pausing)
|
||||
{
|
||||
_pauseEvent.Set();
|
||||
_unpauseEvent.WaitOne();
|
||||
}
|
||||
}
|
||||
while (State != MachineState.Stopping);
|
||||
|
||||
Components.ForEach(component => component.Uninitialize());
|
||||
}
|
||||
|
||||
public MachineEvents Events { get; private set; }
|
||||
public MachineServices Services { get; private set; }
|
||||
public MachineSettings Settings { get; private set; }
|
||||
public MachineState State { get; private set; }
|
||||
|
||||
public Cpu Cpu { get; private set; }
|
||||
public Memory Memory { get; private set; }
|
||||
public Keyboard Keyboard { get; private set; }
|
||||
public GamePort GamePort { get; private set; }
|
||||
public Cassette Cassette { get; private set; }
|
||||
public Speaker Speaker { get; private set; }
|
||||
public Video Video { get; private set; }
|
||||
public NoSlotClock NoSlotClock { get; private set; }
|
||||
|
||||
public PeripheralCard Slot1 { get; private set; }
|
||||
public PeripheralCard Slot2 { get; private set; }
|
||||
public PeripheralCard Slot3 { get; private set; }
|
||||
public PeripheralCard Slot4 { get; private set; }
|
||||
public PeripheralCard Slot5 { get; private set; }
|
||||
public PeripheralCard Slot6 { get; private set; }
|
||||
public PeripheralCard Slot7 { get; private set; }
|
||||
|
||||
public Collection<PeripheralCard> Slots { get; private set; }
|
||||
public Collection<MachineComponent> Components { get; private set; }
|
||||
|
||||
public Thread Thread { get; private set; }
|
||||
|
||||
private AutoResetEvent _pauseEvent = new AutoResetEvent(false);
|
||||
private AutoResetEvent _unpauseEvent = new AutoResetEvent(false);
|
||||
|
||||
private StorageService _storageService;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading;
|
||||
using Jellyfish.Library;
|
||||
using Jellyfish.Virtu.Services;
|
||||
using Jellyfish.Virtu.Settings;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public enum MachineState { Stopped = 0, Starting, Running, Pausing, Paused, Stopping }
|
||||
|
||||
public sealed class Machine : IDisposable
|
||||
{
|
||||
public Machine()
|
||||
{
|
||||
Events = new MachineEvents();
|
||||
Services = new MachineServices();
|
||||
Settings = new MachineSettings();
|
||||
|
||||
Cpu = new Cpu(this);
|
||||
Memory = new Memory(this);
|
||||
Keyboard = new Keyboard(this);
|
||||
GamePort = new GamePort(this);
|
||||
Cassette = new Cassette(this);
|
||||
Speaker = new Speaker(this);
|
||||
Video = new Video(this);
|
||||
NoSlotClock = new NoSlotClock();
|
||||
|
||||
var emptySlot = new PeripheralCard(this);
|
||||
Slot1 = emptySlot;
|
||||
Slot2 = emptySlot;
|
||||
Slot3 = emptySlot;
|
||||
Slot4 = emptySlot;
|
||||
Slot5 = emptySlot;
|
||||
Slot6 = new DiskIIController(this);
|
||||
Slot7 = emptySlot;
|
||||
|
||||
Slots = new Collection<PeripheralCard> { null, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 };
|
||||
Components = new Collection<MachineComponent> { Cpu, Memory, Keyboard, GamePort, Cassette, Speaker, Video, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 };
|
||||
|
||||
Thread = new Thread(Run) { Name = "Machine" };
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_pauseEvent.Close();
|
||||
_unpauseEvent.Close();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Components.ForEach(component => component.Reset()); // while machine starting or paused
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_storageService = Services.GetService<StorageService>();
|
||||
_storageService.Load(MachineSettings.FileName, stream => Settings.Deserialize(stream));
|
||||
|
||||
State = MachineState.Starting;
|
||||
Thread.Start();
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
State = MachineState.Pausing;
|
||||
_pauseEvent.WaitOne();
|
||||
State = MachineState.Paused;
|
||||
}
|
||||
|
||||
public void Unpause()
|
||||
{
|
||||
State = MachineState.Running;
|
||||
_unpauseEvent.Set();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
State = MachineState.Stopping;
|
||||
_unpauseEvent.Set();
|
||||
Thread.IsAliveJoin();
|
||||
State = MachineState.Stopped;
|
||||
|
||||
if (_storageService != null)
|
||||
{
|
||||
_storageService.Save(MachineSettings.FileName, stream => Settings.Serialize(stream));
|
||||
}
|
||||
}
|
||||
|
||||
public DiskIIController FindDiskIIController()
|
||||
{
|
||||
for (int i = 7; i >= 1; i--)
|
||||
{
|
||||
var diskII = Slots[i] as DiskIIController;
|
||||
if (diskII != null)
|
||||
{
|
||||
return diskII;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void Run() // machine thread
|
||||
{
|
||||
Components.ForEach(component => component.Initialize());
|
||||
Reset();
|
||||
|
||||
State = MachineState.Running;
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
Events.HandleEvents(Cpu.Execute());
|
||||
}
|
||||
while (State == MachineState.Running);
|
||||
|
||||
if (State == MachineState.Pausing)
|
||||
{
|
||||
_pauseEvent.Set();
|
||||
_unpauseEvent.WaitOne();
|
||||
}
|
||||
}
|
||||
while (State != MachineState.Stopping);
|
||||
|
||||
Components.ForEach(component => component.Uninitialize());
|
||||
}
|
||||
|
||||
public MachineEvents Events { get; private set; }
|
||||
public MachineServices Services { get; private set; }
|
||||
public MachineSettings Settings { get; private set; }
|
||||
public MachineState State { get; private set; }
|
||||
|
||||
public Cpu Cpu { get; private set; }
|
||||
public Memory Memory { get; private set; }
|
||||
public Keyboard Keyboard { get; private set; }
|
||||
public GamePort GamePort { get; private set; }
|
||||
public Cassette Cassette { get; private set; }
|
||||
public Speaker Speaker { get; private set; }
|
||||
public Video Video { get; private set; }
|
||||
public NoSlotClock NoSlotClock { get; private set; }
|
||||
|
||||
public PeripheralCard Slot1 { get; private set; }
|
||||
public PeripheralCard Slot2 { get; private set; }
|
||||
public PeripheralCard Slot3 { get; private set; }
|
||||
public PeripheralCard Slot4 { get; private set; }
|
||||
public PeripheralCard Slot5 { get; private set; }
|
||||
public PeripheralCard Slot6 { get; private set; }
|
||||
public PeripheralCard Slot7 { get; private set; }
|
||||
|
||||
public Collection<PeripheralCard> Slots { get; private set; }
|
||||
public Collection<MachineComponent> Components { get; private set; }
|
||||
|
||||
public Thread Thread { get; private set; }
|
||||
|
||||
private AutoResetEvent _pauseEvent = new AutoResetEvent(false);
|
||||
private AutoResetEvent _unpauseEvent = new AutoResetEvent(false);
|
||||
|
||||
private StorageService _storageService;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public abstract class MachineComponent
|
||||
{
|
||||
protected MachineComponent(Machine machine)
|
||||
{
|
||||
Machine = machine;
|
||||
}
|
||||
|
||||
public virtual void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Uninitialize()
|
||||
{
|
||||
}
|
||||
|
||||
protected Machine Machine { get; private set; }
|
||||
}
|
||||
}
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public abstract class MachineComponent
|
||||
{
|
||||
protected MachineComponent(Machine machine)
|
||||
{
|
||||
Machine = machine;
|
||||
}
|
||||
|
||||
public virtual void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Uninitialize()
|
||||
{
|
||||
}
|
||||
|
||||
protected Machine Machine { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,107 +1,107 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class MachineEvent
|
||||
{
|
||||
public MachineEvent(int delta, Action action)
|
||||
{
|
||||
Delta = delta;
|
||||
Action = action;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, "Delta = {0} Action = {{{1}.{2}}}", Delta, Action.Method.DeclaringType.Name, Action.Method.Name);
|
||||
}
|
||||
|
||||
public int Delta { get; set; }
|
||||
public Action Action { get; set; }
|
||||
}
|
||||
|
||||
public sealed class MachineEvents
|
||||
{
|
||||
public void AddEvent(int delta, Action action)
|
||||
{
|
||||
var node = _used.First;
|
||||
for (; node != null; node = node.Next)
|
||||
{
|
||||
if (delta < node.Value.Delta)
|
||||
{
|
||||
node.Value.Delta -= delta;
|
||||
break;
|
||||
}
|
||||
if (node.Value.Delta > 0)
|
||||
{
|
||||
delta -= node.Value.Delta;
|
||||
}
|
||||
}
|
||||
|
||||
var newNode = _free.First;
|
||||
if (newNode != null)
|
||||
{
|
||||
_free.RemoveFirst();
|
||||
newNode.Value.Delta = delta;
|
||||
newNode.Value.Action = action;
|
||||
}
|
||||
else
|
||||
{
|
||||
newNode = new LinkedListNode<MachineEvent>(new MachineEvent(delta, action));
|
||||
}
|
||||
|
||||
if (node != null)
|
||||
{
|
||||
_used.AddBefore(node, newNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
_used.AddLast(newNode);
|
||||
}
|
||||
}
|
||||
|
||||
public int FindEvent(Action action)
|
||||
{
|
||||
int delta = 0;
|
||||
|
||||
for (var node = _used.First; node != null; node = node.Next)
|
||||
{
|
||||
delta += node.Value.Delta;
|
||||
if (object.ReferenceEquals(node.Value.Action, action)) // assumes delegate cached
|
||||
{
|
||||
return delta;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void HandleEvents(int delta)
|
||||
{
|
||||
var node = _used.First;
|
||||
node.Value.Delta -= delta;
|
||||
|
||||
while (node.Value.Delta <= 0)
|
||||
{
|
||||
node.Value.Action();
|
||||
RemoveEvent(node);
|
||||
node = _used.First;
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveEvent(LinkedListNode<MachineEvent> node)
|
||||
{
|
||||
if (node.Next != null)
|
||||
{
|
||||
node.Next.Value.Delta += node.Value.Delta;
|
||||
}
|
||||
|
||||
_used.Remove(node);
|
||||
_free.AddFirst(node); // cache node; avoids garbage
|
||||
}
|
||||
|
||||
private LinkedList<MachineEvent> _used = new LinkedList<MachineEvent>();
|
||||
private LinkedList<MachineEvent> _free = new LinkedList<MachineEvent>();
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class MachineEvent
|
||||
{
|
||||
public MachineEvent(int delta, Action action)
|
||||
{
|
||||
Delta = delta;
|
||||
Action = action;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, "Delta = {0} Action = {{{1}.{2}}}", Delta, Action.Method.DeclaringType.Name, Action.Method.Name);
|
||||
}
|
||||
|
||||
public int Delta { get; set; }
|
||||
public Action Action { get; set; }
|
||||
}
|
||||
|
||||
public sealed class MachineEvents
|
||||
{
|
||||
public void AddEvent(int delta, Action action)
|
||||
{
|
||||
var node = _used.First;
|
||||
for (; node != null; node = node.Next)
|
||||
{
|
||||
if (delta < node.Value.Delta)
|
||||
{
|
||||
node.Value.Delta -= delta;
|
||||
break;
|
||||
}
|
||||
if (node.Value.Delta > 0)
|
||||
{
|
||||
delta -= node.Value.Delta;
|
||||
}
|
||||
}
|
||||
|
||||
var newNode = _free.First;
|
||||
if (newNode != null)
|
||||
{
|
||||
_free.RemoveFirst();
|
||||
newNode.Value.Delta = delta;
|
||||
newNode.Value.Action = action;
|
||||
}
|
||||
else
|
||||
{
|
||||
newNode = new LinkedListNode<MachineEvent>(new MachineEvent(delta, action));
|
||||
}
|
||||
|
||||
if (node != null)
|
||||
{
|
||||
_used.AddBefore(node, newNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
_used.AddLast(newNode);
|
||||
}
|
||||
}
|
||||
|
||||
public int FindEvent(Action action)
|
||||
{
|
||||
int delta = 0;
|
||||
|
||||
for (var node = _used.First; node != null; node = node.Next)
|
||||
{
|
||||
delta += node.Value.Delta;
|
||||
if (object.ReferenceEquals(node.Value.Action, action)) // assumes delegate cached
|
||||
{
|
||||
return delta;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void HandleEvents(int delta)
|
||||
{
|
||||
var node = _used.First;
|
||||
node.Value.Delta -= delta;
|
||||
|
||||
while (node.Value.Delta <= 0)
|
||||
{
|
||||
node.Value.Action();
|
||||
RemoveEvent(node);
|
||||
node = _used.First;
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveEvent(LinkedListNode<MachineEvent> node)
|
||||
{
|
||||
if (node.Next != null)
|
||||
{
|
||||
node.Next.Value.Delta += node.Value.Delta;
|
||||
}
|
||||
|
||||
_used.Remove(node);
|
||||
_free.AddFirst(node); // cache node; avoids garbage
|
||||
}
|
||||
|
||||
private LinkedList<MachineEvent> _used = new LinkedList<MachineEvent>();
|
||||
private LinkedList<MachineEvent> _free = new LinkedList<MachineEvent>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,412 +1,412 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Jellyfish.Virtu.Settings
|
||||
{
|
||||
public sealed class MachineSettings
|
||||
{
|
||||
public MachineSettings()
|
||||
{
|
||||
Cpu = new CpuSettings { Is65C02 = true, IsThrottled = true, Multiplier = 1 };
|
||||
DiskII = new DiskIISettings
|
||||
{
|
||||
Disk1 = new DiskSettings { Name = string.Empty, IsWriteProtected = false },
|
||||
Disk2 = new DiskSettings { Name = string.Empty, IsWriteProtected = false }
|
||||
};
|
||||
Keyboard = new KeyboardSettings
|
||||
{
|
||||
UseGamePort = false,
|
||||
Key = new KeySettings
|
||||
{
|
||||
Joystick0 = new JoystickSettings { UpLeft = 0, Up = 'I', UpRight = 0, Left = 'J', Right = 'L', DownLeft = 0, Down = 'K', DownRight = 0 },
|
||||
Joystick1 = new JoystickSettings { UpLeft = 0, Up = 'E', UpRight = 0, Left = 'S', Right = 'F', DownLeft = 0, Down = 'D', DownRight = 0 },
|
||||
Button0 = 0, Button1 = 0, Button2 = 0
|
||||
}
|
||||
};
|
||||
GamePort = new GamePortSettings
|
||||
{
|
||||
UseKeyboard = false,
|
||||
Key = new KeySettings
|
||||
{
|
||||
Joystick0 = new JoystickSettings { UpLeft = 0, Up = 0, UpRight = 0, Left = 0, Right = 0, DownLeft = 0, Down = 0, DownRight = 0 },
|
||||
Joystick1 = new JoystickSettings { UpLeft = 0, Up = 0, UpRight = 0, Left = 0, Right = 0, DownLeft = 0, Down = 0, DownRight = 0 },
|
||||
Button0 = 0, Button1 = 0, Button2 = 0
|
||||
}
|
||||
};
|
||||
#if WINDOWS_PHONE
|
||||
Audio = new AudioSettings { Volume = 0.85 };
|
||||
#else
|
||||
Audio = new AudioSettings { Volume = 0.5 };
|
||||
#endif
|
||||
Video = new VideoSettings
|
||||
{
|
||||
IsFullScreen = false, IsMonochrome = false, ScannerOptions = ScannerOptions.None,
|
||||
Color = new ColorSettings
|
||||
{
|
||||
Black = 0xFF000000, // BGRA
|
||||
DarkBlue = 0xFF000099,
|
||||
DarkGreen = 0xFF117722,
|
||||
MediumBlue = 0xFF0000FF,
|
||||
Brown = 0xFF885500,
|
||||
LightGrey = 0xFF99AAAA,
|
||||
Green = 0xFF00EE11,
|
||||
Aquamarine = 0xFF55FFAA,
|
||||
DeepRed = 0xFFFF1111,
|
||||
Purple = 0xFFDD00DD,
|
||||
DarkGrey = 0xFF445555,
|
||||
LightBlue = 0xFF33AAFF,
|
||||
Orange = 0xFFFF4411,
|
||||
Pink = 0xFFFF9988,
|
||||
Yellow = 0xFFFFFF11,
|
||||
White = 0xFFFFFFFF,
|
||||
Monochrome = 0xFF00AA00
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
|
||||
public void Deserialize(Stream stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var reader = XmlReader.Create(stream))
|
||||
{
|
||||
var ns = Namespace;
|
||||
var root = XElement.Load(reader);
|
||||
var cpu = root.Element(ns + "Cpu");
|
||||
Cpu = new CpuSettings
|
||||
{
|
||||
Is65C02 = (bool)cpu.Attribute("Is65C02"),
|
||||
IsThrottled = (bool)cpu.Attribute("IsThrottled"),
|
||||
Multiplier = (int)cpu.Attribute("Multiplier")
|
||||
};
|
||||
var diskII = root.Element(ns + "DiskII");
|
||||
var disk1 = diskII.Element(ns + "Disk1");
|
||||
var disk2 = diskII.Element(ns + "Disk2");
|
||||
DiskII = new DiskIISettings
|
||||
{
|
||||
Disk1 = new DiskSettings
|
||||
{
|
||||
Name = (string)disk1.Attribute("Name") ?? string.Empty,
|
||||
IsWriteProtected = (bool)disk1.Attribute("IsWriteProtected")
|
||||
},
|
||||
Disk2 = new DiskSettings
|
||||
{
|
||||
Name = (string)disk2.Attribute("Name") ?? string.Empty,
|
||||
IsWriteProtected = (bool)disk2.Attribute("IsWriteProtected")
|
||||
},
|
||||
};
|
||||
var keyboard = root.Element(ns + "Keyboard");
|
||||
var key = keyboard.Element(ns + "Key");
|
||||
var joystick0 = key.Element(ns + "Joystick0");
|
||||
var joystick1 = key.Element(ns + "Joystick1");
|
||||
var buttons = key.Element(ns + "Buttons");
|
||||
Keyboard = new KeyboardSettings
|
||||
{
|
||||
UseGamePort = (bool)keyboard.Attribute("UseGamePort"),
|
||||
Key = new KeySettings
|
||||
{
|
||||
Joystick0 = new JoystickSettings
|
||||
{
|
||||
UpLeft = (int)joystick0.Attribute("UpLeft"),
|
||||
Up = (int)joystick0.Attribute("Up"),
|
||||
UpRight = (int)joystick0.Attribute("UpRight"),
|
||||
Left = (int)joystick0.Attribute("Left"),
|
||||
Right = (int)joystick0.Attribute("Right"),
|
||||
DownLeft = (int)joystick0.Attribute("DownLeft"),
|
||||
Down = (int)joystick0.Attribute("Down"),
|
||||
DownRight = (int)joystick0.Attribute("DownRight")
|
||||
},
|
||||
Joystick1 = new JoystickSettings
|
||||
{
|
||||
UpLeft = (int)joystick1.Attribute("UpLeft"),
|
||||
Up = (int)joystick1.Attribute("Up"),
|
||||
UpRight = (int)joystick1.Attribute("UpRight"),
|
||||
Left = (int)joystick1.Attribute("Left"),
|
||||
Right = (int)joystick1.Attribute("Right"),
|
||||
DownLeft = (int)joystick1.Attribute("DownLeft"),
|
||||
Down = (int)joystick1.Attribute("Down"),
|
||||
DownRight = (int)joystick1.Attribute("DownRight")
|
||||
},
|
||||
Button0 = (int)buttons.Attribute("Button0"),
|
||||
Button1 = (int)buttons.Attribute("Button1"),
|
||||
Button2 = (int)buttons.Attribute("Button2")
|
||||
}
|
||||
};
|
||||
var gamePort = root.Element(ns + "GamePort");
|
||||
key = gamePort.Element(ns + "Key");
|
||||
joystick0 = key.Element(ns + "Joystick0");
|
||||
joystick1 = key.Element(ns + "Joystick1");
|
||||
buttons = key.Element(ns + "Buttons");
|
||||
GamePort = new GamePortSettings
|
||||
{
|
||||
UseKeyboard = (bool)gamePort.Attribute("UseKeyboard"),
|
||||
Key = new KeySettings
|
||||
{
|
||||
Joystick0 = new JoystickSettings
|
||||
{
|
||||
UpLeft = (int)joystick0.Attribute("UpLeft"),
|
||||
Up = (int)joystick0.Attribute("Up"),
|
||||
UpRight = (int)joystick0.Attribute("UpRight"),
|
||||
Left = (int)joystick0.Attribute("Left"),
|
||||
Right = (int)joystick0.Attribute("Right"),
|
||||
DownLeft = (int)joystick0.Attribute("DownLeft"),
|
||||
Down = (int)joystick0.Attribute("Down"),
|
||||
DownRight = (int)joystick0.Attribute("DownRight")
|
||||
},
|
||||
Joystick1 = new JoystickSettings
|
||||
{
|
||||
UpLeft = (int)joystick1.Attribute("UpLeft"),
|
||||
Up = (int)joystick1.Attribute("Up"),
|
||||
UpRight = (int)joystick1.Attribute("UpRight"),
|
||||
Left = (int)joystick1.Attribute("Left"),
|
||||
Right = (int)joystick1.Attribute("Right"),
|
||||
DownLeft = (int)joystick1.Attribute("DownLeft"),
|
||||
Down = (int)joystick1.Attribute("Down"),
|
||||
DownRight = (int)joystick1.Attribute("DownRight")
|
||||
},
|
||||
Button0 = (int)buttons.Attribute("Button0"),
|
||||
Button1 = (int)buttons.Attribute("Button1"),
|
||||
Button2 = (int)buttons.Attribute("Button2")
|
||||
}
|
||||
};
|
||||
var audio = root.Element(ns + "Audio");
|
||||
Audio = new AudioSettings
|
||||
{
|
||||
Volume = (double)audio.Attribute("Volume")
|
||||
};
|
||||
var video = root.Element(ns + "Video");
|
||||
var color = video.Element(ns + "Color");
|
||||
Video = new VideoSettings
|
||||
{
|
||||
IsFullScreen = (bool)video.Attribute("IsFullScreen"),
|
||||
IsMonochrome = (bool)video.Attribute("IsMonochrome"),
|
||||
ScannerOptions = (ScannerOptions)Enum.Parse(typeof(ScannerOptions), (string)video.Attribute("ScannerOptions"), true),
|
||||
Color = new ColorSettings
|
||||
{
|
||||
Black = (uint)color.Attribute("Black"),
|
||||
DarkBlue = (uint)color.Attribute("DarkBlue"),
|
||||
DarkGreen = (uint)color.Attribute("DarkGreen"),
|
||||
MediumBlue = (uint)color.Attribute("MediumBlue"),
|
||||
Brown = (uint)color.Attribute("Brown"),
|
||||
LightGrey = (uint)color.Attribute("LightGrey"),
|
||||
Green = (uint)color.Attribute("Green"),
|
||||
Aquamarine = (uint)color.Attribute("Aquamarine"),
|
||||
DeepRed = (uint)color.Attribute("DeepRed"),
|
||||
Purple = (uint)color.Attribute("Purple"),
|
||||
DarkGrey = (uint)color.Attribute("DarkGrey"),
|
||||
LightBlue = (uint)color.Attribute("LightBlue"),
|
||||
Orange = (uint)color.Attribute("Orange"),
|
||||
Pink = (uint)color.Attribute("Pink"),
|
||||
Yellow = (uint)color.Attribute("Yellow"),
|
||||
White = (uint)color.Attribute("White"),
|
||||
Monochrome = (uint)color.Attribute("Monochrome")
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(Stream stream)
|
||||
{
|
||||
var ns = Namespace;
|
||||
var xml = new XElement(ns + "MachineSettings",
|
||||
new XElement(ns + "Cpu",
|
||||
new XAttribute("Is65C02", Cpu.Is65C02),
|
||||
new XAttribute("IsThrottled", Cpu.IsThrottled),
|
||||
new XAttribute("Multiplier", Cpu.Multiplier)),
|
||||
new XElement(ns + "DiskII",
|
||||
new XElement(ns + "Disk1",
|
||||
new XAttribute("Name", DiskII.Disk1.Name),
|
||||
new XAttribute("IsWriteProtected", DiskII.Disk1.IsWriteProtected)),
|
||||
new XElement(ns + "Disk2",
|
||||
new XAttribute("Name", DiskII.Disk2.Name),
|
||||
new XAttribute("IsWriteProtected", DiskII.Disk2.IsWriteProtected))),
|
||||
new XElement(ns + "Keyboard",
|
||||
new XAttribute("UseGamePort", Keyboard.UseGamePort),
|
||||
new XElement(ns + "Key",
|
||||
new XElement(ns + "Joystick0",
|
||||
new XAttribute("UpLeft", Keyboard.Key.Joystick0.UpLeft),
|
||||
new XAttribute("Up", Keyboard.Key.Joystick0.Up),
|
||||
new XAttribute("UpRight", Keyboard.Key.Joystick0.UpRight),
|
||||
new XAttribute("Left", Keyboard.Key.Joystick0.Left),
|
||||
new XAttribute("Right", Keyboard.Key.Joystick0.Right),
|
||||
new XAttribute("DownLeft", Keyboard.Key.Joystick0.DownLeft),
|
||||
new XAttribute("Down", Keyboard.Key.Joystick0.Down),
|
||||
new XAttribute("DownRight", Keyboard.Key.Joystick0.DownRight)),
|
||||
new XElement(ns + "Joystick1",
|
||||
new XAttribute("UpLeft", Keyboard.Key.Joystick1.UpLeft),
|
||||
new XAttribute("Up", Keyboard.Key.Joystick1.Up),
|
||||
new XAttribute("UpRight", Keyboard.Key.Joystick1.UpRight),
|
||||
new XAttribute("Left", Keyboard.Key.Joystick1.Left),
|
||||
new XAttribute("Right", Keyboard.Key.Joystick1.Right),
|
||||
new XAttribute("DownLeft", Keyboard.Key.Joystick1.DownLeft),
|
||||
new XAttribute("Down", Keyboard.Key.Joystick1.Down),
|
||||
new XAttribute("DownRight", Keyboard.Key.Joystick1.DownRight)),
|
||||
new XElement(ns + "Buttons",
|
||||
new XAttribute("Button0", Keyboard.Key.Button0),
|
||||
new XAttribute("Button1", Keyboard.Key.Button1),
|
||||
new XAttribute("Button2", Keyboard.Key.Button2)))),
|
||||
new XElement(ns + "GamePort",
|
||||
new XAttribute("UseKeyboard", GamePort.UseKeyboard),
|
||||
new XElement(ns + "Key",
|
||||
new XElement(ns + "Joystick0",
|
||||
new XAttribute("UpLeft", GamePort.Key.Joystick0.UpLeft),
|
||||
new XAttribute("Up", GamePort.Key.Joystick0.Up),
|
||||
new XAttribute("UpRight", GamePort.Key.Joystick0.UpRight),
|
||||
new XAttribute("Left", GamePort.Key.Joystick0.Left),
|
||||
new XAttribute("Right", GamePort.Key.Joystick0.Right),
|
||||
new XAttribute("DownLeft", GamePort.Key.Joystick0.DownLeft),
|
||||
new XAttribute("Down", GamePort.Key.Joystick0.Down),
|
||||
new XAttribute("DownRight", GamePort.Key.Joystick0.DownRight)),
|
||||
new XElement(ns + "Joystick1",
|
||||
new XAttribute("UpLeft", GamePort.Key.Joystick1.UpLeft),
|
||||
new XAttribute("Up", GamePort.Key.Joystick1.Up),
|
||||
new XAttribute("UpRight", GamePort.Key.Joystick1.UpRight),
|
||||
new XAttribute("Left", GamePort.Key.Joystick1.Left),
|
||||
new XAttribute("Right", GamePort.Key.Joystick1.Right),
|
||||
new XAttribute("DownLeft", GamePort.Key.Joystick1.DownLeft),
|
||||
new XAttribute("Down", GamePort.Key.Joystick1.Down),
|
||||
new XAttribute("DownRight", GamePort.Key.Joystick1.DownRight)),
|
||||
new XElement(ns + "Buttons",
|
||||
new XAttribute("Button0", Keyboard.Key.Button0),
|
||||
new XAttribute("Button1", Keyboard.Key.Button1),
|
||||
new XAttribute("Button2", Keyboard.Key.Button2)))),
|
||||
new XElement(ns + "Audio",
|
||||
new XAttribute("Volume", Audio.Volume)),
|
||||
new XElement(ns + "Video",
|
||||
new XAttribute("IsFullScreen", Video.IsFullScreen),
|
||||
new XAttribute("IsMonochrome", Video.IsMonochrome),
|
||||
new XAttribute("ScannerOptions", Video.ScannerOptions),
|
||||
new XElement(ns + "Color",
|
||||
new XAttribute("Black", Video.Color.Black),
|
||||
new XAttribute("DarkBlue", Video.Color.DarkBlue),
|
||||
new XAttribute("DarkGreen", Video.Color.DarkGreen),
|
||||
new XAttribute("MediumBlue", Video.Color.MediumBlue),
|
||||
new XAttribute("Brown", Video.Color.Brown),
|
||||
new XAttribute("LightGrey", Video.Color.LightGrey),
|
||||
new XAttribute("Green", Video.Color.Green),
|
||||
new XAttribute("Aquamarine", Video.Color.Aquamarine),
|
||||
new XAttribute("DeepRed", Video.Color.DeepRed),
|
||||
new XAttribute("Purple", Video.Color.Purple),
|
||||
new XAttribute("DarkGrey", Video.Color.DarkGrey),
|
||||
new XAttribute("LightBlue", Video.Color.LightBlue),
|
||||
new XAttribute("Orange", Video.Color.Orange),
|
||||
new XAttribute("Pink", Video.Color.Pink),
|
||||
new XAttribute("Yellow", Video.Color.Yellow),
|
||||
new XAttribute("White", Video.Color.White),
|
||||
new XAttribute("Monochrome", Video.Color.Monochrome))));
|
||||
|
||||
using (var writer = XmlWriter.Create(stream))
|
||||
{
|
||||
xml.WriteTo(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public CpuSettings Cpu { get; set; }
|
||||
public DiskIISettings DiskII { get; set; }
|
||||
public KeyboardSettings Keyboard { get; set; }
|
||||
public GamePortSettings GamePort { get; set; }
|
||||
public AudioSettings Audio { get; set; }
|
||||
public VideoSettings Video { get; set; }
|
||||
|
||||
public const string FileName = "Settings.xml";
|
||||
[SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
|
||||
public static readonly XNamespace Namespace = "http://schemas.jellyfish.co.nz/virtu/settings";
|
||||
}
|
||||
|
||||
public sealed class CpuSettings
|
||||
{
|
||||
public bool Is65C02 { get; set; }
|
||||
public bool IsThrottled { get; set; }
|
||||
public int Multiplier { get; set; }
|
||||
}
|
||||
|
||||
public sealed class DiskSettings
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public bool IsWriteProtected { get; set; }
|
||||
};
|
||||
|
||||
public sealed class DiskIISettings
|
||||
{
|
||||
public DiskSettings Disk1 { get; set; }
|
||||
public DiskSettings Disk2 { get; set; }
|
||||
};
|
||||
|
||||
public sealed class JoystickSettings
|
||||
{
|
||||
public int UpLeft { get; set; }
|
||||
public int Up { get; set; }
|
||||
public int UpRight { get; set; }
|
||||
public int Left { get; set; }
|
||||
public int Right { get; set; }
|
||||
public int DownLeft { get; set; }
|
||||
public int Down { get; set; }
|
||||
public int DownRight { get; set; }
|
||||
};
|
||||
|
||||
public sealed class KeySettings
|
||||
{
|
||||
public JoystickSettings Joystick0 { get; set; }
|
||||
public JoystickSettings Joystick1 { get; set; }
|
||||
public int Button0 { get; set; }
|
||||
public int Button1 { get; set; }
|
||||
public int Button2 { get; set; }
|
||||
};
|
||||
|
||||
public sealed class KeyboardSettings
|
||||
{
|
||||
public bool UseGamePort { get; set; }
|
||||
public KeySettings Key { get; set; }
|
||||
}
|
||||
|
||||
public sealed class GamePortSettings
|
||||
{
|
||||
public bool UseKeyboard { get; set; }
|
||||
public KeySettings Key { get; set; }
|
||||
}
|
||||
|
||||
public sealed class AudioSettings
|
||||
{
|
||||
public double Volume { get; set; }
|
||||
};
|
||||
|
||||
public sealed class ColorSettings
|
||||
{
|
||||
public uint Black { get; set; }
|
||||
public uint DarkBlue { get; set; }
|
||||
public uint DarkGreen { get; set; }
|
||||
public uint MediumBlue { get; set; }
|
||||
public uint Brown { get; set; }
|
||||
public uint LightGrey { get; set; }
|
||||
public uint Green { get; set; }
|
||||
public uint Aquamarine { get; set; }
|
||||
public uint DeepRed { get; set; }
|
||||
public uint Purple { get; set; }
|
||||
public uint DarkGrey { get; set; }
|
||||
public uint LightBlue { get; set; }
|
||||
public uint Orange { get; set; }
|
||||
public uint Pink { get; set; }
|
||||
public uint Yellow { get; set; }
|
||||
public uint White { get; set; }
|
||||
public uint Monochrome { get; set; }
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ScannerOptions { None = 0x0, AppleII = 0x1, Pal = 0x2 } // defaults to AppleIIe, Ntsc
|
||||
|
||||
public sealed class VideoSettings
|
||||
{
|
||||
public bool IsFullScreen { get; set; }
|
||||
public bool IsMonochrome { get; set; }
|
||||
public ScannerOptions ScannerOptions { get; set; }
|
||||
public ColorSettings Color { get; set; }
|
||||
};
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Jellyfish.Virtu.Settings
|
||||
{
|
||||
public sealed class MachineSettings
|
||||
{
|
||||
public MachineSettings()
|
||||
{
|
||||
Cpu = new CpuSettings { Is65C02 = true, IsThrottled = true, Multiplier = 1 };
|
||||
DiskII = new DiskIISettings
|
||||
{
|
||||
Disk1 = new DiskSettings { Name = string.Empty, IsWriteProtected = false },
|
||||
Disk2 = new DiskSettings { Name = string.Empty, IsWriteProtected = false }
|
||||
};
|
||||
Keyboard = new KeyboardSettings
|
||||
{
|
||||
UseGamePort = false,
|
||||
Key = new KeySettings
|
||||
{
|
||||
Joystick0 = new JoystickSettings { UpLeft = 0, Up = 'I', UpRight = 0, Left = 'J', Right = 'L', DownLeft = 0, Down = 'K', DownRight = 0 },
|
||||
Joystick1 = new JoystickSettings { UpLeft = 0, Up = 'E', UpRight = 0, Left = 'S', Right = 'F', DownLeft = 0, Down = 'D', DownRight = 0 },
|
||||
Button0 = 0, Button1 = 0, Button2 = 0
|
||||
}
|
||||
};
|
||||
GamePort = new GamePortSettings
|
||||
{
|
||||
UseKeyboard = false,
|
||||
Key = new KeySettings
|
||||
{
|
||||
Joystick0 = new JoystickSettings { UpLeft = 0, Up = 0, UpRight = 0, Left = 0, Right = 0, DownLeft = 0, Down = 0, DownRight = 0 },
|
||||
Joystick1 = new JoystickSettings { UpLeft = 0, Up = 0, UpRight = 0, Left = 0, Right = 0, DownLeft = 0, Down = 0, DownRight = 0 },
|
||||
Button0 = 0, Button1 = 0, Button2 = 0
|
||||
}
|
||||
};
|
||||
#if WINDOWS_PHONE
|
||||
Audio = new AudioSettings { Volume = 0.85 };
|
||||
#else
|
||||
Audio = new AudioSettings { Volume = 0.5 };
|
||||
#endif
|
||||
Video = new VideoSettings
|
||||
{
|
||||
IsFullScreen = false, IsMonochrome = false, ScannerOptions = ScannerOptions.None,
|
||||
Color = new ColorSettings
|
||||
{
|
||||
Black = 0xFF000000, // BGRA
|
||||
DarkBlue = 0xFF000099,
|
||||
DarkGreen = 0xFF117722,
|
||||
MediumBlue = 0xFF0000FF,
|
||||
Brown = 0xFF885500,
|
||||
LightGrey = 0xFF99AAAA,
|
||||
Green = 0xFF00EE11,
|
||||
Aquamarine = 0xFF55FFAA,
|
||||
DeepRed = 0xFFFF1111,
|
||||
Purple = 0xFFDD00DD,
|
||||
DarkGrey = 0xFF445555,
|
||||
LightBlue = 0xFF33AAFF,
|
||||
Orange = 0xFFFF4411,
|
||||
Pink = 0xFFFF9988,
|
||||
Yellow = 0xFFFFFF11,
|
||||
White = 0xFFFFFFFF,
|
||||
Monochrome = 0xFF00AA00
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
|
||||
public void Deserialize(Stream stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var reader = XmlReader.Create(stream))
|
||||
{
|
||||
var ns = Namespace;
|
||||
var root = XElement.Load(reader);
|
||||
var cpu = root.Element(ns + "Cpu");
|
||||
Cpu = new CpuSettings
|
||||
{
|
||||
Is65C02 = (bool)cpu.Attribute("Is65C02"),
|
||||
IsThrottled = (bool)cpu.Attribute("IsThrottled"),
|
||||
Multiplier = (int)cpu.Attribute("Multiplier")
|
||||
};
|
||||
var diskII = root.Element(ns + "DiskII");
|
||||
var disk1 = diskII.Element(ns + "Disk1");
|
||||
var disk2 = diskII.Element(ns + "Disk2");
|
||||
DiskII = new DiskIISettings
|
||||
{
|
||||
Disk1 = new DiskSettings
|
||||
{
|
||||
Name = (string)disk1.Attribute("Name") ?? string.Empty,
|
||||
IsWriteProtected = (bool)disk1.Attribute("IsWriteProtected")
|
||||
},
|
||||
Disk2 = new DiskSettings
|
||||
{
|
||||
Name = (string)disk2.Attribute("Name") ?? string.Empty,
|
||||
IsWriteProtected = (bool)disk2.Attribute("IsWriteProtected")
|
||||
},
|
||||
};
|
||||
var keyboard = root.Element(ns + "Keyboard");
|
||||
var key = keyboard.Element(ns + "Key");
|
||||
var joystick0 = key.Element(ns + "Joystick0");
|
||||
var joystick1 = key.Element(ns + "Joystick1");
|
||||
var buttons = key.Element(ns + "Buttons");
|
||||
Keyboard = new KeyboardSettings
|
||||
{
|
||||
UseGamePort = (bool)keyboard.Attribute("UseGamePort"),
|
||||
Key = new KeySettings
|
||||
{
|
||||
Joystick0 = new JoystickSettings
|
||||
{
|
||||
UpLeft = (int)joystick0.Attribute("UpLeft"),
|
||||
Up = (int)joystick0.Attribute("Up"),
|
||||
UpRight = (int)joystick0.Attribute("UpRight"),
|
||||
Left = (int)joystick0.Attribute("Left"),
|
||||
Right = (int)joystick0.Attribute("Right"),
|
||||
DownLeft = (int)joystick0.Attribute("DownLeft"),
|
||||
Down = (int)joystick0.Attribute("Down"),
|
||||
DownRight = (int)joystick0.Attribute("DownRight")
|
||||
},
|
||||
Joystick1 = new JoystickSettings
|
||||
{
|
||||
UpLeft = (int)joystick1.Attribute("UpLeft"),
|
||||
Up = (int)joystick1.Attribute("Up"),
|
||||
UpRight = (int)joystick1.Attribute("UpRight"),
|
||||
Left = (int)joystick1.Attribute("Left"),
|
||||
Right = (int)joystick1.Attribute("Right"),
|
||||
DownLeft = (int)joystick1.Attribute("DownLeft"),
|
||||
Down = (int)joystick1.Attribute("Down"),
|
||||
DownRight = (int)joystick1.Attribute("DownRight")
|
||||
},
|
||||
Button0 = (int)buttons.Attribute("Button0"),
|
||||
Button1 = (int)buttons.Attribute("Button1"),
|
||||
Button2 = (int)buttons.Attribute("Button2")
|
||||
}
|
||||
};
|
||||
var gamePort = root.Element(ns + "GamePort");
|
||||
key = gamePort.Element(ns + "Key");
|
||||
joystick0 = key.Element(ns + "Joystick0");
|
||||
joystick1 = key.Element(ns + "Joystick1");
|
||||
buttons = key.Element(ns + "Buttons");
|
||||
GamePort = new GamePortSettings
|
||||
{
|
||||
UseKeyboard = (bool)gamePort.Attribute("UseKeyboard"),
|
||||
Key = new KeySettings
|
||||
{
|
||||
Joystick0 = new JoystickSettings
|
||||
{
|
||||
UpLeft = (int)joystick0.Attribute("UpLeft"),
|
||||
Up = (int)joystick0.Attribute("Up"),
|
||||
UpRight = (int)joystick0.Attribute("UpRight"),
|
||||
Left = (int)joystick0.Attribute("Left"),
|
||||
Right = (int)joystick0.Attribute("Right"),
|
||||
DownLeft = (int)joystick0.Attribute("DownLeft"),
|
||||
Down = (int)joystick0.Attribute("Down"),
|
||||
DownRight = (int)joystick0.Attribute("DownRight")
|
||||
},
|
||||
Joystick1 = new JoystickSettings
|
||||
{
|
||||
UpLeft = (int)joystick1.Attribute("UpLeft"),
|
||||
Up = (int)joystick1.Attribute("Up"),
|
||||
UpRight = (int)joystick1.Attribute("UpRight"),
|
||||
Left = (int)joystick1.Attribute("Left"),
|
||||
Right = (int)joystick1.Attribute("Right"),
|
||||
DownLeft = (int)joystick1.Attribute("DownLeft"),
|
||||
Down = (int)joystick1.Attribute("Down"),
|
||||
DownRight = (int)joystick1.Attribute("DownRight")
|
||||
},
|
||||
Button0 = (int)buttons.Attribute("Button0"),
|
||||
Button1 = (int)buttons.Attribute("Button1"),
|
||||
Button2 = (int)buttons.Attribute("Button2")
|
||||
}
|
||||
};
|
||||
var audio = root.Element(ns + "Audio");
|
||||
Audio = new AudioSettings
|
||||
{
|
||||
Volume = (double)audio.Attribute("Volume")
|
||||
};
|
||||
var video = root.Element(ns + "Video");
|
||||
var color = video.Element(ns + "Color");
|
||||
Video = new VideoSettings
|
||||
{
|
||||
IsFullScreen = (bool)video.Attribute("IsFullScreen"),
|
||||
IsMonochrome = (bool)video.Attribute("IsMonochrome"),
|
||||
ScannerOptions = (ScannerOptions)Enum.Parse(typeof(ScannerOptions), (string)video.Attribute("ScannerOptions"), true),
|
||||
Color = new ColorSettings
|
||||
{
|
||||
Black = (uint)color.Attribute("Black"),
|
||||
DarkBlue = (uint)color.Attribute("DarkBlue"),
|
||||
DarkGreen = (uint)color.Attribute("DarkGreen"),
|
||||
MediumBlue = (uint)color.Attribute("MediumBlue"),
|
||||
Brown = (uint)color.Attribute("Brown"),
|
||||
LightGrey = (uint)color.Attribute("LightGrey"),
|
||||
Green = (uint)color.Attribute("Green"),
|
||||
Aquamarine = (uint)color.Attribute("Aquamarine"),
|
||||
DeepRed = (uint)color.Attribute("DeepRed"),
|
||||
Purple = (uint)color.Attribute("Purple"),
|
||||
DarkGrey = (uint)color.Attribute("DarkGrey"),
|
||||
LightBlue = (uint)color.Attribute("LightBlue"),
|
||||
Orange = (uint)color.Attribute("Orange"),
|
||||
Pink = (uint)color.Attribute("Pink"),
|
||||
Yellow = (uint)color.Attribute("Yellow"),
|
||||
White = (uint)color.Attribute("White"),
|
||||
Monochrome = (uint)color.Attribute("Monochrome")
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(Stream stream)
|
||||
{
|
||||
var ns = Namespace;
|
||||
var xml = new XElement(ns + "MachineSettings",
|
||||
new XElement(ns + "Cpu",
|
||||
new XAttribute("Is65C02", Cpu.Is65C02),
|
||||
new XAttribute("IsThrottled", Cpu.IsThrottled),
|
||||
new XAttribute("Multiplier", Cpu.Multiplier)),
|
||||
new XElement(ns + "DiskII",
|
||||
new XElement(ns + "Disk1",
|
||||
new XAttribute("Name", DiskII.Disk1.Name),
|
||||
new XAttribute("IsWriteProtected", DiskII.Disk1.IsWriteProtected)),
|
||||
new XElement(ns + "Disk2",
|
||||
new XAttribute("Name", DiskII.Disk2.Name),
|
||||
new XAttribute("IsWriteProtected", DiskII.Disk2.IsWriteProtected))),
|
||||
new XElement(ns + "Keyboard",
|
||||
new XAttribute("UseGamePort", Keyboard.UseGamePort),
|
||||
new XElement(ns + "Key",
|
||||
new XElement(ns + "Joystick0",
|
||||
new XAttribute("UpLeft", Keyboard.Key.Joystick0.UpLeft),
|
||||
new XAttribute("Up", Keyboard.Key.Joystick0.Up),
|
||||
new XAttribute("UpRight", Keyboard.Key.Joystick0.UpRight),
|
||||
new XAttribute("Left", Keyboard.Key.Joystick0.Left),
|
||||
new XAttribute("Right", Keyboard.Key.Joystick0.Right),
|
||||
new XAttribute("DownLeft", Keyboard.Key.Joystick0.DownLeft),
|
||||
new XAttribute("Down", Keyboard.Key.Joystick0.Down),
|
||||
new XAttribute("DownRight", Keyboard.Key.Joystick0.DownRight)),
|
||||
new XElement(ns + "Joystick1",
|
||||
new XAttribute("UpLeft", Keyboard.Key.Joystick1.UpLeft),
|
||||
new XAttribute("Up", Keyboard.Key.Joystick1.Up),
|
||||
new XAttribute("UpRight", Keyboard.Key.Joystick1.UpRight),
|
||||
new XAttribute("Left", Keyboard.Key.Joystick1.Left),
|
||||
new XAttribute("Right", Keyboard.Key.Joystick1.Right),
|
||||
new XAttribute("DownLeft", Keyboard.Key.Joystick1.DownLeft),
|
||||
new XAttribute("Down", Keyboard.Key.Joystick1.Down),
|
||||
new XAttribute("DownRight", Keyboard.Key.Joystick1.DownRight)),
|
||||
new XElement(ns + "Buttons",
|
||||
new XAttribute("Button0", Keyboard.Key.Button0),
|
||||
new XAttribute("Button1", Keyboard.Key.Button1),
|
||||
new XAttribute("Button2", Keyboard.Key.Button2)))),
|
||||
new XElement(ns + "GamePort",
|
||||
new XAttribute("UseKeyboard", GamePort.UseKeyboard),
|
||||
new XElement(ns + "Key",
|
||||
new XElement(ns + "Joystick0",
|
||||
new XAttribute("UpLeft", GamePort.Key.Joystick0.UpLeft),
|
||||
new XAttribute("Up", GamePort.Key.Joystick0.Up),
|
||||
new XAttribute("UpRight", GamePort.Key.Joystick0.UpRight),
|
||||
new XAttribute("Left", GamePort.Key.Joystick0.Left),
|
||||
new XAttribute("Right", GamePort.Key.Joystick0.Right),
|
||||
new XAttribute("DownLeft", GamePort.Key.Joystick0.DownLeft),
|
||||
new XAttribute("Down", GamePort.Key.Joystick0.Down),
|
||||
new XAttribute("DownRight", GamePort.Key.Joystick0.DownRight)),
|
||||
new XElement(ns + "Joystick1",
|
||||
new XAttribute("UpLeft", GamePort.Key.Joystick1.UpLeft),
|
||||
new XAttribute("Up", GamePort.Key.Joystick1.Up),
|
||||
new XAttribute("UpRight", GamePort.Key.Joystick1.UpRight),
|
||||
new XAttribute("Left", GamePort.Key.Joystick1.Left),
|
||||
new XAttribute("Right", GamePort.Key.Joystick1.Right),
|
||||
new XAttribute("DownLeft", GamePort.Key.Joystick1.DownLeft),
|
||||
new XAttribute("Down", GamePort.Key.Joystick1.Down),
|
||||
new XAttribute("DownRight", GamePort.Key.Joystick1.DownRight)),
|
||||
new XElement(ns + "Buttons",
|
||||
new XAttribute("Button0", Keyboard.Key.Button0),
|
||||
new XAttribute("Button1", Keyboard.Key.Button1),
|
||||
new XAttribute("Button2", Keyboard.Key.Button2)))),
|
||||
new XElement(ns + "Audio",
|
||||
new XAttribute("Volume", Audio.Volume)),
|
||||
new XElement(ns + "Video",
|
||||
new XAttribute("IsFullScreen", Video.IsFullScreen),
|
||||
new XAttribute("IsMonochrome", Video.IsMonochrome),
|
||||
new XAttribute("ScannerOptions", Video.ScannerOptions),
|
||||
new XElement(ns + "Color",
|
||||
new XAttribute("Black", Video.Color.Black),
|
||||
new XAttribute("DarkBlue", Video.Color.DarkBlue),
|
||||
new XAttribute("DarkGreen", Video.Color.DarkGreen),
|
||||
new XAttribute("MediumBlue", Video.Color.MediumBlue),
|
||||
new XAttribute("Brown", Video.Color.Brown),
|
||||
new XAttribute("LightGrey", Video.Color.LightGrey),
|
||||
new XAttribute("Green", Video.Color.Green),
|
||||
new XAttribute("Aquamarine", Video.Color.Aquamarine),
|
||||
new XAttribute("DeepRed", Video.Color.DeepRed),
|
||||
new XAttribute("Purple", Video.Color.Purple),
|
||||
new XAttribute("DarkGrey", Video.Color.DarkGrey),
|
||||
new XAttribute("LightBlue", Video.Color.LightBlue),
|
||||
new XAttribute("Orange", Video.Color.Orange),
|
||||
new XAttribute("Pink", Video.Color.Pink),
|
||||
new XAttribute("Yellow", Video.Color.Yellow),
|
||||
new XAttribute("White", Video.Color.White),
|
||||
new XAttribute("Monochrome", Video.Color.Monochrome))));
|
||||
|
||||
using (var writer = XmlWriter.Create(stream))
|
||||
{
|
||||
xml.WriteTo(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public CpuSettings Cpu { get; set; }
|
||||
public DiskIISettings DiskII { get; set; }
|
||||
public KeyboardSettings Keyboard { get; set; }
|
||||
public GamePortSettings GamePort { get; set; }
|
||||
public AudioSettings Audio { get; set; }
|
||||
public VideoSettings Video { get; set; }
|
||||
|
||||
public const string FileName = "Settings.xml";
|
||||
[SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
|
||||
public static readonly XNamespace Namespace = "http://schemas.jellyfish.co.nz/virtu/settings";
|
||||
}
|
||||
|
||||
public sealed class CpuSettings
|
||||
{
|
||||
public bool Is65C02 { get; set; }
|
||||
public bool IsThrottled { get; set; }
|
||||
public int Multiplier { get; set; }
|
||||
}
|
||||
|
||||
public sealed class DiskSettings
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public bool IsWriteProtected { get; set; }
|
||||
};
|
||||
|
||||
public sealed class DiskIISettings
|
||||
{
|
||||
public DiskSettings Disk1 { get; set; }
|
||||
public DiskSettings Disk2 { get; set; }
|
||||
};
|
||||
|
||||
public sealed class JoystickSettings
|
||||
{
|
||||
public int UpLeft { get; set; }
|
||||
public int Up { get; set; }
|
||||
public int UpRight { get; set; }
|
||||
public int Left { get; set; }
|
||||
public int Right { get; set; }
|
||||
public int DownLeft { get; set; }
|
||||
public int Down { get; set; }
|
||||
public int DownRight { get; set; }
|
||||
};
|
||||
|
||||
public sealed class KeySettings
|
||||
{
|
||||
public JoystickSettings Joystick0 { get; set; }
|
||||
public JoystickSettings Joystick1 { get; set; }
|
||||
public int Button0 { get; set; }
|
||||
public int Button1 { get; set; }
|
||||
public int Button2 { get; set; }
|
||||
};
|
||||
|
||||
public sealed class KeyboardSettings
|
||||
{
|
||||
public bool UseGamePort { get; set; }
|
||||
public KeySettings Key { get; set; }
|
||||
}
|
||||
|
||||
public sealed class GamePortSettings
|
||||
{
|
||||
public bool UseKeyboard { get; set; }
|
||||
public KeySettings Key { get; set; }
|
||||
}
|
||||
|
||||
public sealed class AudioSettings
|
||||
{
|
||||
public double Volume { get; set; }
|
||||
};
|
||||
|
||||
public sealed class ColorSettings
|
||||
{
|
||||
public uint Black { get; set; }
|
||||
public uint DarkBlue { get; set; }
|
||||
public uint DarkGreen { get; set; }
|
||||
public uint MediumBlue { get; set; }
|
||||
public uint Brown { get; set; }
|
||||
public uint LightGrey { get; set; }
|
||||
public uint Green { get; set; }
|
||||
public uint Aquamarine { get; set; }
|
||||
public uint DeepRed { get; set; }
|
||||
public uint Purple { get; set; }
|
||||
public uint DarkGrey { get; set; }
|
||||
public uint LightBlue { get; set; }
|
||||
public uint Orange { get; set; }
|
||||
public uint Pink { get; set; }
|
||||
public uint Yellow { get; set; }
|
||||
public uint White { get; set; }
|
||||
public uint Monochrome { get; set; }
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ScannerOptions { None = 0x0, AppleII = 0x1, Pal = 0x2 } // defaults to AppleIIe, Ntsc
|
||||
|
||||
public sealed class VideoSettings
|
||||
{
|
||||
public bool IsFullScreen { get; set; }
|
||||
public bool IsMonochrome { get; set; }
|
||||
public ScannerOptions ScannerOptions { get; set; }
|
||||
public ColorSettings Color { get; set; }
|
||||
};
|
||||
}
|
||||
|
|
3120
Virtu/Memory.cs
3120
Virtu/Memory.cs
File diff suppressed because it is too large
Load Diff
|
@ -1,106 +1,106 @@
|
|||
using System;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public partial class Memory
|
||||
{
|
||||
private const int BankCount = 2;
|
||||
|
||||
private const int BankMain = 0;
|
||||
private const int BankAux = 1;
|
||||
|
||||
private const int RegionCount = 12;
|
||||
|
||||
private const int Region0001 = 0;
|
||||
private const int Region02BF = 1;
|
||||
private const int Region0407 = 2;
|
||||
private const int Region080B = 3;
|
||||
private const int Region203F = 4;
|
||||
private const int Region405F = 5;
|
||||
private const int RegionC0C0 = 6;
|
||||
private const int RegionC1C7 = 7;
|
||||
private const int RegionC3C3 = 8;
|
||||
private const int RegionC8CF = 9;
|
||||
private const int RegionD0DF = 10;
|
||||
private const int RegionE0FF = 11;
|
||||
|
||||
private static readonly int[] RegionBaseAddress = new int[RegionCount]
|
||||
{
|
||||
0x0000, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0xC000, 0xC100, 0xC100, 0xC100, 0xD000, 0xE000
|
||||
};
|
||||
|
||||
private const int PageCount = 256;
|
||||
|
||||
private static readonly int[] PageRegion = new int[PageCount]
|
||||
{
|
||||
Region0001, Region0001, Region02BF, Region02BF, Region0407, Region0407, Region0407, Region0407,
|
||||
Region080B, Region080B, Region080B, Region080B, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region203F, Region203F, Region203F, Region203F, Region203F, Region203F, Region203F, Region203F,
|
||||
Region203F, Region203F, Region203F, Region203F, Region203F, Region203F, Region203F, Region203F,
|
||||
Region203F, Region203F, Region203F, Region203F, Region203F, Region203F, Region203F, Region203F,
|
||||
Region203F, Region203F, Region203F, Region203F, Region203F, Region203F, Region203F, Region203F,
|
||||
Region405F, Region405F, Region405F, Region405F, Region405F, Region405F, Region405F, Region405F,
|
||||
Region405F, Region405F, Region405F, Region405F, Region405F, Region405F, Region405F, Region405F,
|
||||
Region405F, Region405F, Region405F, Region405F, Region405F, Region405F, Region405F, Region405F,
|
||||
Region405F, Region405F, Region405F, Region405F, Region405F, Region405F, Region405F, Region405F,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
RegionC0C0, RegionC1C7, RegionC1C7, RegionC3C3, RegionC1C7, RegionC1C7, RegionC1C7, RegionC1C7,
|
||||
RegionC8CF, RegionC8CF, RegionC8CF, RegionC8CF, RegionC8CF, RegionC8CF, RegionC8CF, RegionC8CF,
|
||||
RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF,
|
||||
RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF,
|
||||
RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF,
|
||||
RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF,
|
||||
RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF,
|
||||
RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF
|
||||
};
|
||||
|
||||
private const int State80Col = 0x000001;
|
||||
private const int StateText = 0x000002;
|
||||
private const int StateMixed = 0x000004;
|
||||
private const int StateHires = 0x000008;
|
||||
private const int StateDRes = 0x000010;
|
||||
private const int State80Store = 0x000020;
|
||||
private const int StateAltChrSet = 0x000040;
|
||||
private const int StateAltZP = 0x000080;
|
||||
private const int StateBank1 = 0x000100;
|
||||
private const int StateHRamRd = 0x000200;
|
||||
private const int StateHRamPreWrt = 0x000400;
|
||||
private const int StateHRamWrt = 0x000800;
|
||||
private const int StatePage2 = 0x001000;
|
||||
private const int StateRamRd = 0x002000;
|
||||
private const int StateRamWrt = 0x004000;
|
||||
private const int StateSlotC3Rom = 0x008000;
|
||||
private const int StateIntC8Rom = 0x010000; // [5-28]
|
||||
private const int StateIntCXRom = 0x020000;
|
||||
private const int StateAn0 = 0x040000;
|
||||
private const int StateAn1 = 0x080000;
|
||||
private const int StateAn2 = 0x100000;
|
||||
private const int StateAn3 = 0x200000;
|
||||
private const int StateVideo = State80Col | StateText | StateMixed | StateHires | StateDRes;
|
||||
|
||||
private const int StateVideoModeCount = 32;
|
||||
|
||||
private static readonly int[] StateVideoMode = new int[StateVideoModeCount]
|
||||
{
|
||||
Video.Mode0, Video.Mode0, Video.Mode1, Video.Mode2, Video.Mode3, Video.Mode4, Video.Mode1, Video.Mode2,
|
||||
Video.Mode5, Video.Mode5, Video.Mode1, Video.Mode2, Video.Mode6, Video.Mode7, Video.Mode1, Video.Mode2,
|
||||
Video.Mode8, Video.Mode9, Video.Mode1, Video.Mode2, Video.ModeA, Video.ModeB, Video.Mode1, Video.Mode2,
|
||||
Video.ModeC, Video.ModeD, Video.Mode1, Video.Mode2, Video.ModeE, Video.ModeF, Video.Mode1, Video.Mode2
|
||||
};
|
||||
|
||||
private readonly Action<int, byte>[][][] WriteRamModeBankRegion;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public partial class Memory
|
||||
{
|
||||
private const int BankCount = 2;
|
||||
|
||||
private const int BankMain = 0;
|
||||
private const int BankAux = 1;
|
||||
|
||||
private const int RegionCount = 12;
|
||||
|
||||
private const int Region0001 = 0;
|
||||
private const int Region02BF = 1;
|
||||
private const int Region0407 = 2;
|
||||
private const int Region080B = 3;
|
||||
private const int Region203F = 4;
|
||||
private const int Region405F = 5;
|
||||
private const int RegionC0C0 = 6;
|
||||
private const int RegionC1C7 = 7;
|
||||
private const int RegionC3C3 = 8;
|
||||
private const int RegionC8CF = 9;
|
||||
private const int RegionD0DF = 10;
|
||||
private const int RegionE0FF = 11;
|
||||
|
||||
private static readonly int[] RegionBaseAddress = new int[RegionCount]
|
||||
{
|
||||
0x0000, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0xC000, 0xC100, 0xC100, 0xC100, 0xD000, 0xE000
|
||||
};
|
||||
|
||||
private const int PageCount = 256;
|
||||
|
||||
private static readonly int[] PageRegion = new int[PageCount]
|
||||
{
|
||||
Region0001, Region0001, Region02BF, Region02BF, Region0407, Region0407, Region0407, Region0407,
|
||||
Region080B, Region080B, Region080B, Region080B, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region203F, Region203F, Region203F, Region203F, Region203F, Region203F, Region203F, Region203F,
|
||||
Region203F, Region203F, Region203F, Region203F, Region203F, Region203F, Region203F, Region203F,
|
||||
Region203F, Region203F, Region203F, Region203F, Region203F, Region203F, Region203F, Region203F,
|
||||
Region203F, Region203F, Region203F, Region203F, Region203F, Region203F, Region203F, Region203F,
|
||||
Region405F, Region405F, Region405F, Region405F, Region405F, Region405F, Region405F, Region405F,
|
||||
Region405F, Region405F, Region405F, Region405F, Region405F, Region405F, Region405F, Region405F,
|
||||
Region405F, Region405F, Region405F, Region405F, Region405F, Region405F, Region405F, Region405F,
|
||||
Region405F, Region405F, Region405F, Region405F, Region405F, Region405F, Region405F, Region405F,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF, Region02BF,
|
||||
RegionC0C0, RegionC1C7, RegionC1C7, RegionC3C3, RegionC1C7, RegionC1C7, RegionC1C7, RegionC1C7,
|
||||
RegionC8CF, RegionC8CF, RegionC8CF, RegionC8CF, RegionC8CF, RegionC8CF, RegionC8CF, RegionC8CF,
|
||||
RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF,
|
||||
RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF, RegionD0DF,
|
||||
RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF,
|
||||
RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF,
|
||||
RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF,
|
||||
RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF, RegionE0FF
|
||||
};
|
||||
|
||||
private const int State80Col = 0x000001;
|
||||
private const int StateText = 0x000002;
|
||||
private const int StateMixed = 0x000004;
|
||||
private const int StateHires = 0x000008;
|
||||
private const int StateDRes = 0x000010;
|
||||
private const int State80Store = 0x000020;
|
||||
private const int StateAltChrSet = 0x000040;
|
||||
private const int StateAltZP = 0x000080;
|
||||
private const int StateBank1 = 0x000100;
|
||||
private const int StateHRamRd = 0x000200;
|
||||
private const int StateHRamPreWrt = 0x000400;
|
||||
private const int StateHRamWrt = 0x000800;
|
||||
private const int StatePage2 = 0x001000;
|
||||
private const int StateRamRd = 0x002000;
|
||||
private const int StateRamWrt = 0x004000;
|
||||
private const int StateSlotC3Rom = 0x008000;
|
||||
private const int StateIntC8Rom = 0x010000; // [5-28]
|
||||
private const int StateIntCXRom = 0x020000;
|
||||
private const int StateAn0 = 0x040000;
|
||||
private const int StateAn1 = 0x080000;
|
||||
private const int StateAn2 = 0x100000;
|
||||
private const int StateAn3 = 0x200000;
|
||||
private const int StateVideo = State80Col | StateText | StateMixed | StateHires | StateDRes;
|
||||
|
||||
private const int StateVideoModeCount = 32;
|
||||
|
||||
private static readonly int[] StateVideoMode = new int[StateVideoModeCount]
|
||||
{
|
||||
Video.Mode0, Video.Mode0, Video.Mode1, Video.Mode2, Video.Mode3, Video.Mode4, Video.Mode1, Video.Mode2,
|
||||
Video.Mode5, Video.Mode5, Video.Mode1, Video.Mode2, Video.Mode6, Video.Mode7, Video.Mode1, Video.Mode2,
|
||||
Video.Mode8, Video.Mode9, Video.Mode1, Video.Mode2, Video.ModeA, Video.ModeB, Video.Mode1, Video.Mode2,
|
||||
Video.ModeC, Video.ModeD, Video.Mode1, Video.Mode2, Video.ModeE, Video.ModeF, Video.Mode1, Video.Mode2
|
||||
};
|
||||
|
||||
private readonly Action<int, byte>[][][] WriteRamModeBankRegion;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class NoSlotClock
|
||||
{
|
||||
public NoSlotClock()
|
||||
{
|
||||
}
|
||||
|
||||
public int Read(int address, int data)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
public void Write(int address)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class NoSlotClock
|
||||
{
|
||||
public NoSlotClock()
|
||||
{
|
||||
}
|
||||
|
||||
public int Read(int address, int data)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
public void Write(int address)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,48 +1,48 @@
|
|||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public class PeripheralCard : MachineComponent
|
||||
{
|
||||
public PeripheralCard(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual int ReadIoRegionC0C0(int address)
|
||||
{
|
||||
// read Device Select' address $C0nX; n = slot number + 8
|
||||
return ReadFloatingBus();
|
||||
}
|
||||
|
||||
public virtual int ReadIoRegionC1C7(int address)
|
||||
{
|
||||
// read I/O Select' address $CsXX; s = slot number
|
||||
return ReadFloatingBus();
|
||||
}
|
||||
|
||||
public virtual int ReadIoRegionC8CF(int address)
|
||||
{
|
||||
// read I/O Strobe' address $C800-$CFFF
|
||||
return ReadFloatingBus();
|
||||
}
|
||||
|
||||
public virtual void WriteIoRegionC0C0(int address, int data)
|
||||
{
|
||||
// write Device Select' address $C0nX; n = slot number + 8
|
||||
}
|
||||
|
||||
public virtual void WriteIoRegionC1C7(int address, int data)
|
||||
{
|
||||
// write I/O Select' address $CsXX; s = slot number
|
||||
}
|
||||
|
||||
public virtual void WriteIoRegionC8CF(int address, int data)
|
||||
{
|
||||
// write I/O Strobe' address $C800-$CFFF
|
||||
}
|
||||
|
||||
protected int ReadFloatingBus()
|
||||
{
|
||||
return Machine.Video.ReadFloatingBus();
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public class PeripheralCard : MachineComponent
|
||||
{
|
||||
public PeripheralCard(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual int ReadIoRegionC0C0(int address)
|
||||
{
|
||||
// read Device Select' address $C0nX; n = slot number + 8
|
||||
return ReadFloatingBus();
|
||||
}
|
||||
|
||||
public virtual int ReadIoRegionC1C7(int address)
|
||||
{
|
||||
// read I/O Select' address $CsXX; s = slot number
|
||||
return ReadFloatingBus();
|
||||
}
|
||||
|
||||
public virtual int ReadIoRegionC8CF(int address)
|
||||
{
|
||||
// read I/O Strobe' address $C800-$CFFF
|
||||
return ReadFloatingBus();
|
||||
}
|
||||
|
||||
public virtual void WriteIoRegionC0C0(int address, int data)
|
||||
{
|
||||
// write Device Select' address $C0nX; n = slot number + 8
|
||||
}
|
||||
|
||||
public virtual void WriteIoRegionC1C7(int address, int data)
|
||||
{
|
||||
// write I/O Select' address $CsXX; s = slot number
|
||||
}
|
||||
|
||||
public virtual void WriteIoRegionC8CF(int address, int data)
|
||||
{
|
||||
// write I/O Strobe' address $C800-$CFFF
|
||||
}
|
||||
|
||||
protected int ReadFloatingBus()
|
||||
{
|
||||
return Machine.Video.ReadFloatingBus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,65 +1,65 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public abstract class AudioService : MachineService
|
||||
{
|
||||
protected AudioService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public void Output(int data) // machine thread
|
||||
{
|
||||
_buffer[_index + 0] = (byte)(data & 0xFF);
|
||||
_buffer[_index + 1] = (byte)(data >> 8);
|
||||
_index = (_index + 2) % SampleSize;
|
||||
if (_index == 0)
|
||||
{
|
||||
_readEvent.Set();
|
||||
if (Machine.Settings.Cpu.IsThrottled)
|
||||
{
|
||||
_writeEvent.WaitOne(SampleLatency * 2); // allow timeout; avoids deadlock
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Buffer.BlockCopy(SampleZero, 0, _buffer, 0, SampleSize);
|
||||
}
|
||||
|
||||
public abstract void SetVolume(double volume); // machine thread
|
||||
|
||||
protected void Update(int bufferSize, Action<byte[], int> updateBuffer) // audio thread
|
||||
{
|
||||
if (Machine.State == MachineState.Running)
|
||||
{
|
||||
_readEvent.WaitOne(SampleLatency * 2); // allow timeout; avoids deadlock
|
||||
}
|
||||
if (updateBuffer != null)
|
||||
{
|
||||
updateBuffer(_buffer, bufferSize);
|
||||
}
|
||||
_writeEvent.Set();
|
||||
}
|
||||
|
||||
public const int SampleRate = 44100; // hz
|
||||
public const int SampleChannels = 1;
|
||||
public const int SampleBits = 16;
|
||||
public const int SampleLatency = 40; // ms
|
||||
public const int SampleSize = (SampleRate * SampleLatency / 1000) * SampleChannels * (SampleBits / 8);
|
||||
|
||||
[SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
|
||||
protected static readonly byte[] SampleZero = new byte[SampleSize];
|
||||
|
||||
private byte[] _buffer = new byte[SampleSize];
|
||||
private int _index;
|
||||
|
||||
private AutoResetEvent _readEvent = new AutoResetEvent(false);
|
||||
private AutoResetEvent _writeEvent = new AutoResetEvent(false);
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public abstract class AudioService : MachineService
|
||||
{
|
||||
protected AudioService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public void Output(int data) // machine thread
|
||||
{
|
||||
_buffer[_index + 0] = (byte)(data & 0xFF);
|
||||
_buffer[_index + 1] = (byte)(data >> 8);
|
||||
_index = (_index + 2) % SampleSize;
|
||||
if (_index == 0)
|
||||
{
|
||||
_readEvent.Set();
|
||||
if (Machine.Settings.Cpu.IsThrottled)
|
||||
{
|
||||
_writeEvent.WaitOne(SampleLatency * 2); // allow timeout; avoids deadlock
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Buffer.BlockCopy(SampleZero, 0, _buffer, 0, SampleSize);
|
||||
}
|
||||
|
||||
public abstract void SetVolume(double volume); // machine thread
|
||||
|
||||
protected void Update(int bufferSize, Action<byte[], int> updateBuffer) // audio thread
|
||||
{
|
||||
if (Machine.State == MachineState.Running)
|
||||
{
|
||||
_readEvent.WaitOne(SampleLatency * 2); // allow timeout; avoids deadlock
|
||||
}
|
||||
if (updateBuffer != null)
|
||||
{
|
||||
updateBuffer(_buffer, bufferSize);
|
||||
}
|
||||
_writeEvent.Set();
|
||||
}
|
||||
|
||||
public const int SampleRate = 44100; // hz
|
||||
public const int SampleChannels = 1;
|
||||
public const int SampleBits = 16;
|
||||
public const int SampleLatency = 40; // ms
|
||||
public const int SampleSize = (SampleRate * SampleLatency / 1000) * SampleChannels * (SampleBits / 8);
|
||||
|
||||
[SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
|
||||
protected static readonly byte[] SampleZero = new byte[SampleSize];
|
||||
|
||||
private byte[] _buffer = new byte[SampleSize];
|
||||
private int _index;
|
||||
|
||||
private AutoResetEvent _readEvent = new AutoResetEvent(false);
|
||||
private AutoResetEvent _writeEvent = new AutoResetEvent(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public class DebugService : MachineService
|
||||
{
|
||||
public DebugService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public void WriteLine(string message)
|
||||
{
|
||||
OnWriteLine(string.Concat(DateTime.Now.TimeOfDay, ' ', message));
|
||||
}
|
||||
|
||||
protected virtual void OnWriteLine(string message)
|
||||
{
|
||||
Debug.WriteLine(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public class DebugService : MachineService
|
||||
{
|
||||
public DebugService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public void WriteLine(string message)
|
||||
{
|
||||
OnWriteLine(string.Concat(DateTime.Now.TimeOfDay, ' ', message));
|
||||
}
|
||||
|
||||
protected virtual void OnWriteLine(string message)
|
||||
{
|
||||
Debug.WriteLine(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,73 +1,73 @@
|
|||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public struct Joystick
|
||||
{
|
||||
public Joystick(bool isUp, bool isLeft, bool isRight, bool isDown)
|
||||
{
|
||||
_isUp = isUp;
|
||||
_isLeft = isLeft;
|
||||
_isRight = isRight;
|
||||
_isDown = isDown;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return ((obj is Joystick) && (this == (Joystick)obj));
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (_isUp.GetHashCode() ^ _isLeft.GetHashCode() ^ _isRight.GetHashCode() ^ _isDown.GetHashCode());
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return !(_isUp || _isDown || _isLeft || _isRight) ? "Position = Center" :
|
||||
string.Concat("Position = ", _isUp ? "Up" : _isDown ? "Down" : string.Empty, _isLeft ? "Left" : _isRight ? "Right" : string.Empty);
|
||||
}
|
||||
|
||||
public static bool operator ==(Joystick joystick1, Joystick joystick2)
|
||||
{
|
||||
return ((joystick1._isUp == joystick2._isUp) && (joystick1._isLeft == joystick2._isLeft) &&
|
||||
(joystick1._isRight == joystick2._isRight) && (joystick1._isDown == joystick2._isDown));
|
||||
}
|
||||
|
||||
public static bool operator !=(Joystick joystick1, Joystick joystick2)
|
||||
{
|
||||
return !(joystick1 == joystick2);
|
||||
}
|
||||
|
||||
public bool IsUp { get { return _isUp; } } // no auto props
|
||||
public bool IsLeft { get { return _isLeft; } }
|
||||
public bool IsRight { get { return _isRight; } }
|
||||
public bool IsDown { get { return _isDown; } }
|
||||
|
||||
private bool _isUp;
|
||||
private bool _isLeft;
|
||||
private bool _isRight;
|
||||
private bool _isDown;
|
||||
}
|
||||
|
||||
public class GamePortService : MachineService
|
||||
{
|
||||
public GamePortService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
Paddle0 = Paddle1 = Paddle2 = Paddle3 = 255; // not connected
|
||||
}
|
||||
|
||||
public virtual void Update() { } // main thread
|
||||
|
||||
public int Paddle0 { get; protected set; }
|
||||
public int Paddle1 { get; protected set; }
|
||||
public int Paddle2 { get; protected set; }
|
||||
public int Paddle3 { get; protected set; }
|
||||
|
||||
public Joystick Joystick0 { get; protected set; }
|
||||
public Joystick Joystick1 { get; protected set; }
|
||||
|
||||
public bool IsButton0Down { get; protected set; }
|
||||
public bool IsButton1Down { get; protected set; }
|
||||
public bool IsButton2Down { get; protected set; }
|
||||
}
|
||||
}
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public struct Joystick
|
||||
{
|
||||
public Joystick(bool isUp, bool isLeft, bool isRight, bool isDown)
|
||||
{
|
||||
_isUp = isUp;
|
||||
_isLeft = isLeft;
|
||||
_isRight = isRight;
|
||||
_isDown = isDown;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return ((obj is Joystick) && (this == (Joystick)obj));
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (_isUp.GetHashCode() ^ _isLeft.GetHashCode() ^ _isRight.GetHashCode() ^ _isDown.GetHashCode());
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return !(_isUp || _isDown || _isLeft || _isRight) ? "Position = Center" :
|
||||
string.Concat("Position = ", _isUp ? "Up" : _isDown ? "Down" : string.Empty, _isLeft ? "Left" : _isRight ? "Right" : string.Empty);
|
||||
}
|
||||
|
||||
public static bool operator ==(Joystick joystick1, Joystick joystick2)
|
||||
{
|
||||
return ((joystick1._isUp == joystick2._isUp) && (joystick1._isLeft == joystick2._isLeft) &&
|
||||
(joystick1._isRight == joystick2._isRight) && (joystick1._isDown == joystick2._isDown));
|
||||
}
|
||||
|
||||
public static bool operator !=(Joystick joystick1, Joystick joystick2)
|
||||
{
|
||||
return !(joystick1 == joystick2);
|
||||
}
|
||||
|
||||
public bool IsUp { get { return _isUp; } } // no auto props
|
||||
public bool IsLeft { get { return _isLeft; } }
|
||||
public bool IsRight { get { return _isRight; } }
|
||||
public bool IsDown { get { return _isDown; } }
|
||||
|
||||
private bool _isUp;
|
||||
private bool _isLeft;
|
||||
private bool _isRight;
|
||||
private bool _isDown;
|
||||
}
|
||||
|
||||
public class GamePortService : MachineService
|
||||
{
|
||||
public GamePortService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
Paddle0 = Paddle1 = Paddle2 = Paddle3 = 255; // not connected
|
||||
}
|
||||
|
||||
public virtual void Update() { } // main thread
|
||||
|
||||
public int Paddle0 { get; protected set; }
|
||||
public int Paddle1 { get; protected set; }
|
||||
public int Paddle2 { get; protected set; }
|
||||
public int Paddle3 { get; protected set; }
|
||||
|
||||
public Joystick Joystick0 { get; protected set; }
|
||||
public Joystick Joystick1 { get; protected set; }
|
||||
|
||||
public bool IsButton0Down { get; protected set; }
|
||||
public bool IsButton1Down { get; protected set; }
|
||||
public bool IsButton2Down { get; protected set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,41 +1,41 @@
|
|||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public abstract class KeyboardService : MachineService
|
||||
{
|
||||
protected KeyboardService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAnyKeyDown { get; protected set; }
|
||||
public bool IsControlKeyDown { get; protected set; }
|
||||
public bool IsShiftKeyDown { get; protected set; }
|
||||
|
||||
public bool IsOpenAppleKeyDown { get; protected set; }
|
||||
public bool IsCloseAppleKeyDown { get; protected set; }
|
||||
|
||||
protected bool IsResetKeyDown { get; set; }
|
||||
|
||||
private bool _resetKeyDown;
|
||||
}
|
||||
}
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public abstract class KeyboardService : MachineService
|
||||
{
|
||||
protected KeyboardService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAnyKeyDown { get; protected set; }
|
||||
public bool IsControlKeyDown { get; protected set; }
|
||||
public bool IsShiftKeyDown { get; protected set; }
|
||||
|
||||
public bool IsOpenAppleKeyDown { get; protected set; }
|
||||
public bool IsCloseAppleKeyDown { get; protected set; }
|
||||
|
||||
protected bool IsResetKeyDown { get; set; }
|
||||
|
||||
private bool _resetKeyDown;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
using System;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public abstract class MachineService : IDisposable
|
||||
{
|
||||
protected MachineService(Machine machine)
|
||||
{
|
||||
Machine = machine;
|
||||
}
|
||||
|
||||
~MachineService()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
}
|
||||
|
||||
protected Machine Machine { get; private set; }
|
||||
protected DebugService DebugService { get { return Machine.Services.GetService<DebugService>(); } }
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public abstract class MachineService : IDisposable
|
||||
{
|
||||
protected MachineService(Machine machine)
|
||||
{
|
||||
Machine = machine;
|
||||
}
|
||||
|
||||
~MachineService()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
}
|
||||
|
||||
protected Machine Machine { get; private set; }
|
||||
protected DebugService DebugService { get { return Machine.Services.GetService<DebugService>(); } }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,51 +1,51 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using Jellyfish.Virtu.Properties;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class MachineServices : IServiceProvider
|
||||
{
|
||||
public void AddService(Type serviceType, MachineService serviceProvider)
|
||||
{
|
||||
if (serviceType == null)
|
||||
{
|
||||
throw new ArgumentNullException("serviceType");
|
||||
}
|
||||
if (_serviceProviders.ContainsKey(serviceType))
|
||||
{
|
||||
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.ServiceAlreadyPresent, serviceType.FullName), "serviceType");
|
||||
}
|
||||
if (serviceProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException("serviceProvider");
|
||||
}
|
||||
if (!serviceType.IsAssignableFrom(serviceProvider.GetType()))
|
||||
{
|
||||
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.ServiceMustBeAssignable, serviceType.FullName, serviceProvider.GetType().FullName));
|
||||
}
|
||||
|
||||
_serviceProviders.Add(serviceType, serviceProvider);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
|
||||
public T GetService<T>()
|
||||
{
|
||||
return (T)((IServiceProvider)this).GetService(typeof(T));
|
||||
}
|
||||
|
||||
public void RemoveService(Type serviceType)
|
||||
{
|
||||
_serviceProviders.Remove(serviceType);
|
||||
}
|
||||
|
||||
object IServiceProvider.GetService(Type serviceType)
|
||||
{
|
||||
return _serviceProviders.ContainsKey(serviceType) ? _serviceProviders[serviceType] : null;
|
||||
}
|
||||
|
||||
private Dictionary<Type, MachineService> _serviceProviders = new Dictionary<Type, MachineService>();
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using Jellyfish.Virtu.Properties;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class MachineServices : IServiceProvider
|
||||
{
|
||||
public void AddService(Type serviceType, MachineService serviceProvider)
|
||||
{
|
||||
if (serviceType == null)
|
||||
{
|
||||
throw new ArgumentNullException("serviceType");
|
||||
}
|
||||
if (_serviceProviders.ContainsKey(serviceType))
|
||||
{
|
||||
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.ServiceAlreadyPresent, serviceType.FullName), "serviceType");
|
||||
}
|
||||
if (serviceProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException("serviceProvider");
|
||||
}
|
||||
if (!serviceType.IsAssignableFrom(serviceProvider.GetType()))
|
||||
{
|
||||
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.ServiceMustBeAssignable, serviceType.FullName, serviceProvider.GetType().FullName));
|
||||
}
|
||||
|
||||
_serviceProviders.Add(serviceType, serviceProvider);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
|
||||
public T GetService<T>()
|
||||
{
|
||||
return (T)((IServiceProvider)this).GetService(typeof(T));
|
||||
}
|
||||
|
||||
public void RemoveService(Type serviceType)
|
||||
{
|
||||
_serviceProviders.Remove(serviceType);
|
||||
}
|
||||
|
||||
object IServiceProvider.GetService(Type serviceType)
|
||||
{
|
||||
return _serviceProviders.ContainsKey(serviceType) ? _serviceProviders[serviceType] : null;
|
||||
}
|
||||
|
||||
private Dictionary<Type, MachineService> _serviceProviders = new Dictionary<Type, MachineService>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using Jellyfish.Virtu.Properties;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public abstract class StorageService : MachineService
|
||||
{
|
||||
protected StorageService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
public static Stream GetResourceStream(string resourceName, int resourceSize = 0)
|
||||
{
|
||||
var resourceManager = new ResourceManager("Jellyfish.Virtu.g", Assembly.GetExecutingAssembly()) { IgnoreCase = true };
|
||||
var resourceStream = (Stream)resourceManager.GetObject(resourceName);
|
||||
if (resourceStream == null)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ResourceNotFound, resourceName));
|
||||
}
|
||||
if ((resourceSize > 0) && (resourceStream.Length != resourceSize))
|
||||
{
|
||||
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ResourceInvalid, resourceName));
|
||||
}
|
||||
|
||||
return resourceStream;
|
||||
}
|
||||
|
||||
public abstract void Load(string path, Action<Stream> reader);
|
||||
public abstract void Save(string path, Action<Stream> writer);
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using Jellyfish.Virtu.Properties;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public abstract class StorageService : MachineService
|
||||
{
|
||||
protected StorageService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
|
||||
public static Stream GetResourceStream(string resourceName, int resourceSize = 0)
|
||||
{
|
||||
var resourceManager = new ResourceManager("Jellyfish.Virtu.g", Assembly.GetExecutingAssembly()) { IgnoreCase = true };
|
||||
var resourceStream = (Stream)resourceManager.GetObject(resourceName);
|
||||
if (resourceStream == null)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ResourceNotFound, resourceName));
|
||||
}
|
||||
if ((resourceSize > 0) && (resourceStream.Length != resourceSize))
|
||||
{
|
||||
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ResourceInvalid, resourceName));
|
||||
}
|
||||
|
||||
return resourceStream;
|
||||
}
|
||||
|
||||
public abstract void Load(string path, Action<Stream> reader);
|
||||
public abstract void Save(string path, Action<Stream> writer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public abstract class VideoService : MachineService
|
||||
{
|
||||
protected VideoService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract void SetPixel(int x, int y, uint color);
|
||||
public abstract void Update(); // main thread
|
||||
|
||||
public void ToggleFullScreen()
|
||||
{
|
||||
IsFullScreen ^= true;
|
||||
}
|
||||
|
||||
public bool IsFullScreen { get; private set; }
|
||||
}
|
||||
}
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public abstract class VideoService : MachineService
|
||||
{
|
||||
protected VideoService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract void SetPixel(int x, int y, uint color);
|
||||
public abstract void Update(); // main thread
|
||||
|
||||
public void ToggleFullScreen()
|
||||
{
|
||||
IsFullScreen ^= true;
|
||||
}
|
||||
|
||||
public bool IsFullScreen { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<jl:ApplicationBase x:Class="Jellyfish.Virtu.MainApp"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:jl="clr-namespace:Jellyfish.Library;assembly=Jellyfish.Library"
|
||||
xmlns:jv="clr-namespace:Jellyfish.Virtu;assembly=Jellyfish.Virtu">
|
||||
<Application.RootVisual>
|
||||
<jv:MainPage />
|
||||
</Application.RootVisual>
|
||||
<Application.Resources>
|
||||
</Application.Resources>
|
||||
</jl:ApplicationBase>
|
||||
<jl:ApplicationBase x:Class="Jellyfish.Virtu.MainApp"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:jl="clr-namespace:Jellyfish.Library;assembly=Jellyfish.Library"
|
||||
xmlns:jv="clr-namespace:Jellyfish.Virtu;assembly=Jellyfish.Virtu">
|
||||
<Application.RootVisual>
|
||||
<jv:MainPage />
|
||||
</Application.RootVisual>
|
||||
<Application.Resources>
|
||||
</Application.Resources>
|
||||
</jl:ApplicationBase>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed partial class MainApp : ApplicationBase
|
||||
{
|
||||
public MainApp() :
|
||||
base("Virtu")
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializeOutOfBrowserUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed partial class MainApp : ApplicationBase
|
||||
{
|
||||
public MainApp() :
|
||||
base("Virtu")
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializeOutOfBrowserUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
<UserControl x:Class="Jellyfish.Virtu.MainPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:jl="clr-namespace:Jellyfish.Library;assembly=Jellyfish.Library">
|
||||
<Grid Background="Black">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<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" />
|
||||
</StackPanel>
|
||||
<jl:FrameRateCounter Margin="0,0,4,0" HorizontalAlignment="Right" VerticalAlignment="Center" />
|
||||
<Grid Grid.Row="1">
|
||||
<Image x:Name="_image" MinWidth="560" MinHeight="384" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
<MediaElement x:Name="_media" />
|
||||
<ScrollViewer x:Name="_debugScrollViewer" BorderThickness="0" IsTabStop="False" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<TextBlock x:Name="_debugText" FontFamily="Consolas" FontSize="12" Foreground="White" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
<UserControl x:Class="Jellyfish.Virtu.MainPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:jl="clr-namespace:Jellyfish.Library;assembly=Jellyfish.Library">
|
||||
<Grid Background="Black">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<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" />
|
||||
</StackPanel>
|
||||
<jl:FrameRateCounter Margin="0,0,4,0" HorizontalAlignment="Right" VerticalAlignment="Center" />
|
||||
<Grid Grid.Row="1">
|
||||
<Image x:Name="_image" MinWidth="560" MinHeight="384" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
<MediaElement x:Name="_media" />
|
||||
<ScrollViewer x:Name="_debugScrollViewer" BorderThickness="0" IsTabStop="False" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<TextBlock x:Name="_debugText" FontFamily="Consolas" FontSize="12" Foreground="White" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
|
|
@ -1,95 +1,95 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using Jellyfish.Virtu.Services;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed partial class MainPage : UserControl, IDisposable
|
||||
{
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (!DesignerProperties.IsInDesignTool)
|
||||
{
|
||||
_debugService = new SilverlightDebugService(_machine, this);
|
||||
_storageService = new IsolatedStorageService(_machine);
|
||||
_keyboardService = new SilverlightKeyboardService(_machine, this);
|
||||
_gamePortService = new GamePortService(_machine); // not connected
|
||||
_audioService = new SilverlightAudioService(_machine, this, _media);
|
||||
_videoService = new SilverlightVideoService(_machine, this, _image);
|
||||
|
||||
_machine.Services.AddService(typeof(DebugService), _debugService);
|
||||
_machine.Services.AddService(typeof(StorageService), _storageService);
|
||||
_machine.Services.AddService(typeof(KeyboardService), _keyboardService);
|
||||
_machine.Services.AddService(typeof(GamePortService), _gamePortService);
|
||||
_machine.Services.AddService(typeof(AudioService), _audioService);
|
||||
_machine.Services.AddService(typeof(VideoService), _videoService);
|
||||
|
||||
Loaded += (sender, e) => _machine.Start();
|
||||
CompositionTarget.Rendering += OnCompositionTargetRendering;
|
||||
Application.Current.Exit += (sender, e) => _machine.Stop();
|
||||
|
||||
_disk1Button.Click += (sender, e) => OnDiskButtonClick(0);
|
||||
_disk2Button.Click += (sender, e) => OnDiskButtonClick(1);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_machine.Dispose();
|
||||
_debugService.Dispose();
|
||||
_storageService.Dispose();
|
||||
_keyboardService.Dispose();
|
||||
_gamePortService.Dispose();
|
||||
_audioService.Dispose();
|
||||
_videoService.Dispose();
|
||||
}
|
||||
|
||||
public void WriteLine(string message)
|
||||
{
|
||||
_debugText.Text += message;
|
||||
_debugScrollViewer.UpdateLayout();
|
||||
_debugScrollViewer.ScrollToVerticalOffset(double.MaxValue);
|
||||
}
|
||||
|
||||
private void OnCompositionTargetRendering(object sender, EventArgs e)
|
||||
{
|
||||
_keyboardService.Update();
|
||||
_gamePortService.Update();
|
||||
_videoService.Update();
|
||||
}
|
||||
|
||||
private void OnDiskButtonClick(int drive)
|
||||
{
|
||||
var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" };
|
||||
|
||||
bool? result = dialog.ShowDialog();
|
||||
if (result.HasValue && result.Value)
|
||||
{
|
||||
using (var stream = dialog.File.OpenRead())
|
||||
{
|
||||
_machine.Pause();
|
||||
var diskII = _machine.FindDiskIIController();
|
||||
if (diskII != null)
|
||||
{
|
||||
diskII.Drives[drive].InsertDisk(dialog.File.Name, stream, false);
|
||||
}
|
||||
_machine.Unpause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Machine _machine = new Machine();
|
||||
|
||||
private DebugService _debugService;
|
||||
private StorageService _storageService;
|
||||
private KeyboardService _keyboardService;
|
||||
private GamePortService _gamePortService;
|
||||
private AudioService _audioService;
|
||||
private VideoService _videoService;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using Jellyfish.Virtu.Services;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed partial class MainPage : UserControl, IDisposable
|
||||
{
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (!DesignerProperties.IsInDesignTool)
|
||||
{
|
||||
_debugService = new SilverlightDebugService(_machine, this);
|
||||
_storageService = new IsolatedStorageService(_machine);
|
||||
_keyboardService = new SilverlightKeyboardService(_machine, this);
|
||||
_gamePortService = new GamePortService(_machine); // not connected
|
||||
_audioService = new SilverlightAudioService(_machine, this, _media);
|
||||
_videoService = new SilverlightVideoService(_machine, this, _image);
|
||||
|
||||
_machine.Services.AddService(typeof(DebugService), _debugService);
|
||||
_machine.Services.AddService(typeof(StorageService), _storageService);
|
||||
_machine.Services.AddService(typeof(KeyboardService), _keyboardService);
|
||||
_machine.Services.AddService(typeof(GamePortService), _gamePortService);
|
||||
_machine.Services.AddService(typeof(AudioService), _audioService);
|
||||
_machine.Services.AddService(typeof(VideoService), _videoService);
|
||||
|
||||
Loaded += (sender, e) => _machine.Start();
|
||||
CompositionTarget.Rendering += OnCompositionTargetRendering;
|
||||
Application.Current.Exit += (sender, e) => _machine.Stop();
|
||||
|
||||
_disk1Button.Click += (sender, e) => OnDiskButtonClick(0);
|
||||
_disk2Button.Click += (sender, e) => OnDiskButtonClick(1);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_machine.Dispose();
|
||||
_debugService.Dispose();
|
||||
_storageService.Dispose();
|
||||
_keyboardService.Dispose();
|
||||
_gamePortService.Dispose();
|
||||
_audioService.Dispose();
|
||||
_videoService.Dispose();
|
||||
}
|
||||
|
||||
public void WriteLine(string message)
|
||||
{
|
||||
_debugText.Text += message;
|
||||
_debugScrollViewer.UpdateLayout();
|
||||
_debugScrollViewer.ScrollToVerticalOffset(double.MaxValue);
|
||||
}
|
||||
|
||||
private void OnCompositionTargetRendering(object sender, EventArgs e)
|
||||
{
|
||||
_keyboardService.Update();
|
||||
_gamePortService.Update();
|
||||
_videoService.Update();
|
||||
}
|
||||
|
||||
private void OnDiskButtonClick(int drive)
|
||||
{
|
||||
var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" };
|
||||
|
||||
bool? result = dialog.ShowDialog();
|
||||
if (result.HasValue && result.Value)
|
||||
{
|
||||
using (var stream = dialog.File.OpenRead())
|
||||
{
|
||||
_machine.Pause();
|
||||
var diskII = _machine.FindDiskIIController();
|
||||
if (diskII != null)
|
||||
{
|
||||
diskII.Drives[drive].InsertDisk(dialog.File.Name, stream, false);
|
||||
}
|
||||
_machine.Unpause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Machine _machine = new Machine();
|
||||
|
||||
private DebugService _debugService;
|
||||
private StorageService _storageService;
|
||||
private KeyboardService _keyboardService;
|
||||
private GamePortService _gamePortService;
|
||||
private AudioService _audioService;
|
||||
private VideoService _videoService;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<jl:ApplicationBase x:Class="Jellyfish.Virtu.MainApp"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
|
||||
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
|
||||
xmlns:jl="clr-namespace:Jellyfish.Library;assembly=Jellyfish.Library">
|
||||
<Application.Resources>
|
||||
</Application.Resources>
|
||||
|
||||
<Application.ApplicationLifetimeObjects>
|
||||
<shell:PhoneApplicationService />
|
||||
</Application.ApplicationLifetimeObjects>
|
||||
</jl:ApplicationBase>
|
||||
<jl:ApplicationBase x:Class="Jellyfish.Virtu.MainApp"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
|
||||
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
|
||||
xmlns:jl="clr-namespace:Jellyfish.Library;assembly=Jellyfish.Library">
|
||||
<Application.Resources>
|
||||
</Application.Resources>
|
||||
|
||||
<Application.ApplicationLifetimeObjects>
|
||||
<shell:PhoneApplicationService />
|
||||
</Application.ApplicationLifetimeObjects>
|
||||
</jl:ApplicationBase>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed partial class MainApp : ApplicationBase
|
||||
{
|
||||
public MainApp() :
|
||||
base("Virtu")
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializePhoneApplication();
|
||||
}
|
||||
}
|
||||
}
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed partial class MainApp : ApplicationBase
|
||||
{
|
||||
public MainApp() :
|
||||
base("Virtu")
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializePhoneApplication();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
<phone:PhoneApplicationPage
|
||||
x:Class="Jellyfish.Virtu.MainPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
|
||||
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:jl="clr-namespace:Jellyfish.Library;assembly=Jellyfish.Library"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="480"
|
||||
FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}"
|
||||
Foreground="{StaticResource PhoneForegroundBrush}"
|
||||
Orientation="Landscape" SupportedOrientations="Landscape" Title="Virtu">
|
||||
<Grid Background="Black">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<!--<StackPanel Orientation="Horizontal">
|
||||
<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" />
|
||||
</StackPanel>-->
|
||||
<jl:FrameRateCounter Margin="0,0,4,0" HorizontalAlignment="Right" VerticalAlignment="Center" />
|
||||
<Grid Grid.Row="1">
|
||||
<Image x:Name="_image" MinWidth="560" MinHeight="384" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
<MediaElement x:Name="_media" />
|
||||
<ScrollViewer x:Name="_debugScrollViewer" BorderThickness="0" IsTabStop="False" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<TextBlock x:Name="_debugText" FontFamily="Consolas" FontSize="12" Foreground="White" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</phone:PhoneApplicationPage>
|
||||
<phone:PhoneApplicationPage
|
||||
x:Class="Jellyfish.Virtu.MainPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
|
||||
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:jl="clr-namespace:Jellyfish.Library;assembly=Jellyfish.Library"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="480"
|
||||
FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}"
|
||||
Foreground="{StaticResource PhoneForegroundBrush}"
|
||||
Orientation="Landscape" SupportedOrientations="Landscape" Title="Virtu">
|
||||
<Grid Background="Black">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<!--<StackPanel Orientation="Horizontal">
|
||||
<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" />
|
||||
</StackPanel>-->
|
||||
<jl:FrameRateCounter Margin="0,0,4,0" HorizontalAlignment="Right" VerticalAlignment="Center" />
|
||||
<Grid Grid.Row="1">
|
||||
<Image x:Name="_image" MinWidth="560" MinHeight="384" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
<MediaElement x:Name="_media" />
|
||||
<ScrollViewer x:Name="_debugScrollViewer" BorderThickness="0" IsTabStop="False" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<TextBlock x:Name="_debugText" FontFamily="Consolas" FontSize="12" Foreground="White" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</phone:PhoneApplicationPage>
|
||||
|
|
|
@ -1,91 +1,91 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using Jellyfish.Virtu.Services;
|
||||
using Microsoft.Phone.Controls;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed partial class MainPage : PhoneApplicationPage, IDisposable
|
||||
{
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (!DesignerProperties.IsInDesignTool)
|
||||
{
|
||||
_debugService = new SilverlightDebugService(_machine, this);
|
||||
_storageService = new IsolatedStorageService(_machine);
|
||||
_keyboardService = new SilverlightKeyboardService(_machine, this);
|
||||
_gamePortService = new GamePortService(_machine); // not connected
|
||||
_audioService = new SilverlightAudioService(_machine, this, _media);
|
||||
_videoService = new SilverlightVideoService(_machine, this, _image);
|
||||
|
||||
_machine.Services.AddService(typeof(DebugService), _debugService);
|
||||
_machine.Services.AddService(typeof(StorageService), _storageService);
|
||||
_machine.Services.AddService(typeof(KeyboardService), _keyboardService);
|
||||
_machine.Services.AddService(typeof(GamePortService), _gamePortService);
|
||||
_machine.Services.AddService(typeof(AudioService), _audioService);
|
||||
_machine.Services.AddService(typeof(VideoService), _videoService);
|
||||
|
||||
Loaded += (sender, e) => _machine.Start();
|
||||
CompositionTarget.Rendering += OnCompositionTargetRendering;
|
||||
Application.Current.Exit += (sender, e) => _machine.Stop();
|
||||
|
||||
//_disk1Button.Click += (sender, e) => OnDiskButtonClick(0); // TODO
|
||||
//_disk2Button.Click += (sender, e) => OnDiskButtonClick(1);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_machine.Dispose();
|
||||
_debugService.Dispose();
|
||||
_storageService.Dispose();
|
||||
_keyboardService.Dispose();
|
||||
_gamePortService.Dispose();
|
||||
_audioService.Dispose();
|
||||
_videoService.Dispose();
|
||||
}
|
||||
|
||||
public void WriteLine(string message)
|
||||
{
|
||||
_debugText.Text += message;
|
||||
_debugScrollViewer.UpdateLayout();
|
||||
_debugScrollViewer.ScrollToVerticalOffset(double.MaxValue);
|
||||
}
|
||||
|
||||
private void OnCompositionTargetRendering(object sender, EventArgs e)
|
||||
{
|
||||
_keyboardService.Update();
|
||||
_gamePortService.Update();
|
||||
_videoService.Update();
|
||||
}
|
||||
|
||||
//private void OnDiskButtonClick(int drive) // TODO
|
||||
//{
|
||||
// var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" };
|
||||
|
||||
// bool? result = dialog.ShowDialog();
|
||||
// if (result.HasValue && result.Value)
|
||||
// {
|
||||
// using (var stream = dialog.File.OpenRead())
|
||||
// {
|
||||
// _machine.Pause();
|
||||
// _machine.DiskII.Drives[drive].InsertDisk(dialog.File.Name, stream, false);
|
||||
// _machine.Unpause();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
private Machine _machine = new Machine();
|
||||
|
||||
private DebugService _debugService;
|
||||
private StorageService _storageService;
|
||||
private KeyboardService _keyboardService;
|
||||
private GamePortService _gamePortService;
|
||||
private AudioService _audioService;
|
||||
private VideoService _videoService;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using Jellyfish.Virtu.Services;
|
||||
using Microsoft.Phone.Controls;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed partial class MainPage : PhoneApplicationPage, IDisposable
|
||||
{
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (!DesignerProperties.IsInDesignTool)
|
||||
{
|
||||
_debugService = new SilverlightDebugService(_machine, this);
|
||||
_storageService = new IsolatedStorageService(_machine);
|
||||
_keyboardService = new SilverlightKeyboardService(_machine, this);
|
||||
_gamePortService = new GamePortService(_machine); // not connected
|
||||
_audioService = new SilverlightAudioService(_machine, this, _media);
|
||||
_videoService = new SilverlightVideoService(_machine, this, _image);
|
||||
|
||||
_machine.Services.AddService(typeof(DebugService), _debugService);
|
||||
_machine.Services.AddService(typeof(StorageService), _storageService);
|
||||
_machine.Services.AddService(typeof(KeyboardService), _keyboardService);
|
||||
_machine.Services.AddService(typeof(GamePortService), _gamePortService);
|
||||
_machine.Services.AddService(typeof(AudioService), _audioService);
|
||||
_machine.Services.AddService(typeof(VideoService), _videoService);
|
||||
|
||||
Loaded += (sender, e) => _machine.Start();
|
||||
CompositionTarget.Rendering += OnCompositionTargetRendering;
|
||||
Application.Current.Exit += (sender, e) => _machine.Stop();
|
||||
|
||||
//_disk1Button.Click += (sender, e) => OnDiskButtonClick(0); // TODO
|
||||
//_disk2Button.Click += (sender, e) => OnDiskButtonClick(1);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_machine.Dispose();
|
||||
_debugService.Dispose();
|
||||
_storageService.Dispose();
|
||||
_keyboardService.Dispose();
|
||||
_gamePortService.Dispose();
|
||||
_audioService.Dispose();
|
||||
_videoService.Dispose();
|
||||
}
|
||||
|
||||
public void WriteLine(string message)
|
||||
{
|
||||
_debugText.Text += message;
|
||||
_debugScrollViewer.UpdateLayout();
|
||||
_debugScrollViewer.ScrollToVerticalOffset(double.MaxValue);
|
||||
}
|
||||
|
||||
private void OnCompositionTargetRendering(object sender, EventArgs e)
|
||||
{
|
||||
_keyboardService.Update();
|
||||
_gamePortService.Update();
|
||||
_videoService.Update();
|
||||
}
|
||||
|
||||
//private void OnDiskButtonClick(int drive) // TODO
|
||||
//{
|
||||
// var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" };
|
||||
|
||||
// bool? result = dialog.ShowDialog();
|
||||
// if (result.HasValue && result.Value)
|
||||
// {
|
||||
// using (var stream = dialog.File.OpenRead())
|
||||
// {
|
||||
// _machine.Pause();
|
||||
// _machine.DiskII.Drives[drive].InsertDisk(dialog.File.Name, stream, false);
|
||||
// _machine.Unpause();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
private Machine _machine = new Machine();
|
||||
|
||||
private DebugService _debugService;
|
||||
private StorageService _storageService;
|
||||
private KeyboardService _keyboardService;
|
||||
private GamePortService _gamePortService;
|
||||
private AudioService _audioService;
|
||||
private VideoService _videoService;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Deployment.Parts>
|
||||
</Deployment.Parts>
|
||||
</Deployment>
|
||||
<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Deployment.Parts>
|
||||
</Deployment.Parts>
|
||||
</Deployment>
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using Jellyfish.Library;
|
||||
|
||||
[assembly: AssemblyTitle("Virtu")]
|
||||
[assembly: AssemblyDescription("Apple IIe Emulator")]
|
||||
[assembly: AssemblyProduct("Jellyfish.Virtu.Silverlight.Phone")]
|
||||
[assembly: AssemblyCompany("Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")]
|
||||
|
||||
[assembly: AssemblyVersion("0.8.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.8.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.8.3.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("89a50370-1ed9-4cf1-ad08-043b6e6f3c90")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using Jellyfish.Library;
|
||||
|
||||
[assembly: AssemblyTitle("Virtu")]
|
||||
[assembly: AssemblyDescription("Apple IIe Emulator")]
|
||||
[assembly: AssemblyProduct("Jellyfish.Virtu.Silverlight.Phone")]
|
||||
[assembly: AssemblyCompany("Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")]
|
||||
|
||||
[assembly: AssemblyVersion("0.8.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.8.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.8.3.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("89a50370-1ed9-4cf1-ad08-043b6e6f3c90")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Deployment xmlns="http://schemas.microsoft.com/windowsphone/2009/deployment" AppPlatformVersion="7.0">
|
||||
<App xmlns="" ProductID="{89a50370-1ed9-4cf1-ad08-043b6e6f3c90}" Title="Virtu" RuntimeType="Silverlight" Version="1.0.0.0" Genre="Apps.Normal" Author="Sean Fausett & Nick Westgate" Description="Apple IIe Emulator" Publisher="Digital Jellyfish Design Ltd">
|
||||
<IconPath IsRelative="true" IsResource="false">AppIcon.png</IconPath>
|
||||
<Capabilities>
|
||||
<Capability Name="ID_CAP_NETWORKING" />
|
||||
<Capability Name="ID_CAP_LOCATION" />
|
||||
<Capability Name="ID_CAP_SENSORS" />
|
||||
<Capability Name="ID_CAP_MICROPHONE" />
|
||||
<Capability Name="ID_CAP_MEDIALIB" />
|
||||
<Capability Name="ID_CAP_GAMERSERVICES" />
|
||||
<Capability Name="ID_CAP_PHONEDIALER" />
|
||||
<Capability Name="ID_CAP_PUSH_NOTIFICATION" />
|
||||
<Capability Name="ID_CAP_WEBBROWSERCOMPONENT" />
|
||||
</Capabilities>
|
||||
<Tasks>
|
||||
<DefaultTask Name="_default" NavigationPage="MainPage.xaml" />
|
||||
</Tasks>
|
||||
<Tokens>
|
||||
<PrimaryToken TokenID="Jellyfish.Virtu.Silverlight.Phone.Token" TaskName="_default">
|
||||
<TemplateType5>
|
||||
<BackgroundImageURI IsRelative="true" IsResource="false">Background.png</BackgroundImageURI>
|
||||
<Count>0</Count>
|
||||
<Title>Virtu</Title>
|
||||
</TemplateType5>
|
||||
</PrimaryToken>
|
||||
</Tokens>
|
||||
</App>
|
||||
</Deployment>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Deployment xmlns="http://schemas.microsoft.com/windowsphone/2009/deployment" AppPlatformVersion="7.0">
|
||||
<App xmlns="" ProductID="{89a50370-1ed9-4cf1-ad08-043b6e6f3c90}" Title="Virtu" RuntimeType="Silverlight" Version="1.0.0.0" Genre="Apps.Normal" Author="Sean Fausett & Nick Westgate" Description="Apple IIe Emulator" Publisher="Digital Jellyfish Design Ltd">
|
||||
<IconPath IsRelative="true" IsResource="false">AppIcon.png</IconPath>
|
||||
<Capabilities>
|
||||
<Capability Name="ID_CAP_NETWORKING" />
|
||||
<Capability Name="ID_CAP_LOCATION" />
|
||||
<Capability Name="ID_CAP_SENSORS" />
|
||||
<Capability Name="ID_CAP_MICROPHONE" />
|
||||
<Capability Name="ID_CAP_MEDIALIB" />
|
||||
<Capability Name="ID_CAP_GAMERSERVICES" />
|
||||
<Capability Name="ID_CAP_PHONEDIALER" />
|
||||
<Capability Name="ID_CAP_PUSH_NOTIFICATION" />
|
||||
<Capability Name="ID_CAP_WEBBROWSERCOMPONENT" />
|
||||
</Capabilities>
|
||||
<Tasks>
|
||||
<DefaultTask Name="_default" NavigationPage="MainPage.xaml" />
|
||||
</Tasks>
|
||||
<Tokens>
|
||||
<PrimaryToken TokenID="Jellyfish.Virtu.Silverlight.Phone.Token" TaskName="_default">
|
||||
<TemplateType5>
|
||||
<BackgroundImageURI IsRelative="true" IsResource="false">Background.png</BackgroundImageURI>
|
||||
<Count>0</Count>
|
||||
<Title>Virtu</Title>
|
||||
</TemplateType5>
|
||||
</PrimaryToken>
|
||||
</Tokens>
|
||||
</App>
|
||||
</Deployment>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Deployment.Parts>
|
||||
</Deployment.Parts>
|
||||
</Deployment>
|
||||
<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Deployment.Parts>
|
||||
</Deployment.Parts>
|
||||
</Deployment>
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using Jellyfish.Library;
|
||||
|
||||
[assembly: AssemblyTitle("Virtu")]
|
||||
[assembly: AssemblyDescription("Apple IIe Emulator")]
|
||||
[assembly: AssemblyProduct("Jellyfish.Virtu.Silverlight")]
|
||||
[assembly: AssemblyCompany("Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")]
|
||||
|
||||
[assembly: AssemblyVersion("0.8.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.8.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.8.3.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("89a50370-1ed9-4cf1-ad08-043b6e6f3c90")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using Jellyfish.Library;
|
||||
|
||||
[assembly: AssemblyTitle("Virtu")]
|
||||
[assembly: AssemblyDescription("Apple IIe Emulator")]
|
||||
[assembly: AssemblyProduct("Jellyfish.Virtu.Silverlight")]
|
||||
[assembly: AssemblyCompany("Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")]
|
||||
|
||||
[assembly: AssemblyVersion("0.8.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.8.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.8.3.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("89a50370-1ed9-4cf1-ad08-043b6e6f3c90")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<OutOfBrowserSettings ShortName="Virtu" EnableGPUAcceleration="False" ShowInstallMenuItem="True">
|
||||
<OutOfBrowserSettings.Blurb>Apple IIe Emulator</OutOfBrowserSettings.Blurb>
|
||||
<OutOfBrowserSettings.WindowSettings>
|
||||
<WindowSettings Title="Virtu" />
|
||||
</OutOfBrowserSettings.WindowSettings>
|
||||
<OutOfBrowserSettings.SecuritySettings>
|
||||
<SecuritySettings ElevatedPermissions="Required" />
|
||||
</OutOfBrowserSettings.SecuritySettings>
|
||||
<OutOfBrowserSettings.Icons>
|
||||
<Icon Size="16,16">AppIcon16.png</Icon>
|
||||
<Icon Size="32,32">AppIcon32.png</Icon>
|
||||
<Icon Size="48,48">AppIcon48.png</Icon>
|
||||
<Icon Size="128,128">AppIcon128.png</Icon>
|
||||
</OutOfBrowserSettings.Icons>
|
||||
<OutOfBrowserSettings ShortName="Virtu" EnableGPUAcceleration="False" ShowInstallMenuItem="True">
|
||||
<OutOfBrowserSettings.Blurb>Apple IIe Emulator</OutOfBrowserSettings.Blurb>
|
||||
<OutOfBrowserSettings.WindowSettings>
|
||||
<WindowSettings Title="Virtu" />
|
||||
</OutOfBrowserSettings.WindowSettings>
|
||||
<OutOfBrowserSettings.SecuritySettings>
|
||||
<SecuritySettings ElevatedPermissions="Required" />
|
||||
</OutOfBrowserSettings.SecuritySettings>
|
||||
<OutOfBrowserSettings.Icons>
|
||||
<Icon Size="16,16">AppIcon16.png</Icon>
|
||||
<Icon Size="32,32">AppIcon32.png</Icon>
|
||||
<Icon Size="48,48">AppIcon48.png</Icon>
|
||||
<Icon Size="128,128">AppIcon128.png</Icon>
|
||||
</OutOfBrowserSettings.Icons>
|
||||
</OutOfBrowserSettings>
|
|
@ -1,60 +1,60 @@
|
|||
using System;
|
||||
using System.Windows.Controls;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class SilverlightAudioService : AudioService
|
||||
{
|
||||
public SilverlightAudioService(Machine machine, UserControl page, MediaElement media) :
|
||||
base(machine)
|
||||
{
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException("page");
|
||||
}
|
||||
if (media == null)
|
||||
{
|
||||
throw new ArgumentNullException("media");
|
||||
}
|
||||
|
||||
_media = media;
|
||||
_mediaSource = new WaveMediaStreamSource(SampleRate, SampleChannels, SampleBits, SampleSize, SampleLatency, OnMediaSourceUpdate);
|
||||
_media.SetSource(_mediaSource);
|
||||
|
||||
page.Loaded += (sender, e) => _media.Play();
|
||||
#if !WINDOWS_PHONE
|
||||
page.Unloaded += (sender, e) => _media.Stop();
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void SetVolume(double volume) // machine thread
|
||||
{
|
||||
_media.Dispatcher.BeginInvoke(() => _media.Volume = volume);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_mediaSource.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void OnMediaSourceUpdate(byte[] buffer, int bufferSize) // audio thread
|
||||
{
|
||||
//if (_count++ % (1000 / SampleLatency) == 0)
|
||||
//{
|
||||
// DebugService.WriteLine("OnMediaSourceUpdate");
|
||||
//}
|
||||
|
||||
Update(bufferSize, (source, count) => Buffer.BlockCopy(source, 0, buffer, 0, count));
|
||||
}
|
||||
|
||||
private MediaElement _media;
|
||||
private WaveMediaStreamSource _mediaSource;
|
||||
//private int _count;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Windows.Controls;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class SilverlightAudioService : AudioService
|
||||
{
|
||||
public SilverlightAudioService(Machine machine, UserControl page, MediaElement media) :
|
||||
base(machine)
|
||||
{
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException("page");
|
||||
}
|
||||
if (media == null)
|
||||
{
|
||||
throw new ArgumentNullException("media");
|
||||
}
|
||||
|
||||
_media = media;
|
||||
_mediaSource = new WaveMediaStreamSource(SampleRate, SampleChannels, SampleBits, SampleSize, SampleLatency, OnMediaSourceUpdate);
|
||||
_media.SetSource(_mediaSource);
|
||||
|
||||
page.Loaded += (sender, e) => _media.Play();
|
||||
#if !WINDOWS_PHONE
|
||||
page.Unloaded += (sender, e) => _media.Stop();
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void SetVolume(double volume) // machine thread
|
||||
{
|
||||
_media.Dispatcher.BeginInvoke(() => _media.Volume = volume);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_mediaSource.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void OnMediaSourceUpdate(byte[] buffer, int bufferSize) // audio thread
|
||||
{
|
||||
//if (_count++ % (1000 / SampleLatency) == 0)
|
||||
//{
|
||||
// DebugService.WriteLine("OnMediaSourceUpdate");
|
||||
//}
|
||||
|
||||
Update(bufferSize, (source, count) => Buffer.BlockCopy(source, 0, buffer, 0, count));
|
||||
}
|
||||
|
||||
private MediaElement _media;
|
||||
private WaveMediaStreamSource _mediaSource;
|
||||
//private int _count;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
using System;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class SilverlightDebugService : DebugService
|
||||
{
|
||||
public SilverlightDebugService(Machine machine, MainPage page) :
|
||||
base(machine)
|
||||
{
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException("page");
|
||||
}
|
||||
|
||||
_page = page;
|
||||
}
|
||||
|
||||
protected override void OnWriteLine(string message)
|
||||
{
|
||||
_page.Dispatcher.CheckBeginInvoke(() => _page.WriteLine(message + Environment.NewLine));
|
||||
}
|
||||
|
||||
private MainPage _page;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class SilverlightDebugService : DebugService
|
||||
{
|
||||
public SilverlightDebugService(Machine machine, MainPage page) :
|
||||
base(machine)
|
||||
{
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException("page");
|
||||
}
|
||||
|
||||
_page = page;
|
||||
}
|
||||
|
||||
protected override void OnWriteLine(string message)
|
||||
{
|
||||
_page.Dispatcher.CheckBeginInvoke(() => _page.WriteLine(message + Environment.NewLine));
|
||||
}
|
||||
|
||||
private MainPage _page;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,402 +1,402 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class SilverlightKeyboardService : KeyboardService
|
||||
{
|
||||
public SilverlightKeyboardService(Machine machine, UserControl page) :
|
||||
base(machine)
|
||||
{
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException("page");
|
||||
}
|
||||
|
||||
page.KeyDown += OnPageKeyDown;
|
||||
page.KeyUp += OnPageKeyUp;
|
||||
page.LostFocus += OnPageLostFocus;
|
||||
}
|
||||
|
||||
public override bool IsKeyDown(int key)
|
||||
{
|
||||
return IsKeyDown((Key)key);
|
||||
}
|
||||
|
||||
public override void Update() // main thread
|
||||
{
|
||||
if (_updateAnyKeyDown) // SL is missing access to keyboard state; could lose track of keyboard state after Alt+Tab
|
||||
{
|
||||
_updateAnyKeyDown = false;
|
||||
IsAnyKeyDown = false;
|
||||
foreach (Key key in KeyValues)
|
||||
{
|
||||
if (IsKeyDown(key))
|
||||
{
|
||||
IsAnyKeyDown = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var modifiers = System.Windows.Input.Keyboard.Modifiers;
|
||||
IsControlKeyDown = ((modifiers & ModifierKeys.Control) != 0);
|
||||
IsShiftKeyDown = ((modifiers & ModifierKeys.Shift) != 0);
|
||||
|
||||
IsOpenAppleKeyDown = ((modifiers & ModifierKeys.Alt) != 0) || IsKeyDown(Key.NumPad0);
|
||||
IsCloseAppleKeyDown = ((modifiers & ModifierKeys.Windows) != 0) || IsKeyDown(Key.Decimal);
|
||||
IsResetKeyDown = IsControlKeyDown && IsKeyDown(Key.Back);
|
||||
|
||||
base.Update();
|
||||
}
|
||||
|
||||
private bool IsKeyDown(Key key)
|
||||
{
|
||||
return _states[(int)key];
|
||||
}
|
||||
|
||||
private void OnPageKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
//DebugService.WriteLine(string.Concat("OnPageKeyDn: Key=", e.Key, " PlatformKeyCode=", e.PlatformKeyCode));
|
||||
|
||||
_states[(int)e.Key] = true;
|
||||
_updateAnyKeyDown = false;
|
||||
IsAnyKeyDown = true;
|
||||
|
||||
int asciiKey = GetAsciiKey(e.Key, e.PlatformKeyCode);
|
||||
if (asciiKey >= 0)
|
||||
{
|
||||
Machine.Keyboard.Latch = asciiKey;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
private void OnPageKeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
//DebugService.WriteLine(string.Concat("OnPageKeyUp: Key=", e.Key, " PlatformKeyCode=", e.PlatformKeyCode));
|
||||
|
||||
_states[(int)e.Key] = false;
|
||||
_updateAnyKeyDown = true;
|
||||
|
||||
var 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
|
||||
{
|
||||
IsAnyKeyDown = false;
|
||||
foreach (Key key in KeyValues)
|
||||
{
|
||||
_states[(int)key] = false;
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
|
||||
[SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode")]
|
||||
private int GetAsciiKey(Key key, int platformKeyCode)
|
||||
{
|
||||
var modifiers = System.Windows.Input.Keyboard.Modifiers;
|
||||
bool control = ((modifiers & ModifierKeys.Control) != 0);
|
||||
bool shift = ((modifiers & ModifierKeys.Shift) != 0);
|
||||
bool capsLock = shift ^ _capsLock;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case Key.Left:
|
||||
return 0x08;
|
||||
|
||||
case Key.Tab:
|
||||
return 0x09;
|
||||
|
||||
case Key.Down:
|
||||
return 0x0A;
|
||||
|
||||
case Key.Up:
|
||||
return 0x0B;
|
||||
|
||||
case Key.Enter:
|
||||
return 0x0D;
|
||||
|
||||
case Key.Right:
|
||||
return 0x15;
|
||||
|
||||
case Key.Escape:
|
||||
return 0x1B;
|
||||
|
||||
case Key.Back:
|
||||
return control ? -1 : 0x7F;
|
||||
|
||||
case Key.Space:
|
||||
return ' ';
|
||||
|
||||
case Key.D1:
|
||||
return shift ? '!' : '1';
|
||||
|
||||
case Key.D2:
|
||||
return control ? 0x00 : shift ? '@' : '2';
|
||||
|
||||
case Key.D3:
|
||||
return shift ? '#' : '3';
|
||||
|
||||
case Key.D4:
|
||||
return shift ? '$' : '4';
|
||||
|
||||
case Key.D5:
|
||||
return shift ? '%' : '5';
|
||||
|
||||
case Key.D6:
|
||||
return control ? 0x1E : shift ? '^' : '6';
|
||||
|
||||
case Key.D7:
|
||||
return shift ? '&' : '7';
|
||||
|
||||
case Key.D8:
|
||||
return shift ? '*' : '8';
|
||||
|
||||
case Key.D9:
|
||||
return shift ? '(' : '9';
|
||||
|
||||
case Key.D0:
|
||||
return shift ? ')' : '0';
|
||||
|
||||
case Key.A:
|
||||
return control ? 0x01 : capsLock ? 'A' : 'a';
|
||||
|
||||
case Key.B:
|
||||
return control ? 0x02 : capsLock ? 'B' : 'b';
|
||||
|
||||
case Key.C:
|
||||
return control ? 0x03 : capsLock ? 'C' : 'c';
|
||||
|
||||
case Key.D:
|
||||
return control ? 0x04 : capsLock ? 'D' : 'd';
|
||||
|
||||
case Key.E:
|
||||
return control ? 0x05 : capsLock ? 'E' : 'e';
|
||||
|
||||
case Key.F:
|
||||
return control ? 0x06 : capsLock ? 'F' : 'f';
|
||||
|
||||
case Key.G:
|
||||
return control ? 0x07 : capsLock ? 'G' : 'g';
|
||||
|
||||
case Key.H:
|
||||
return control ? 0x08 : capsLock ? 'H' : 'h';
|
||||
|
||||
case Key.I:
|
||||
return control ? 0x09 : capsLock ? 'I' : 'i';
|
||||
|
||||
case Key.J:
|
||||
return control ? 0x0A : capsLock ? 'J' : 'j';
|
||||
|
||||
case Key.K:
|
||||
return control ? 0x0B : capsLock ? 'K' : 'k';
|
||||
|
||||
case Key.L:
|
||||
return control ? 0x0C : capsLock ? 'L' : 'l';
|
||||
|
||||
case Key.M:
|
||||
return control ? 0x0D : capsLock ? 'M' : 'm';
|
||||
|
||||
case Key.N:
|
||||
return control ? 0x0E : capsLock ? 'N' : 'n';
|
||||
|
||||
case Key.O:
|
||||
return control ? 0x0F : capsLock ? 'O' : 'o';
|
||||
|
||||
case Key.P:
|
||||
return control ? 0x10 : capsLock ? 'P' : 'p';
|
||||
|
||||
case Key.Q:
|
||||
return control ? 0x11 : capsLock ? 'Q' : 'q';
|
||||
|
||||
case Key.R:
|
||||
return control ? 0x12 : capsLock ? 'R' : 'r';
|
||||
|
||||
case Key.S:
|
||||
return control ? 0x13 : capsLock ? 'S' : 's';
|
||||
|
||||
case Key.T:
|
||||
return control ? 0x14 : capsLock ? 'T' : 't';
|
||||
|
||||
case Key.U:
|
||||
return control ? 0x15 : capsLock ? 'U' : 'u';
|
||||
|
||||
case Key.V:
|
||||
return control ? 0x16 : capsLock ? 'V' : 'v';
|
||||
|
||||
case Key.W:
|
||||
return control ? 0x17 : capsLock ? 'W' : 'w';
|
||||
|
||||
case Key.X:
|
||||
return control ? 0x18 : capsLock ? 'X' : 'x';
|
||||
|
||||
case Key.Y:
|
||||
return control ? 0x19 : capsLock ? 'Y' : 'y';
|
||||
|
||||
case Key.Z:
|
||||
return control ? 0x1A : capsLock ? 'Z' : 'z';
|
||||
|
||||
case Key.Unknown:
|
||||
switch (Environment.OSVersion.Platform)
|
||||
{
|
||||
case PlatformID.Win32NT:
|
||||
switch (platformKeyCode)
|
||||
{
|
||||
case 0xBA: // WinForms Keys.Oem1
|
||||
return shift ? ':' : ';';
|
||||
|
||||
case 0xBF: // WinForms Keys.Oem2
|
||||
return shift ? '?' : '/';
|
||||
|
||||
case 0xC0: // WinForms Keys.Oem3
|
||||
return shift ? '~' : '`';
|
||||
|
||||
case 0xDB: // WinForms Keys.Oem4
|
||||
return shift ? '{' : '[';
|
||||
|
||||
case 0xDC: // WinForms Keys.Oem5
|
||||
return control ? 0x1C : shift ? '|' : '\\';
|
||||
|
||||
case 0xDD: // WinForms Keys.Oem6
|
||||
return control ? 0x1D : shift ? '}' : ']';
|
||||
|
||||
case 0xDE: // WinForms Keys.Oem7
|
||||
return shift ? '"' : '\'';
|
||||
|
||||
case 0xBD: // WinForms Keys.OemMinus
|
||||
return control ? 0x1F : shift ? '_' : '-';
|
||||
|
||||
case 0xBB: // WinForms Keys.OemPlus
|
||||
return shift ? '+' : '=';
|
||||
|
||||
case 0xBC: // WinForms Keys.OemComma
|
||||
return shift ? '<' : ',';
|
||||
|
||||
case 0xBE: // WinForms Keys.OemPeriod
|
||||
return shift ? '>' : '.';
|
||||
}
|
||||
break;
|
||||
#if !WINDOWS_PHONE
|
||||
case PlatformID.MacOSX:
|
||||
switch (platformKeyCode)
|
||||
{
|
||||
case 0x29:
|
||||
return shift ? ':' : ';';
|
||||
|
||||
case 0x2C:
|
||||
return shift ? '?' : '/';
|
||||
|
||||
case 0x32:
|
||||
return shift ? '~' : '`';
|
||||
|
||||
case 0x21:
|
||||
return shift ? '{' : '[';
|
||||
|
||||
case 0x2A:
|
||||
return control ? 0x1C : shift ? '|' : '\\';
|
||||
|
||||
case 0x1E:
|
||||
return control ? 0x1D : shift ? '}' : ']';
|
||||
|
||||
case 0x27:
|
||||
return shift ? '"' : '\'';
|
||||
|
||||
case 0x1B:
|
||||
return control ? 0x1F : shift ? '_' : '-';
|
||||
|
||||
case 0x18:
|
||||
return shift ? '+' : '=';
|
||||
|
||||
case 0x2B:
|
||||
return shift ? '<' : ',';
|
||||
|
||||
case 0x2F:
|
||||
return shift ? '>' : '.';
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case PlatformID.Unix:
|
||||
switch (platformKeyCode)
|
||||
{
|
||||
case 0x2F:
|
||||
return shift ? ':' : ';';
|
||||
|
||||
case 0x3D:
|
||||
return shift ? '?' : '/';
|
||||
|
||||
case 0x31:
|
||||
return shift ? '~' : '`';
|
||||
|
||||
case 0x22:
|
||||
return shift ? '{' : '[';
|
||||
|
||||
case 0x33:
|
||||
return control ? 0x1C : shift ? '|' : '\\';
|
||||
|
||||
case 0x23:
|
||||
return control ? 0x1D : shift ? '}' : ']';
|
||||
|
||||
case 0x30:
|
||||
return shift ? '"' : '\'';
|
||||
|
||||
case 0x14:
|
||||
return control ? 0x1F : shift ? '_' : '-';
|
||||
|
||||
case 0x15:
|
||||
return shift ? '+' : '=';
|
||||
|
||||
case 0x3B:
|
||||
return shift ? '<' : ',';
|
||||
|
||||
case 0x3C:
|
||||
return shift ? '>' : '.';
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static readonly Key[] KeyValues =
|
||||
(from key in
|
||||
(from field in typeof(Key).GetFields() // missing Enum.GetValues; use reflection
|
||||
where field.IsLiteral
|
||||
select (Key)field.GetValue(typeof(Key)))
|
||||
where (key != Key.None) // filter Key.None
|
||||
select key).ToArray();
|
||||
|
||||
private static readonly int KeyCount = (int)(KeyValues.Max()) + 1;
|
||||
|
||||
private bool[] _states = new bool[KeyCount];
|
||||
private bool _capsLock;
|
||||
private bool _updateAnyKeyDown;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class SilverlightKeyboardService : KeyboardService
|
||||
{
|
||||
public SilverlightKeyboardService(Machine machine, UserControl page) :
|
||||
base(machine)
|
||||
{
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException("page");
|
||||
}
|
||||
|
||||
page.KeyDown += OnPageKeyDown;
|
||||
page.KeyUp += OnPageKeyUp;
|
||||
page.LostFocus += OnPageLostFocus;
|
||||
}
|
||||
|
||||
public override bool IsKeyDown(int key)
|
||||
{
|
||||
return IsKeyDown((Key)key);
|
||||
}
|
||||
|
||||
public override void Update() // main thread
|
||||
{
|
||||
if (_updateAnyKeyDown) // SL is missing access to keyboard state; could lose track of keyboard state after Alt+Tab
|
||||
{
|
||||
_updateAnyKeyDown = false;
|
||||
IsAnyKeyDown = false;
|
||||
foreach (Key key in KeyValues)
|
||||
{
|
||||
if (IsKeyDown(key))
|
||||
{
|
||||
IsAnyKeyDown = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var modifiers = System.Windows.Input.Keyboard.Modifiers;
|
||||
IsControlKeyDown = ((modifiers & ModifierKeys.Control) != 0);
|
||||
IsShiftKeyDown = ((modifiers & ModifierKeys.Shift) != 0);
|
||||
|
||||
IsOpenAppleKeyDown = ((modifiers & ModifierKeys.Alt) != 0) || IsKeyDown(Key.NumPad0);
|
||||
IsCloseAppleKeyDown = ((modifiers & ModifierKeys.Windows) != 0) || IsKeyDown(Key.Decimal);
|
||||
IsResetKeyDown = IsControlKeyDown && IsKeyDown(Key.Back);
|
||||
|
||||
base.Update();
|
||||
}
|
||||
|
||||
private bool IsKeyDown(Key key)
|
||||
{
|
||||
return _states[(int)key];
|
||||
}
|
||||
|
||||
private void OnPageKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
//DebugService.WriteLine(string.Concat("OnPageKeyDn: Key=", e.Key, " PlatformKeyCode=", e.PlatformKeyCode));
|
||||
|
||||
_states[(int)e.Key] = true;
|
||||
_updateAnyKeyDown = false;
|
||||
IsAnyKeyDown = true;
|
||||
|
||||
int asciiKey = GetAsciiKey(e.Key, e.PlatformKeyCode);
|
||||
if (asciiKey >= 0)
|
||||
{
|
||||
Machine.Keyboard.Latch = asciiKey;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
private void OnPageKeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
//DebugService.WriteLine(string.Concat("OnPageKeyUp: Key=", e.Key, " PlatformKeyCode=", e.PlatformKeyCode));
|
||||
|
||||
_states[(int)e.Key] = false;
|
||||
_updateAnyKeyDown = true;
|
||||
|
||||
var 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
|
||||
{
|
||||
IsAnyKeyDown = false;
|
||||
foreach (Key key in KeyValues)
|
||||
{
|
||||
_states[(int)key] = false;
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
|
||||
[SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode")]
|
||||
private int GetAsciiKey(Key key, int platformKeyCode)
|
||||
{
|
||||
var modifiers = System.Windows.Input.Keyboard.Modifiers;
|
||||
bool control = ((modifiers & ModifierKeys.Control) != 0);
|
||||
bool shift = ((modifiers & ModifierKeys.Shift) != 0);
|
||||
bool capsLock = shift ^ _capsLock;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case Key.Left:
|
||||
return 0x08;
|
||||
|
||||
case Key.Tab:
|
||||
return 0x09;
|
||||
|
||||
case Key.Down:
|
||||
return 0x0A;
|
||||
|
||||
case Key.Up:
|
||||
return 0x0B;
|
||||
|
||||
case Key.Enter:
|
||||
return 0x0D;
|
||||
|
||||
case Key.Right:
|
||||
return 0x15;
|
||||
|
||||
case Key.Escape:
|
||||
return 0x1B;
|
||||
|
||||
case Key.Back:
|
||||
return control ? -1 : 0x7F;
|
||||
|
||||
case Key.Space:
|
||||
return ' ';
|
||||
|
||||
case Key.D1:
|
||||
return shift ? '!' : '1';
|
||||
|
||||
case Key.D2:
|
||||
return control ? 0x00 : shift ? '@' : '2';
|
||||
|
||||
case Key.D3:
|
||||
return shift ? '#' : '3';
|
||||
|
||||
case Key.D4:
|
||||
return shift ? '$' : '4';
|
||||
|
||||
case Key.D5:
|
||||
return shift ? '%' : '5';
|
||||
|
||||
case Key.D6:
|
||||
return control ? 0x1E : shift ? '^' : '6';
|
||||
|
||||
case Key.D7:
|
||||
return shift ? '&' : '7';
|
||||
|
||||
case Key.D8:
|
||||
return shift ? '*' : '8';
|
||||
|
||||
case Key.D9:
|
||||
return shift ? '(' : '9';
|
||||
|
||||
case Key.D0:
|
||||
return shift ? ')' : '0';
|
||||
|
||||
case Key.A:
|
||||
return control ? 0x01 : capsLock ? 'A' : 'a';
|
||||
|
||||
case Key.B:
|
||||
return control ? 0x02 : capsLock ? 'B' : 'b';
|
||||
|
||||
case Key.C:
|
||||
return control ? 0x03 : capsLock ? 'C' : 'c';
|
||||
|
||||
case Key.D:
|
||||
return control ? 0x04 : capsLock ? 'D' : 'd';
|
||||
|
||||
case Key.E:
|
||||
return control ? 0x05 : capsLock ? 'E' : 'e';
|
||||
|
||||
case Key.F:
|
||||
return control ? 0x06 : capsLock ? 'F' : 'f';
|
||||
|
||||
case Key.G:
|
||||
return control ? 0x07 : capsLock ? 'G' : 'g';
|
||||
|
||||
case Key.H:
|
||||
return control ? 0x08 : capsLock ? 'H' : 'h';
|
||||
|
||||
case Key.I:
|
||||
return control ? 0x09 : capsLock ? 'I' : 'i';
|
||||
|
||||
case Key.J:
|
||||
return control ? 0x0A : capsLock ? 'J' : 'j';
|
||||
|
||||
case Key.K:
|
||||
return control ? 0x0B : capsLock ? 'K' : 'k';
|
||||
|
||||
case Key.L:
|
||||
return control ? 0x0C : capsLock ? 'L' : 'l';
|
||||
|
||||
case Key.M:
|
||||
return control ? 0x0D : capsLock ? 'M' : 'm';
|
||||
|
||||
case Key.N:
|
||||
return control ? 0x0E : capsLock ? 'N' : 'n';
|
||||
|
||||
case Key.O:
|
||||
return control ? 0x0F : capsLock ? 'O' : 'o';
|
||||
|
||||
case Key.P:
|
||||
return control ? 0x10 : capsLock ? 'P' : 'p';
|
||||
|
||||
case Key.Q:
|
||||
return control ? 0x11 : capsLock ? 'Q' : 'q';
|
||||
|
||||
case Key.R:
|
||||
return control ? 0x12 : capsLock ? 'R' : 'r';
|
||||
|
||||
case Key.S:
|
||||
return control ? 0x13 : capsLock ? 'S' : 's';
|
||||
|
||||
case Key.T:
|
||||
return control ? 0x14 : capsLock ? 'T' : 't';
|
||||
|
||||
case Key.U:
|
||||
return control ? 0x15 : capsLock ? 'U' : 'u';
|
||||
|
||||
case Key.V:
|
||||
return control ? 0x16 : capsLock ? 'V' : 'v';
|
||||
|
||||
case Key.W:
|
||||
return control ? 0x17 : capsLock ? 'W' : 'w';
|
||||
|
||||
case Key.X:
|
||||
return control ? 0x18 : capsLock ? 'X' : 'x';
|
||||
|
||||
case Key.Y:
|
||||
return control ? 0x19 : capsLock ? 'Y' : 'y';
|
||||
|
||||
case Key.Z:
|
||||
return control ? 0x1A : capsLock ? 'Z' : 'z';
|
||||
|
||||
case Key.Unknown:
|
||||
switch (Environment.OSVersion.Platform)
|
||||
{
|
||||
case PlatformID.Win32NT:
|
||||
switch (platformKeyCode)
|
||||
{
|
||||
case 0xBA: // WinForms Keys.Oem1
|
||||
return shift ? ':' : ';';
|
||||
|
||||
case 0xBF: // WinForms Keys.Oem2
|
||||
return shift ? '?' : '/';
|
||||
|
||||
case 0xC0: // WinForms Keys.Oem3
|
||||
return shift ? '~' : '`';
|
||||
|
||||
case 0xDB: // WinForms Keys.Oem4
|
||||
return shift ? '{' : '[';
|
||||
|
||||
case 0xDC: // WinForms Keys.Oem5
|
||||
return control ? 0x1C : shift ? '|' : '\\';
|
||||
|
||||
case 0xDD: // WinForms Keys.Oem6
|
||||
return control ? 0x1D : shift ? '}' : ']';
|
||||
|
||||
case 0xDE: // WinForms Keys.Oem7
|
||||
return shift ? '"' : '\'';
|
||||
|
||||
case 0xBD: // WinForms Keys.OemMinus
|
||||
return control ? 0x1F : shift ? '_' : '-';
|
||||
|
||||
case 0xBB: // WinForms Keys.OemPlus
|
||||
return shift ? '+' : '=';
|
||||
|
||||
case 0xBC: // WinForms Keys.OemComma
|
||||
return shift ? '<' : ',';
|
||||
|
||||
case 0xBE: // WinForms Keys.OemPeriod
|
||||
return shift ? '>' : '.';
|
||||
}
|
||||
break;
|
||||
#if !WINDOWS_PHONE
|
||||
case PlatformID.MacOSX:
|
||||
switch (platformKeyCode)
|
||||
{
|
||||
case 0x29:
|
||||
return shift ? ':' : ';';
|
||||
|
||||
case 0x2C:
|
||||
return shift ? '?' : '/';
|
||||
|
||||
case 0x32:
|
||||
return shift ? '~' : '`';
|
||||
|
||||
case 0x21:
|
||||
return shift ? '{' : '[';
|
||||
|
||||
case 0x2A:
|
||||
return control ? 0x1C : shift ? '|' : '\\';
|
||||
|
||||
case 0x1E:
|
||||
return control ? 0x1D : shift ? '}' : ']';
|
||||
|
||||
case 0x27:
|
||||
return shift ? '"' : '\'';
|
||||
|
||||
case 0x1B:
|
||||
return control ? 0x1F : shift ? '_' : '-';
|
||||
|
||||
case 0x18:
|
||||
return shift ? '+' : '=';
|
||||
|
||||
case 0x2B:
|
||||
return shift ? '<' : ',';
|
||||
|
||||
case 0x2F:
|
||||
return shift ? '>' : '.';
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case PlatformID.Unix:
|
||||
switch (platformKeyCode)
|
||||
{
|
||||
case 0x2F:
|
||||
return shift ? ':' : ';';
|
||||
|
||||
case 0x3D:
|
||||
return shift ? '?' : '/';
|
||||
|
||||
case 0x31:
|
||||
return shift ? '~' : '`';
|
||||
|
||||
case 0x22:
|
||||
return shift ? '{' : '[';
|
||||
|
||||
case 0x33:
|
||||
return control ? 0x1C : shift ? '|' : '\\';
|
||||
|
||||
case 0x23:
|
||||
return control ? 0x1D : shift ? '}' : ']';
|
||||
|
||||
case 0x30:
|
||||
return shift ? '"' : '\'';
|
||||
|
||||
case 0x14:
|
||||
return control ? 0x1F : shift ? '_' : '-';
|
||||
|
||||
case 0x15:
|
||||
return shift ? '+' : '=';
|
||||
|
||||
case 0x3B:
|
||||
return shift ? '<' : ',';
|
||||
|
||||
case 0x3C:
|
||||
return shift ? '>' : '.';
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static readonly Key[] KeyValues =
|
||||
(from key in
|
||||
(from field in typeof(Key).GetFields() // missing Enum.GetValues; use reflection
|
||||
where field.IsLiteral
|
||||
select (Key)field.GetValue(typeof(Key)))
|
||||
where (key != Key.None) // filter Key.None
|
||||
select key).ToArray();
|
||||
|
||||
private static readonly int KeyCount = (int)(KeyValues.Max()) + 1;
|
||||
|
||||
private bool[] _states = new bool[KeyCount];
|
||||
private bool _capsLock;
|
||||
private bool _updateAnyKeyDown;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,100 +1,100 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media.Imaging;
|
||||
#if WINDOWS_PHONE
|
||||
using Microsoft.Phone.Controls;
|
||||
#endif
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class SilverlightVideoService : VideoService
|
||||
{
|
||||
public SilverlightVideoService(Machine machine, UserControl page, Image image) :
|
||||
base(machine)
|
||||
{
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException("page");
|
||||
}
|
||||
if (image == null)
|
||||
{
|
||||
throw new ArgumentNullException("image");
|
||||
}
|
||||
|
||||
_page = page;
|
||||
_image = image;
|
||||
_image.Source = _bitmap;
|
||||
|
||||
#if !WINDOWS_PHONE
|
||||
_page.LayoutUpdated += (sender, e) => SetWindowSizeToContent();
|
||||
#else
|
||||
((PhoneApplicationPage)_page).OrientationChanged += (sender, e) => SetImageSize(swapOrientation: (e.Orientation & PageOrientation.Landscape) != 0);
|
||||
#endif
|
||||
_page.SizeChanged += (sender, e) => SetImageSize();
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow")]
|
||||
public override void SetPixel(int x, int y, uint color)
|
||||
{
|
||||
_pixels[y * BitmapWidth + x] = (int)color;
|
||||
_pixelsDirty = true;
|
||||
}
|
||||
|
||||
public override void Update() // main thread
|
||||
{
|
||||
#if !WINDOWS_PHONE
|
||||
var content = Application.Current.Host.Content;
|
||||
if (Application.Current.IsRunningOutOfBrowser && (content.IsFullScreen != IsFullScreen))
|
||||
{
|
||||
Application.Current.RootVisual.Dispatcher.BeginInvoke(() => content.IsFullScreen = IsFullScreen); // queue to dispatcher; avoids crash!
|
||||
}
|
||||
#endif
|
||||
if (_pixelsDirty)
|
||||
{
|
||||
_pixelsDirty = false;
|
||||
for (int i = 0; i < BitmapWidth * BitmapHeight; i++)
|
||||
{
|
||||
_bitmap.Pixels[i] = _pixels[i];
|
||||
}
|
||||
_bitmap.Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetImageSize(bool swapOrientation = false)
|
||||
{
|
||||
int uniformScale = Math.Max(1, swapOrientation ? Math.Min((int)_page.RenderSize.Height / BitmapWidth, (int)_page.RenderSize.Width / BitmapHeight) :
|
||||
Math.Min((int)_page.RenderSize.Width / BitmapWidth, (int)_page.RenderSize.Height / BitmapHeight));
|
||||
_image.Width = uniformScale * BitmapWidth;
|
||||
_image.Height = uniformScale * BitmapHeight;
|
||||
Machine.Video.DirtyScreen();
|
||||
}
|
||||
|
||||
#if !WINDOWS_PHONE
|
||||
private void SetWindowSizeToContent()
|
||||
{
|
||||
if (Application.Current.IsRunningOutOfBrowser && !_sizedToContent)
|
||||
{
|
||||
_sizedToContent = true;
|
||||
var window = Application.Current.MainWindow;
|
||||
var size = Application.Current.RootVisual.DesiredSize;
|
||||
window.Width = size.Width;
|
||||
window.Height = size.Height;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private const int BitmapWidth = 560;
|
||||
private const int BitmapHeight = 384;
|
||||
|
||||
private UserControl _page;
|
||||
private Image _image;
|
||||
private WriteableBitmap _bitmap = new WriteableBitmap(BitmapWidth, BitmapHeight);
|
||||
private int[] _pixels = new int[BitmapWidth * BitmapHeight];
|
||||
private bool _pixelsDirty;
|
||||
#if !WINDOWS_PHONE
|
||||
private bool _sizedToContent;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media.Imaging;
|
||||
#if WINDOWS_PHONE
|
||||
using Microsoft.Phone.Controls;
|
||||
#endif
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class SilverlightVideoService : VideoService
|
||||
{
|
||||
public SilverlightVideoService(Machine machine, UserControl page, Image image) :
|
||||
base(machine)
|
||||
{
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException("page");
|
||||
}
|
||||
if (image == null)
|
||||
{
|
||||
throw new ArgumentNullException("image");
|
||||
}
|
||||
|
||||
_page = page;
|
||||
_image = image;
|
||||
_image.Source = _bitmap;
|
||||
|
||||
#if !WINDOWS_PHONE
|
||||
_page.LayoutUpdated += (sender, e) => SetWindowSizeToContent();
|
||||
#else
|
||||
((PhoneApplicationPage)_page).OrientationChanged += (sender, e) => SetImageSize(swapOrientation: (e.Orientation & PageOrientation.Landscape) != 0);
|
||||
#endif
|
||||
_page.SizeChanged += (sender, e) => SetImageSize();
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow")]
|
||||
public override void SetPixel(int x, int y, uint color)
|
||||
{
|
||||
_pixels[y * BitmapWidth + x] = (int)color;
|
||||
_pixelsDirty = true;
|
||||
}
|
||||
|
||||
public override void Update() // main thread
|
||||
{
|
||||
#if !WINDOWS_PHONE
|
||||
var content = Application.Current.Host.Content;
|
||||
if (Application.Current.IsRunningOutOfBrowser && (content.IsFullScreen != IsFullScreen))
|
||||
{
|
||||
Application.Current.RootVisual.Dispatcher.BeginInvoke(() => content.IsFullScreen = IsFullScreen); // queue to dispatcher; avoids crash!
|
||||
}
|
||||
#endif
|
||||
if (_pixelsDirty)
|
||||
{
|
||||
_pixelsDirty = false;
|
||||
for (int i = 0; i < BitmapWidth * BitmapHeight; i++)
|
||||
{
|
||||
_bitmap.Pixels[i] = _pixels[i];
|
||||
}
|
||||
_bitmap.Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetImageSize(bool swapOrientation = false)
|
||||
{
|
||||
int uniformScale = Math.Max(1, swapOrientation ? Math.Min((int)_page.RenderSize.Height / BitmapWidth, (int)_page.RenderSize.Width / BitmapHeight) :
|
||||
Math.Min((int)_page.RenderSize.Width / BitmapWidth, (int)_page.RenderSize.Height / BitmapHeight));
|
||||
_image.Width = uniformScale * BitmapWidth;
|
||||
_image.Height = uniformScale * BitmapHeight;
|
||||
Machine.Video.DirtyScreen();
|
||||
}
|
||||
|
||||
#if !WINDOWS_PHONE
|
||||
private void SetWindowSizeToContent()
|
||||
{
|
||||
if (Application.Current.IsRunningOutOfBrowser && !_sizedToContent)
|
||||
{
|
||||
_sizedToContent = true;
|
||||
var window = Application.Current.MainWindow;
|
||||
var size = Application.Current.RootVisual.DesiredSize;
|
||||
window.Width = size.Width;
|
||||
window.Height = size.Height;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private const int BitmapWidth = 560;
|
||||
private const int BitmapHeight = 384;
|
||||
|
||||
private UserControl _page;
|
||||
private Image _image;
|
||||
private WriteableBitmap _bitmap = new WriteableBitmap(BitmapWidth, BitmapHeight);
|
||||
private int[] _pixels = new int[BitmapWidth * BitmapHeight];
|
||||
private bool _pixelsDirty;
|
||||
#if !WINDOWS_PHONE
|
||||
private bool _sizedToContent;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
146
Virtu/Speaker.cs
146
Virtu/Speaker.cs
|
@ -1,73 +1,73 @@
|
|||
using System;
|
||||
using Jellyfish.Virtu.Services;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class Speaker : MachineComponent
|
||||
{
|
||||
public Speaker(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
_flushOutputEvent = FlushOutputEvent; // cache delegates; avoids garbage
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
_audioService = Machine.Services.GetService<AudioService>();
|
||||
|
||||
UpdateSettings();
|
||||
Machine.Video.VSync += (sender, e) => UpdateSettings();
|
||||
|
||||
Machine.Events.AddEvent(CyclesPerFlush * Machine.Settings.Cpu.Multiplier, _flushOutputEvent);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_audioService.Reset();
|
||||
_isHigh = false;
|
||||
_highCycles = _totalCycles = 0;
|
||||
}
|
||||
|
||||
public void ToggleOutput()
|
||||
{
|
||||
UpdateCycles();
|
||||
_isHigh ^= true;
|
||||
}
|
||||
|
||||
private void FlushOutputEvent()
|
||||
{
|
||||
UpdateCycles();
|
||||
_audioService.Output(_highCycles * short.MaxValue / _totalCycles); // quick and dirty decimation
|
||||
_highCycles = _totalCycles = 0;
|
||||
|
||||
Machine.Events.AddEvent(CyclesPerFlush * Machine.Settings.Cpu.Multiplier, _flushOutputEvent);
|
||||
}
|
||||
|
||||
private void UpdateCycles()
|
||||
{
|
||||
int delta = (int)(Machine.Cpu.Cycles - _lastCycles);
|
||||
if (_isHigh)
|
||||
{
|
||||
_highCycles += delta;
|
||||
}
|
||||
_totalCycles += delta;
|
||||
_lastCycles = Machine.Cpu.Cycles;
|
||||
}
|
||||
|
||||
private void UpdateSettings()
|
||||
{
|
||||
_audioService.SetVolume(Machine.Settings.Audio.Volume);
|
||||
}
|
||||
|
||||
private const int CyclesPerFlush = 23;
|
||||
|
||||
private Action _flushOutputEvent;
|
||||
|
||||
private bool _isHigh;
|
||||
private int _highCycles;
|
||||
private int _totalCycles;
|
||||
private long _lastCycles;
|
||||
|
||||
private AudioService _audioService;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using Jellyfish.Virtu.Services;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class Speaker : MachineComponent
|
||||
{
|
||||
public Speaker(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
_flushOutputEvent = FlushOutputEvent; // cache delegates; avoids garbage
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
_audioService = Machine.Services.GetService<AudioService>();
|
||||
|
||||
UpdateSettings();
|
||||
Machine.Video.VSync += (sender, e) => UpdateSettings();
|
||||
|
||||
Machine.Events.AddEvent(CyclesPerFlush * Machine.Settings.Cpu.Multiplier, _flushOutputEvent);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_audioService.Reset();
|
||||
_isHigh = false;
|
||||
_highCycles = _totalCycles = 0;
|
||||
}
|
||||
|
||||
public void ToggleOutput()
|
||||
{
|
||||
UpdateCycles();
|
||||
_isHigh ^= true;
|
||||
}
|
||||
|
||||
private void FlushOutputEvent()
|
||||
{
|
||||
UpdateCycles();
|
||||
_audioService.Output(_highCycles * short.MaxValue / _totalCycles); // quick and dirty decimation
|
||||
_highCycles = _totalCycles = 0;
|
||||
|
||||
Machine.Events.AddEvent(CyclesPerFlush * Machine.Settings.Cpu.Multiplier, _flushOutputEvent);
|
||||
}
|
||||
|
||||
private void UpdateCycles()
|
||||
{
|
||||
int delta = (int)(Machine.Cpu.Cycles - _lastCycles);
|
||||
if (_isHigh)
|
||||
{
|
||||
_highCycles += delta;
|
||||
}
|
||||
_totalCycles += delta;
|
||||
_lastCycles = Machine.Cpu.Cycles;
|
||||
}
|
||||
|
||||
private void UpdateSettings()
|
||||
{
|
||||
_audioService.SetVolume(Machine.Settings.Audio.Volume);
|
||||
}
|
||||
|
||||
private const int CyclesPerFlush = 23;
|
||||
|
||||
private Action _flushOutputEvent;
|
||||
|
||||
private bool _isHigh;
|
||||
private int _highCycles;
|
||||
private int _totalCycles;
|
||||
private long _lastCycles;
|
||||
|
||||
private AudioService _audioService;
|
||||
}
|
||||
}
|
||||
|
|
2054
Virtu/Video.cs
2054
Virtu/Video.cs
File diff suppressed because it is too large
Load Diff
3288
Virtu/VideoData.cs
3288
Virtu/VideoData.cs
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +1,8 @@
|
|||
<jl:ApplicationBase x:Class="Jellyfish.Virtu.MainApp"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:jl="clr-namespace:Jellyfish.Library;assembly=Jellyfish.Library"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
</Application.Resources>
|
||||
</jl:ApplicationBase>
|
||||
<jl:ApplicationBase x:Class="Jellyfish.Virtu.MainApp"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:jl="clr-namespace:Jellyfish.Library;assembly=Jellyfish.Library"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
</Application.Resources>
|
||||
</jl:ApplicationBase>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
using System.Security.Permissions;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed partial class MainApp : ApplicationBase
|
||||
{
|
||||
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
|
||||
public MainApp() :
|
||||
base("Virtu")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Security.Permissions;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed partial class MainApp : ApplicationBase
|
||||
{
|
||||
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
|
||||
public MainApp() :
|
||||
base("Virtu")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
<UserControl x:Class="Jellyfish.Virtu.MainPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:jl="clr-namespace:Jellyfish.Library;assembly=Jellyfish.Library"
|
||||
Focusable="True">
|
||||
<Grid Background="Black">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<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" />
|
||||
</StackPanel>
|
||||
<jl:FrameRateCounter Margin="0,0,4,0" HorizontalAlignment="Right" VerticalAlignment="Center" />
|
||||
<Grid Grid.Row="1">
|
||||
<Image x:Name="_image" MinWidth="560" MinHeight="384" RenderOptions.BitmapScalingMode="NearestNeighbor" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
<ScrollViewer x:Name="_debugScrollViewer" BorderThickness="0" Focusable="False" IsTabStop="False" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<TextBlock x:Name="_debugText" FontFamily="Consolas" FontSize="12" Foreground="White" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
<UserControl x:Class="Jellyfish.Virtu.MainPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:jl="clr-namespace:Jellyfish.Library;assembly=Jellyfish.Library"
|
||||
Focusable="True">
|
||||
<Grid Background="Black">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<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" />
|
||||
</StackPanel>
|
||||
<jl:FrameRateCounter Margin="0,0,4,0" HorizontalAlignment="Right" VerticalAlignment="Center" />
|
||||
<Grid Grid.Row="1">
|
||||
<Image x:Name="_image" MinWidth="560" MinHeight="384" RenderOptions.BitmapScalingMode="NearestNeighbor" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
<ScrollViewer x:Name="_debugScrollViewer" BorderThickness="0" Focusable="False" IsTabStop="False" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<TextBlock x:Name="_debugText" FontFamily="Consolas" FontSize="12" Foreground="White" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
|
|
@ -1,106 +1,106 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using Jellyfish.Virtu.Services;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed partial class MainPage : UserControl, IDisposable
|
||||
{
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (!DesignerProperties.GetIsInDesignMode(this))
|
||||
{
|
||||
_debugService = new WpfDebugService(_machine, this);
|
||||
_storageService = new WpfStorageService(_machine);
|
||||
_keyboardService = new WpfKeyboardService(_machine, this);
|
||||
_gamePortService = new GamePortService(_machine); // not connected
|
||||
_audioService = new WpfAudioService(_machine, this);
|
||||
_videoService = new WpfVideoService(_machine, this, _image);
|
||||
|
||||
_machine.Services.AddService(typeof(DebugService), _debugService);
|
||||
_machine.Services.AddService(typeof(StorageService), _storageService);
|
||||
_machine.Services.AddService(typeof(KeyboardService), _keyboardService);
|
||||
_machine.Services.AddService(typeof(GamePortService), _gamePortService);
|
||||
_machine.Services.AddService(typeof(AudioService), _audioService);
|
||||
_machine.Services.AddService(typeof(VideoService), _videoService);
|
||||
|
||||
Loaded += (sender, e) => _machine.Start();
|
||||
CompositionTarget.Rendering += OnCompositionTargetRendering;
|
||||
Application.Current.Exit += (sender, e) => _machine.Stop();
|
||||
|
||||
_disk1Button.Click += (sender, e) => OnDiskButtonClick(0);
|
||||
_disk2Button.Click += (sender, e) => OnDiskButtonClick(1);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_machine.Dispose();
|
||||
_debugService.Dispose();
|
||||
_storageService.Dispose();
|
||||
_keyboardService.Dispose();
|
||||
_gamePortService.Dispose();
|
||||
_audioService.Dispose();
|
||||
_videoService.Dispose();
|
||||
}
|
||||
|
||||
public void WriteLine(string message)
|
||||
{
|
||||
_debugText.Text += message;
|
||||
_debugScrollViewer.UpdateLayout();
|
||||
_debugScrollViewer.ScrollToVerticalOffset(double.MaxValue);
|
||||
}
|
||||
|
||||
private void OnCompositionTargetRendering(object sender, EventArgs e)
|
||||
{
|
||||
_keyboardService.Update();
|
||||
_gamePortService.Update();
|
||||
_videoService.Update();
|
||||
}
|
||||
|
||||
private void OnDiskButtonClick(int drive)
|
||||
{
|
||||
var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" };
|
||||
|
||||
bool? result = dialog.ShowDialog();
|
||||
if (result.HasValue && result.Value)
|
||||
{
|
||||
using (var stream = File.OpenRead(dialog.FileName))
|
||||
{
|
||||
_machine.Pause();
|
||||
var diskII = _machine.FindDiskIIController();
|
||||
if (diskII != null)
|
||||
{
|
||||
diskII.Drives[drive].InsertDisk(dialog.FileName, stream, false);
|
||||
var settings = _machine.Settings.DiskII;
|
||||
if (drive == 0)
|
||||
{
|
||||
settings.Disk1.Name = dialog.FileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.Disk2.Name = dialog.FileName;
|
||||
}
|
||||
}
|
||||
_machine.Unpause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Machine _machine = new Machine();
|
||||
|
||||
private DebugService _debugService;
|
||||
private StorageService _storageService;
|
||||
private KeyboardService _keyboardService;
|
||||
private GamePortService _gamePortService;
|
||||
private AudioService _audioService;
|
||||
private VideoService _videoService;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using Jellyfish.Virtu.Services;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed partial class MainPage : UserControl, IDisposable
|
||||
{
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (!DesignerProperties.GetIsInDesignMode(this))
|
||||
{
|
||||
_debugService = new WpfDebugService(_machine, this);
|
||||
_storageService = new WpfStorageService(_machine);
|
||||
_keyboardService = new WpfKeyboardService(_machine, this);
|
||||
_gamePortService = new GamePortService(_machine); // not connected
|
||||
_audioService = new WpfAudioService(_machine, this);
|
||||
_videoService = new WpfVideoService(_machine, this, _image);
|
||||
|
||||
_machine.Services.AddService(typeof(DebugService), _debugService);
|
||||
_machine.Services.AddService(typeof(StorageService), _storageService);
|
||||
_machine.Services.AddService(typeof(KeyboardService), _keyboardService);
|
||||
_machine.Services.AddService(typeof(GamePortService), _gamePortService);
|
||||
_machine.Services.AddService(typeof(AudioService), _audioService);
|
||||
_machine.Services.AddService(typeof(VideoService), _videoService);
|
||||
|
||||
Loaded += (sender, e) => _machine.Start();
|
||||
CompositionTarget.Rendering += OnCompositionTargetRendering;
|
||||
Application.Current.Exit += (sender, e) => _machine.Stop();
|
||||
|
||||
_disk1Button.Click += (sender, e) => OnDiskButtonClick(0);
|
||||
_disk2Button.Click += (sender, e) => OnDiskButtonClick(1);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_machine.Dispose();
|
||||
_debugService.Dispose();
|
||||
_storageService.Dispose();
|
||||
_keyboardService.Dispose();
|
||||
_gamePortService.Dispose();
|
||||
_audioService.Dispose();
|
||||
_videoService.Dispose();
|
||||
}
|
||||
|
||||
public void WriteLine(string message)
|
||||
{
|
||||
_debugText.Text += message;
|
||||
_debugScrollViewer.UpdateLayout();
|
||||
_debugScrollViewer.ScrollToVerticalOffset(double.MaxValue);
|
||||
}
|
||||
|
||||
private void OnCompositionTargetRendering(object sender, EventArgs e)
|
||||
{
|
||||
_keyboardService.Update();
|
||||
_gamePortService.Update();
|
||||
_videoService.Update();
|
||||
}
|
||||
|
||||
private void OnDiskButtonClick(int drive)
|
||||
{
|
||||
var dialog = new OpenFileDialog() { Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*" };
|
||||
|
||||
bool? result = dialog.ShowDialog();
|
||||
if (result.HasValue && result.Value)
|
||||
{
|
||||
using (var stream = File.OpenRead(dialog.FileName))
|
||||
{
|
||||
_machine.Pause();
|
||||
var diskII = _machine.FindDiskIIController();
|
||||
if (diskII != null)
|
||||
{
|
||||
diskII.Drives[drive].InsertDisk(dialog.FileName, stream, false);
|
||||
var settings = _machine.Settings.DiskII;
|
||||
if (drive == 0)
|
||||
{
|
||||
settings.Disk1.Name = dialog.FileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.Disk2.Name = dialog.FileName;
|
||||
}
|
||||
}
|
||||
_machine.Unpause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Machine _machine = new Machine();
|
||||
|
||||
private DebugService _debugService;
|
||||
private StorageService _storageService;
|
||||
private KeyboardService _keyboardService;
|
||||
private GamePortService _gamePortService;
|
||||
private AudioService _audioService;
|
||||
private VideoService _videoService;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<Window x:Class="Jellyfish.Virtu.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:jv="clr-namespace:Jellyfish.Virtu"
|
||||
Title="Virtu" WindowStartupLocation="CenterScreen" FocusManager.FocusedElement="{Binding ElementName=_mainPage}">
|
||||
<jv:MainPage x:Name="_mainPage" />
|
||||
</Window>
|
||||
<Window x:Class="Jellyfish.Virtu.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:jv="clr-namespace:Jellyfish.Virtu"
|
||||
Title="Virtu" WindowStartupLocation="CenterScreen" FocusManager.FocusedElement="{Binding ElementName=_mainPage}">
|
||||
<jv:MainPage x:Name="_mainPage" />
|
||||
</Window>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
using System.Windows;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Windows;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using Jellyfish.Library;
|
||||
|
||||
[assembly: AssemblyTitle("Virtu")]
|
||||
[assembly: AssemblyDescription("Apple IIe Emulator")]
|
||||
[assembly: AssemblyProduct("Jellyfish.Virtu.Wpf")]
|
||||
[assembly: AssemblyCompany("Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")]
|
||||
|
||||
[assembly: AssemblyVersion("0.8.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.8.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.8.3.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("89a50370-1ed9-4cf1-ad08-043b6e6f3c90")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
|
||||
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using Jellyfish.Library;
|
||||
|
||||
[assembly: AssemblyTitle("Virtu")]
|
||||
[assembly: AssemblyDescription("Apple IIe Emulator")]
|
||||
[assembly: AssemblyProduct("Jellyfish.Virtu.Wpf")]
|
||||
[assembly: AssemblyCompany("Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")]
|
||||
|
||||
[assembly: AssemblyVersion("0.8.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.8.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.8.3.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("89a50370-1ed9-4cf1-ad08-043b6e6f3c90")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
|
||||
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
|
||||
|
|
|
@ -1,59 +1,59 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class WpfAudioService : AudioService
|
||||
{
|
||||
[SecurityCritical]
|
||||
public WpfAudioService(Machine machine, UserControl page) :
|
||||
base(machine)
|
||||
{
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException("page");
|
||||
}
|
||||
|
||||
_directSound = new DirectSound(SampleRate, SampleChannels, SampleBits, SampleSize, OnDirectSoundUpdate);
|
||||
|
||||
page.Loaded += (sender, e) =>
|
||||
{
|
||||
var window = Window.GetWindow(page);
|
||||
_directSound.Start(window.GetHandle());
|
||||
window.Closed += (_sender, _e) => _directSound.Stop();
|
||||
};
|
||||
}
|
||||
|
||||
public override void SetVolume(double volume) // machine thread
|
||||
{
|
||||
_directSound.SetVolume(volume);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_directSound.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void OnDirectSoundUpdate(IntPtr buffer, int bufferSize) // audio thread
|
||||
{
|
||||
//if (_count++ % (1000 / SampleLatency) == 0)
|
||||
//{
|
||||
// DebugService.WriteLine("OnDirectSoundUpdate");
|
||||
//}
|
||||
|
||||
Update(bufferSize, (source, count) => Marshal.Copy(source, 0, buffer, count));
|
||||
}
|
||||
|
||||
private DirectSound _directSound;
|
||||
//private int _count;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class WpfAudioService : AudioService
|
||||
{
|
||||
[SecurityCritical]
|
||||
public WpfAudioService(Machine machine, UserControl page) :
|
||||
base(machine)
|
||||
{
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException("page");
|
||||
}
|
||||
|
||||
_directSound = new DirectSound(SampleRate, SampleChannels, SampleBits, SampleSize, OnDirectSoundUpdate);
|
||||
|
||||
page.Loaded += (sender, e) =>
|
||||
{
|
||||
var window = Window.GetWindow(page);
|
||||
_directSound.Start(window.GetHandle());
|
||||
window.Closed += (_sender, _e) => _directSound.Stop();
|
||||
};
|
||||
}
|
||||
|
||||
public override void SetVolume(double volume) // machine thread
|
||||
{
|
||||
_directSound.SetVolume(volume);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_directSound.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void OnDirectSoundUpdate(IntPtr buffer, int bufferSize) // audio thread
|
||||
{
|
||||
//if (_count++ % (1000 / SampleLatency) == 0)
|
||||
//{
|
||||
// DebugService.WriteLine("OnDirectSoundUpdate");
|
||||
//}
|
||||
|
||||
Update(bufferSize, (source, count) => Marshal.Copy(source, 0, buffer, count));
|
||||
}
|
||||
|
||||
private DirectSound _directSound;
|
||||
//private int _count;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
using System;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class WpfDebugService : DebugService
|
||||
{
|
||||
public WpfDebugService(Machine machine, MainPage page) :
|
||||
base(machine)
|
||||
{
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException("page");
|
||||
}
|
||||
|
||||
_page = page;
|
||||
}
|
||||
|
||||
protected override void OnWriteLine(string message)
|
||||
{
|
||||
_page.Dispatcher.CheckInvoke(() => _page.WriteLine(message + Environment.NewLine));
|
||||
}
|
||||
|
||||
private MainPage _page;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class WpfDebugService : DebugService
|
||||
{
|
||||
public WpfDebugService(Machine machine, MainPage page) :
|
||||
base(machine)
|
||||
{
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException("page");
|
||||
}
|
||||
|
||||
_page = page;
|
||||
}
|
||||
|
||||
protected override void OnWriteLine(string message)
|
||||
{
|
||||
_page.Dispatcher.CheckInvoke(() => _page.WriteLine(message + Environment.NewLine));
|
||||
}
|
||||
|
||||
private MainPage _page;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,297 +1,297 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class WpfKeyboardService : KeyboardService
|
||||
{
|
||||
public WpfKeyboardService(Machine machine, UserControl page) :
|
||||
base(machine)
|
||||
{
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException("page");
|
||||
}
|
||||
|
||||
page.KeyDown += OnPageKeyDown;
|
||||
page.KeyUp += OnPageKeyUp;
|
||||
page.GotKeyboardFocus += (sender, e) => _updateAnyKeyDown = true;
|
||||
}
|
||||
|
||||
public override bool IsKeyDown(int key)
|
||||
{
|
||||
return IsKeyDown((Key)key);
|
||||
}
|
||||
|
||||
public override void Update() // main thread
|
||||
{
|
||||
var keyboard = System.Windows.Input.Keyboard.PrimaryDevice;
|
||||
if (_updateAnyKeyDown)
|
||||
{
|
||||
_updateAnyKeyDown = false;
|
||||
IsAnyKeyDown = false;
|
||||
foreach (Key key in KeyValues)
|
||||
{
|
||||
bool isKeyDown = keyboard.IsKeyDown(key);
|
||||
_states[(int)key] = isKeyDown;
|
||||
if (isKeyDown)
|
||||
{
|
||||
IsAnyKeyDown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IsControlKeyDown = ((keyboard.Modifiers & ModifierKeys.Control) != 0);
|
||||
IsShiftKeyDown = ((keyboard.Modifiers & ModifierKeys.Shift) != 0);
|
||||
|
||||
IsOpenAppleKeyDown = keyboard.IsKeyDown(Key.LeftAlt) || IsKeyDown(Key.NumPad0);
|
||||
IsCloseAppleKeyDown = keyboard.IsKeyDown(Key.RightAlt) || IsKeyDown(Key.Decimal);
|
||||
IsResetKeyDown = IsControlKeyDown && keyboard.IsKeyDown(Key.Back);
|
||||
|
||||
base.Update();
|
||||
}
|
||||
|
||||
private bool IsKeyDown(Key key)
|
||||
{
|
||||
return _states[(int)key];
|
||||
}
|
||||
|
||||
private void OnPageKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
//DebugService.WriteLine(string.Concat("OnPageKeyDn: Key=", e.Key));
|
||||
|
||||
_states[(int)((e.Key == Key.System) ? e.SystemKey : e.Key)] = true;
|
||||
_updateAnyKeyDown = false;
|
||||
IsAnyKeyDown = true;
|
||||
|
||||
int asciiKey = GetAsciiKey(e.Key, e.KeyboardDevice);
|
||||
if (asciiKey >= 0)
|
||||
{
|
||||
Machine.Keyboard.Latch = asciiKey;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
private void OnPageKeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
//DebugService.WriteLine(string.Concat("OnPageKeyUp: Key=", e.Key));
|
||||
|
||||
_states[(int)((e.Key == Key.System) ? e.SystemKey : e.Key)] = false;
|
||||
_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", "CA1505:AvoidUnmaintainableCode")]
|
||||
private static int GetAsciiKey(Key key, KeyboardDevice keyboard)
|
||||
{
|
||||
bool control = ((keyboard.Modifiers & ModifierKeys.Control) != 0);
|
||||
bool shift = ((keyboard.Modifiers & ModifierKeys.Shift) != 0);
|
||||
bool capsLock = shift ^ keyboard.IsKeyToggled(Key.CapsLock);
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case Key.Left:
|
||||
return 0x08;
|
||||
|
||||
case Key.Tab:
|
||||
return 0x09;
|
||||
|
||||
case Key.Down:
|
||||
return 0x0A;
|
||||
|
||||
case Key.Up:
|
||||
return 0x0B;
|
||||
|
||||
case Key.Enter:
|
||||
return 0x0D;
|
||||
|
||||
case Key.Right:
|
||||
return 0x15;
|
||||
|
||||
case Key.Escape:
|
||||
return 0x1B;
|
||||
|
||||
case Key.Back:
|
||||
return control ? -1 : 0x7F;
|
||||
|
||||
case Key.Space:
|
||||
return ' ';
|
||||
|
||||
case Key.D1:
|
||||
return shift ? '!' : '1';
|
||||
|
||||
case Key.D2:
|
||||
return control ? 0x00 : shift ? '@' : '2';
|
||||
|
||||
case Key.D3:
|
||||
return shift ? '#' : '3';
|
||||
|
||||
case Key.D4:
|
||||
return shift ? '$' : '4';
|
||||
|
||||
case Key.D5:
|
||||
return shift ? '%' : '5';
|
||||
|
||||
case Key.D6:
|
||||
return control ? 0x1E : shift ? '^' : '6';
|
||||
|
||||
case Key.D7:
|
||||
return shift ? '&' : '7';
|
||||
|
||||
case Key.D8:
|
||||
return shift ? '*' : '8';
|
||||
|
||||
case Key.D9:
|
||||
return shift ? '(' : '9';
|
||||
|
||||
case Key.D0:
|
||||
return shift ? ')' : '0';
|
||||
|
||||
case Key.A:
|
||||
return control ? 0x01 : capsLock ? 'A' : 'a';
|
||||
|
||||
case Key.B:
|
||||
return control ? 0x02 : capsLock ? 'B' : 'b';
|
||||
|
||||
case Key.C:
|
||||
return control ? 0x03 : capsLock ? 'C' : 'c';
|
||||
|
||||
case Key.D:
|
||||
return control ? 0x04 : capsLock ? 'D' : 'd';
|
||||
|
||||
case Key.E:
|
||||
return control ? 0x05 : capsLock ? 'E' : 'e';
|
||||
|
||||
case Key.F:
|
||||
return control ? 0x06 : capsLock ? 'F' : 'f';
|
||||
|
||||
case Key.G:
|
||||
return control ? 0x07 : capsLock ? 'G' : 'g';
|
||||
|
||||
case Key.H:
|
||||
return control ? 0x08 : capsLock ? 'H' : 'h';
|
||||
|
||||
case Key.I:
|
||||
return control ? 0x09 : capsLock ? 'I' : 'i';
|
||||
|
||||
case Key.J:
|
||||
return control ? 0x0A : capsLock ? 'J' : 'j';
|
||||
|
||||
case Key.K:
|
||||
return control ? 0x0B : capsLock ? 'K' : 'k';
|
||||
|
||||
case Key.L:
|
||||
return control ? 0x0C : capsLock ? 'L' : 'l';
|
||||
|
||||
case Key.M:
|
||||
return control ? 0x0D : capsLock ? 'M' : 'm';
|
||||
|
||||
case Key.N:
|
||||
return control ? 0x0E : capsLock ? 'N' : 'n';
|
||||
|
||||
case Key.O:
|
||||
return control ? 0x0F : capsLock ? 'O' : 'o';
|
||||
|
||||
case Key.P:
|
||||
return control ? 0x10 : capsLock ? 'P' : 'p';
|
||||
|
||||
case Key.Q:
|
||||
return control ? 0x11 : capsLock ? 'Q' : 'q';
|
||||
|
||||
case Key.R:
|
||||
return control ? 0x12 : capsLock ? 'R' : 'r';
|
||||
|
||||
case Key.S:
|
||||
return control ? 0x13 : capsLock ? 'S' : 's';
|
||||
|
||||
case Key.T:
|
||||
return control ? 0x14 : capsLock ? 'T' : 't';
|
||||
|
||||
case Key.U:
|
||||
return control ? 0x15 : capsLock ? 'U' : 'u';
|
||||
|
||||
case Key.V:
|
||||
return control ? 0x16 : capsLock ? 'V' : 'v';
|
||||
|
||||
case Key.W:
|
||||
return control ? 0x17 : capsLock ? 'W' : 'w';
|
||||
|
||||
case Key.X:
|
||||
return control ? 0x18 : capsLock ? 'X' : 'x';
|
||||
|
||||
case Key.Y:
|
||||
return control ? 0x19 : capsLock ? 'Y' : 'y';
|
||||
|
||||
case Key.Z:
|
||||
return control ? 0x1A : capsLock ? 'Z' : 'z';
|
||||
|
||||
case Key.Oem1:
|
||||
return shift ? ':' : ';';
|
||||
|
||||
case Key.Oem2:
|
||||
return shift ? '?' : '/';
|
||||
|
||||
case Key.Oem3:
|
||||
return shift ? '~' : '`';
|
||||
|
||||
case Key.Oem4:
|
||||
return shift ? '{' : '[';
|
||||
|
||||
case Key.Oem5:
|
||||
return control ? 0x1C : shift ? '|' : '\\';
|
||||
|
||||
case Key.Oem6:
|
||||
return control ? 0x1D : shift ? '}' : ']';
|
||||
|
||||
case Key.Oem7:
|
||||
return shift ? '"' : '\'';
|
||||
|
||||
case Key.OemMinus:
|
||||
return control ? 0x1F : shift ? '_' : '-';
|
||||
|
||||
case Key.OemPlus:
|
||||
return shift ? '+' : '=';
|
||||
|
||||
case Key.OemComma:
|
||||
return shift ? '<' : ',';
|
||||
|
||||
case Key.OemPeriod:
|
||||
return shift ? '>' : '.';
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static readonly Key[] KeyValues =
|
||||
(from key in (Key[])Enum.GetValues(typeof(Key))
|
||||
where (key != Key.None) // filter Key.None; avoids validation exception
|
||||
select key).ToArray();
|
||||
|
||||
private static readonly int KeyCount = (int)(KeyValues.Max()) + 1;
|
||||
|
||||
private bool[] _states = new bool[KeyCount];
|
||||
private bool _updateAnyKeyDown;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class WpfKeyboardService : KeyboardService
|
||||
{
|
||||
public WpfKeyboardService(Machine machine, UserControl page) :
|
||||
base(machine)
|
||||
{
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException("page");
|
||||
}
|
||||
|
||||
page.KeyDown += OnPageKeyDown;
|
||||
page.KeyUp += OnPageKeyUp;
|
||||
page.GotKeyboardFocus += (sender, e) => _updateAnyKeyDown = true;
|
||||
}
|
||||
|
||||
public override bool IsKeyDown(int key)
|
||||
{
|
||||
return IsKeyDown((Key)key);
|
||||
}
|
||||
|
||||
public override void Update() // main thread
|
||||
{
|
||||
var keyboard = System.Windows.Input.Keyboard.PrimaryDevice;
|
||||
if (_updateAnyKeyDown)
|
||||
{
|
||||
_updateAnyKeyDown = false;
|
||||
IsAnyKeyDown = false;
|
||||
foreach (Key key in KeyValues)
|
||||
{
|
||||
bool isKeyDown = keyboard.IsKeyDown(key);
|
||||
_states[(int)key] = isKeyDown;
|
||||
if (isKeyDown)
|
||||
{
|
||||
IsAnyKeyDown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IsControlKeyDown = ((keyboard.Modifiers & ModifierKeys.Control) != 0);
|
||||
IsShiftKeyDown = ((keyboard.Modifiers & ModifierKeys.Shift) != 0);
|
||||
|
||||
IsOpenAppleKeyDown = keyboard.IsKeyDown(Key.LeftAlt) || IsKeyDown(Key.NumPad0);
|
||||
IsCloseAppleKeyDown = keyboard.IsKeyDown(Key.RightAlt) || IsKeyDown(Key.Decimal);
|
||||
IsResetKeyDown = IsControlKeyDown && keyboard.IsKeyDown(Key.Back);
|
||||
|
||||
base.Update();
|
||||
}
|
||||
|
||||
private bool IsKeyDown(Key key)
|
||||
{
|
||||
return _states[(int)key];
|
||||
}
|
||||
|
||||
private void OnPageKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
//DebugService.WriteLine(string.Concat("OnPageKeyDn: Key=", e.Key));
|
||||
|
||||
_states[(int)((e.Key == Key.System) ? e.SystemKey : e.Key)] = true;
|
||||
_updateAnyKeyDown = false;
|
||||
IsAnyKeyDown = true;
|
||||
|
||||
int asciiKey = GetAsciiKey(e.Key, e.KeyboardDevice);
|
||||
if (asciiKey >= 0)
|
||||
{
|
||||
Machine.Keyboard.Latch = asciiKey;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
private void OnPageKeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
//DebugService.WriteLine(string.Concat("OnPageKeyUp: Key=", e.Key));
|
||||
|
||||
_states[(int)((e.Key == Key.System) ? e.SystemKey : e.Key)] = false;
|
||||
_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", "CA1505:AvoidUnmaintainableCode")]
|
||||
private static int GetAsciiKey(Key key, KeyboardDevice keyboard)
|
||||
{
|
||||
bool control = ((keyboard.Modifiers & ModifierKeys.Control) != 0);
|
||||
bool shift = ((keyboard.Modifiers & ModifierKeys.Shift) != 0);
|
||||
bool capsLock = shift ^ keyboard.IsKeyToggled(Key.CapsLock);
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case Key.Left:
|
||||
return 0x08;
|
||||
|
||||
case Key.Tab:
|
||||
return 0x09;
|
||||
|
||||
case Key.Down:
|
||||
return 0x0A;
|
||||
|
||||
case Key.Up:
|
||||
return 0x0B;
|
||||
|
||||
case Key.Enter:
|
||||
return 0x0D;
|
||||
|
||||
case Key.Right:
|
||||
return 0x15;
|
||||
|
||||
case Key.Escape:
|
||||
return 0x1B;
|
||||
|
||||
case Key.Back:
|
||||
return control ? -1 : 0x7F;
|
||||
|
||||
case Key.Space:
|
||||
return ' ';
|
||||
|
||||
case Key.D1:
|
||||
return shift ? '!' : '1';
|
||||
|
||||
case Key.D2:
|
||||
return control ? 0x00 : shift ? '@' : '2';
|
||||
|
||||
case Key.D3:
|
||||
return shift ? '#' : '3';
|
||||
|
||||
case Key.D4:
|
||||
return shift ? '$' : '4';
|
||||
|
||||
case Key.D5:
|
||||
return shift ? '%' : '5';
|
||||
|
||||
case Key.D6:
|
||||
return control ? 0x1E : shift ? '^' : '6';
|
||||
|
||||
case Key.D7:
|
||||
return shift ? '&' : '7';
|
||||
|
||||
case Key.D8:
|
||||
return shift ? '*' : '8';
|
||||
|
||||
case Key.D9:
|
||||
return shift ? '(' : '9';
|
||||
|
||||
case Key.D0:
|
||||
return shift ? ')' : '0';
|
||||
|
||||
case Key.A:
|
||||
return control ? 0x01 : capsLock ? 'A' : 'a';
|
||||
|
||||
case Key.B:
|
||||
return control ? 0x02 : capsLock ? 'B' : 'b';
|
||||
|
||||
case Key.C:
|
||||
return control ? 0x03 : capsLock ? 'C' : 'c';
|
||||
|
||||
case Key.D:
|
||||
return control ? 0x04 : capsLock ? 'D' : 'd';
|
||||
|
||||
case Key.E:
|
||||
return control ? 0x05 : capsLock ? 'E' : 'e';
|
||||
|
||||
case Key.F:
|
||||
return control ? 0x06 : capsLock ? 'F' : 'f';
|
||||
|
||||
case Key.G:
|
||||
return control ? 0x07 : capsLock ? 'G' : 'g';
|
||||
|
||||
case Key.H:
|
||||
return control ? 0x08 : capsLock ? 'H' : 'h';
|
||||
|
||||
case Key.I:
|
||||
return control ? 0x09 : capsLock ? 'I' : 'i';
|
||||
|
||||
case Key.J:
|
||||
return control ? 0x0A : capsLock ? 'J' : 'j';
|
||||
|
||||
case Key.K:
|
||||
return control ? 0x0B : capsLock ? 'K' : 'k';
|
||||
|
||||
case Key.L:
|
||||
return control ? 0x0C : capsLock ? 'L' : 'l';
|
||||
|
||||
case Key.M:
|
||||
return control ? 0x0D : capsLock ? 'M' : 'm';
|
||||
|
||||
case Key.N:
|
||||
return control ? 0x0E : capsLock ? 'N' : 'n';
|
||||
|
||||
case Key.O:
|
||||
return control ? 0x0F : capsLock ? 'O' : 'o';
|
||||
|
||||
case Key.P:
|
||||
return control ? 0x10 : capsLock ? 'P' : 'p';
|
||||
|
||||
case Key.Q:
|
||||
return control ? 0x11 : capsLock ? 'Q' : 'q';
|
||||
|
||||
case Key.R:
|
||||
return control ? 0x12 : capsLock ? 'R' : 'r';
|
||||
|
||||
case Key.S:
|
||||
return control ? 0x13 : capsLock ? 'S' : 's';
|
||||
|
||||
case Key.T:
|
||||
return control ? 0x14 : capsLock ? 'T' : 't';
|
||||
|
||||
case Key.U:
|
||||
return control ? 0x15 : capsLock ? 'U' : 'u';
|
||||
|
||||
case Key.V:
|
||||
return control ? 0x16 : capsLock ? 'V' : 'v';
|
||||
|
||||
case Key.W:
|
||||
return control ? 0x17 : capsLock ? 'W' : 'w';
|
||||
|
||||
case Key.X:
|
||||
return control ? 0x18 : capsLock ? 'X' : 'x';
|
||||
|
||||
case Key.Y:
|
||||
return control ? 0x19 : capsLock ? 'Y' : 'y';
|
||||
|
||||
case Key.Z:
|
||||
return control ? 0x1A : capsLock ? 'Z' : 'z';
|
||||
|
||||
case Key.Oem1:
|
||||
return shift ? ':' : ';';
|
||||
|
||||
case Key.Oem2:
|
||||
return shift ? '?' : '/';
|
||||
|
||||
case Key.Oem3:
|
||||
return shift ? '~' : '`';
|
||||
|
||||
case Key.Oem4:
|
||||
return shift ? '{' : '[';
|
||||
|
||||
case Key.Oem5:
|
||||
return control ? 0x1C : shift ? '|' : '\\';
|
||||
|
||||
case Key.Oem6:
|
||||
return control ? 0x1D : shift ? '}' : ']';
|
||||
|
||||
case Key.Oem7:
|
||||
return shift ? '"' : '\'';
|
||||
|
||||
case Key.OemMinus:
|
||||
return control ? 0x1F : shift ? '_' : '-';
|
||||
|
||||
case Key.OemPlus:
|
||||
return shift ? '+' : '=';
|
||||
|
||||
case Key.OemComma:
|
||||
return shift ? '<' : ',';
|
||||
|
||||
case Key.OemPeriod:
|
||||
return shift ? '>' : '.';
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static readonly Key[] KeyValues =
|
||||
(from key in (Key[])Enum.GetValues(typeof(Key))
|
||||
where (key != Key.None) // filter Key.None; avoids validation exception
|
||||
select key).ToArray();
|
||||
|
||||
private static readonly int KeyCount = (int)(KeyValues.Max()) + 1;
|
||||
|
||||
private bool[] _states = new bool[KeyCount];
|
||||
private bool _updateAnyKeyDown;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
using System.Deployment.Application;
|
||||
using System.IO.IsolatedStorage;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class WpfStorageService : IsolatedStorageService
|
||||
{
|
||||
public WpfStorageService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IsolatedStorageFile GetStore()
|
||||
{
|
||||
return ApplicationDeployment.IsNetworkDeployed ? // clickonce
|
||||
IsolatedStorageFile.GetUserStoreForApplication() : IsolatedStorageFile.GetUserStoreForAssembly();
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Deployment.Application;
|
||||
using System.IO.IsolatedStorage;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class WpfStorageService : IsolatedStorageService
|
||||
{
|
||||
public WpfStorageService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IsolatedStorageFile GetStore()
|
||||
{
|
||||
return ApplicationDeployment.IsNetworkDeployed ? // clickonce
|
||||
IsolatedStorageFile.GetUserStoreForApplication() : IsolatedStorageFile.GetUserStoreForAssembly();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,101 +1,101 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class WpfVideoService : VideoService
|
||||
{
|
||||
public WpfVideoService(Machine machine, UserControl page, Image image) :
|
||||
base(machine)
|
||||
{
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException("page");
|
||||
}
|
||||
if (image == null)
|
||||
{
|
||||
throw new ArgumentNullException("image");
|
||||
}
|
||||
|
||||
_page = page;
|
||||
_image = image;
|
||||
_image.Source = _bitmap;
|
||||
|
||||
_page.Loaded += (sender, e) => SetWindowSizeToContent();
|
||||
_page.SizeChanged += (sender, e) => SetImageSize();
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow")]
|
||||
public override void SetPixel(int x, int y, uint color)
|
||||
{
|
||||
_pixels[y * BitmapWidth + x] = color;
|
||||
_pixelsDirty = true;
|
||||
}
|
||||
|
||||
public override void Update() // main thread
|
||||
{
|
||||
if (_isFullScreen != IsFullScreen)
|
||||
{
|
||||
var window = Window.GetWindow(_page);
|
||||
if (IsFullScreen)
|
||||
{
|
||||
window.ResizeMode = ResizeMode.NoResize;
|
||||
window.WindowStyle = WindowStyle.None;
|
||||
window.WindowState = WindowState.Maximized;
|
||||
}
|
||||
else
|
||||
{
|
||||
window.WindowState = WindowState.Normal;
|
||||
window.WindowStyle = WindowStyle.SingleBorderWindow;
|
||||
window.ResizeMode = ResizeMode.CanResize;
|
||||
}
|
||||
_isFullScreen = IsFullScreen;
|
||||
}
|
||||
|
||||
if (_pixelsDirty)
|
||||
{
|
||||
_pixelsDirty = false;
|
||||
_bitmap.WritePixels(BitmapRect, _pixels, BitmapStride, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetImageSize()
|
||||
{
|
||||
int uniformScale = Math.Max(1, Math.Min((int)_page.RenderSize.Width / BitmapWidth, (int)_page.RenderSize.Height / BitmapHeight));
|
||||
_image.Width = uniformScale * BitmapWidth;
|
||||
_image.Height = uniformScale * BitmapHeight;
|
||||
Machine.Video.DirtyScreen();
|
||||
}
|
||||
|
||||
private void SetWindowSizeToContent()
|
||||
{
|
||||
if (!_sizedToContent)
|
||||
{
|
||||
_sizedToContent = true;
|
||||
var window = Application.Current.MainWindow;
|
||||
var size = window.DesiredSize;
|
||||
window.Width = size.Width;
|
||||
window.Height = size.Height;
|
||||
}
|
||||
}
|
||||
|
||||
private const int BitmapWidth = 560;
|
||||
private const int BitmapHeight = 384;
|
||||
private const int BitmapDpi = 96;
|
||||
private static readonly PixelFormat BitmapPixelFormat = PixelFormats.Bgr32;
|
||||
private static readonly int BitmapStride = (BitmapWidth * BitmapPixelFormat.BitsPerPixel + 7) / 8;
|
||||
private static readonly Int32Rect BitmapRect = new Int32Rect(0, 0, BitmapWidth, BitmapHeight);
|
||||
|
||||
private UserControl _page;
|
||||
private Image _image;
|
||||
private WriteableBitmap _bitmap = new WriteableBitmap(BitmapWidth, BitmapHeight, BitmapDpi, BitmapDpi, BitmapPixelFormat, null);
|
||||
private uint[] _pixels = new uint[BitmapWidth * BitmapHeight];
|
||||
private bool _pixelsDirty;
|
||||
private bool _isFullScreen;
|
||||
private bool _sizedToContent;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class WpfVideoService : VideoService
|
||||
{
|
||||
public WpfVideoService(Machine machine, UserControl page, Image image) :
|
||||
base(machine)
|
||||
{
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException("page");
|
||||
}
|
||||
if (image == null)
|
||||
{
|
||||
throw new ArgumentNullException("image");
|
||||
}
|
||||
|
||||
_page = page;
|
||||
_image = image;
|
||||
_image.Source = _bitmap;
|
||||
|
||||
_page.Loaded += (sender, e) => SetWindowSizeToContent();
|
||||
_page.SizeChanged += (sender, e) => SetImageSize();
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow")]
|
||||
public override void SetPixel(int x, int y, uint color)
|
||||
{
|
||||
_pixels[y * BitmapWidth + x] = color;
|
||||
_pixelsDirty = true;
|
||||
}
|
||||
|
||||
public override void Update() // main thread
|
||||
{
|
||||
if (_isFullScreen != IsFullScreen)
|
||||
{
|
||||
var window = Window.GetWindow(_page);
|
||||
if (IsFullScreen)
|
||||
{
|
||||
window.ResizeMode = ResizeMode.NoResize;
|
||||
window.WindowStyle = WindowStyle.None;
|
||||
window.WindowState = WindowState.Maximized;
|
||||
}
|
||||
else
|
||||
{
|
||||
window.WindowState = WindowState.Normal;
|
||||
window.WindowStyle = WindowStyle.SingleBorderWindow;
|
||||
window.ResizeMode = ResizeMode.CanResize;
|
||||
}
|
||||
_isFullScreen = IsFullScreen;
|
||||
}
|
||||
|
||||
if (_pixelsDirty)
|
||||
{
|
||||
_pixelsDirty = false;
|
||||
_bitmap.WritePixels(BitmapRect, _pixels, BitmapStride, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetImageSize()
|
||||
{
|
||||
int uniformScale = Math.Max(1, Math.Min((int)_page.RenderSize.Width / BitmapWidth, (int)_page.RenderSize.Height / BitmapHeight));
|
||||
_image.Width = uniformScale * BitmapWidth;
|
||||
_image.Height = uniformScale * BitmapHeight;
|
||||
Machine.Video.DirtyScreen();
|
||||
}
|
||||
|
||||
private void SetWindowSizeToContent()
|
||||
{
|
||||
if (!_sizedToContent)
|
||||
{
|
||||
_sizedToContent = true;
|
||||
var window = Application.Current.MainWindow;
|
||||
var size = window.DesiredSize;
|
||||
window.Width = size.Width;
|
||||
window.Height = size.Height;
|
||||
}
|
||||
}
|
||||
|
||||
private const int BitmapWidth = 560;
|
||||
private const int BitmapHeight = 384;
|
||||
private const int BitmapDpi = 96;
|
||||
private static readonly PixelFormat BitmapPixelFormat = PixelFormats.Bgr32;
|
||||
private static readonly int BitmapStride = (BitmapWidth * BitmapPixelFormat.BitsPerPixel + 7) / 8;
|
||||
private static readonly Int32Rect BitmapRect = new Int32Rect(0, 0, BitmapWidth, BitmapHeight);
|
||||
|
||||
private UserControl _page;
|
||||
private Image _image;
|
||||
private WriteableBitmap _bitmap = new WriteableBitmap(BitmapWidth, BitmapHeight, BitmapDpi, BitmapDpi, BitmapPixelFormat, null);
|
||||
private uint[] _pixels = new uint[BitmapWidth * BitmapHeight];
|
||||
private bool _pixelsDirty;
|
||||
private bool _isFullScreen;
|
||||
private bool _sizedToContent;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
namespace Jellyfish.Virtu
|
||||
{
|
||||
#if WINDOWS || XBOX
|
||||
static class MainApp
|
||||
{
|
||||
static void Main()
|
||||
{
|
||||
using (var game = new MainGame())
|
||||
{
|
||||
game.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
#if WINDOWS || XBOX
|
||||
static class MainApp
|
||||
{
|
||||
static void Main()
|
||||
{
|
||||
using (var game = new MainGame())
|
||||
{
|
||||
game.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,91 +1,91 @@
|
|||
using Jellyfish.Library;
|
||||
using Jellyfish.Virtu.Services;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class MainGame : GameBase
|
||||
{
|
||||
public MainGame() :
|
||||
base("Virtu")
|
||||
{
|
||||
#if WINDOWS
|
||||
IsMouseVisible = true;
|
||||
#endif
|
||||
var frameRateCounter = new FrameRateCounter(this); // no initializers; avoids CA2000
|
||||
Components.Add(frameRateCounter);
|
||||
frameRateCounter.DrawOrder = 1;
|
||||
frameRateCounter.FontName = "Consolas";
|
||||
|
||||
_debugService = new DebugService(_machine);
|
||||
#if WINDOWS_PHONE
|
||||
_storageService = new IsolatedStorageService(_machine);
|
||||
#else
|
||||
_storageService = new XnaStorageService(_machine, this);
|
||||
#endif
|
||||
_keyboardService = new XnaKeyboardService(_machine);
|
||||
_gamePortService = new XnaGamePortService(_machine);
|
||||
_audioService = new XnaAudioService(_machine, this);
|
||||
_videoService = new XnaVideoService(_machine, this);
|
||||
|
||||
_machine.Services.AddService(typeof(DebugService), _debugService);
|
||||
_machine.Services.AddService(typeof(StorageService), _storageService);
|
||||
_machine.Services.AddService(typeof(KeyboardService), _keyboardService);
|
||||
_machine.Services.AddService(typeof(GamePortService), _gamePortService);
|
||||
_machine.Services.AddService(typeof(AudioService), _audioService);
|
||||
_machine.Services.AddService(typeof(VideoService), _videoService);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_machine.Dispose();
|
||||
_debugService.Dispose();
|
||||
_storageService.Dispose();
|
||||
_keyboardService.Dispose();
|
||||
_gamePortService.Dispose();
|
||||
_audioService.Dispose();
|
||||
_videoService.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
protected override void BeginRun()
|
||||
{
|
||||
_machine.Start();
|
||||
}
|
||||
|
||||
protected override void Update(GameTime gameTime)
|
||||
{
|
||||
_keyboardService.Update();
|
||||
_gamePortService.Update();
|
||||
|
||||
base.Update(gameTime);
|
||||
}
|
||||
|
||||
protected override void Draw(GameTime gameTime)
|
||||
{
|
||||
GraphicsDevice.Clear(Color.Black);
|
||||
_videoService.Update();
|
||||
|
||||
base.Draw(gameTime);
|
||||
}
|
||||
|
||||
protected override void EndRun()
|
||||
{
|
||||
_machine.Stop();
|
||||
}
|
||||
|
||||
private Machine _machine = new Machine();
|
||||
|
||||
private DebugService _debugService;
|
||||
private StorageService _storageService;
|
||||
private KeyboardService _keyboardService;
|
||||
private GamePortService _gamePortService;
|
||||
private AudioService _audioService;
|
||||
private VideoService _videoService;
|
||||
}
|
||||
}
|
||||
using Jellyfish.Library;
|
||||
using Jellyfish.Virtu.Services;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class MainGame : GameBase
|
||||
{
|
||||
public MainGame() :
|
||||
base("Virtu")
|
||||
{
|
||||
#if WINDOWS
|
||||
IsMouseVisible = true;
|
||||
#endif
|
||||
var frameRateCounter = new FrameRateCounter(this); // no initializers; avoids CA2000
|
||||
Components.Add(frameRateCounter);
|
||||
frameRateCounter.DrawOrder = 1;
|
||||
frameRateCounter.FontName = "Consolas";
|
||||
|
||||
_debugService = new DebugService(_machine);
|
||||
#if WINDOWS_PHONE
|
||||
_storageService = new IsolatedStorageService(_machine);
|
||||
#else
|
||||
_storageService = new XnaStorageService(_machine, this);
|
||||
#endif
|
||||
_keyboardService = new XnaKeyboardService(_machine);
|
||||
_gamePortService = new XnaGamePortService(_machine);
|
||||
_audioService = new XnaAudioService(_machine, this);
|
||||
_videoService = new XnaVideoService(_machine, this);
|
||||
|
||||
_machine.Services.AddService(typeof(DebugService), _debugService);
|
||||
_machine.Services.AddService(typeof(StorageService), _storageService);
|
||||
_machine.Services.AddService(typeof(KeyboardService), _keyboardService);
|
||||
_machine.Services.AddService(typeof(GamePortService), _gamePortService);
|
||||
_machine.Services.AddService(typeof(AudioService), _audioService);
|
||||
_machine.Services.AddService(typeof(VideoService), _videoService);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_machine.Dispose();
|
||||
_debugService.Dispose();
|
||||
_storageService.Dispose();
|
||||
_keyboardService.Dispose();
|
||||
_gamePortService.Dispose();
|
||||
_audioService.Dispose();
|
||||
_videoService.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
protected override void BeginRun()
|
||||
{
|
||||
_machine.Start();
|
||||
}
|
||||
|
||||
protected override void Update(GameTime gameTime)
|
||||
{
|
||||
_keyboardService.Update();
|
||||
_gamePortService.Update();
|
||||
|
||||
base.Update(gameTime);
|
||||
}
|
||||
|
||||
protected override void Draw(GameTime gameTime)
|
||||
{
|
||||
GraphicsDevice.Clear(Color.Black);
|
||||
_videoService.Update();
|
||||
|
||||
base.Draw(gameTime);
|
||||
}
|
||||
|
||||
protected override void EndRun()
|
||||
{
|
||||
_machine.Stop();
|
||||
}
|
||||
|
||||
private Machine _machine = new Machine();
|
||||
|
||||
private DebugService _debugService;
|
||||
private StorageService _storageService;
|
||||
private KeyboardService _keyboardService;
|
||||
private GamePortService _gamePortService;
|
||||
private AudioService _audioService;
|
||||
private VideoService _videoService;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Deployment.Parts>
|
||||
</Deployment.Parts>
|
||||
</Deployment>
|
||||
<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Deployment.Parts>
|
||||
</Deployment.Parts>
|
||||
</Deployment>
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using Jellyfish.Library;
|
||||
|
||||
[assembly: AssemblyTitle("Virtu")]
|
||||
[assembly: AssemblyDescription("Apple IIe Emulator")]
|
||||
#if WINDOWS_PHONE
|
||||
[assembly: AssemblyProduct("Jellyfish.Virtu.Xna.Phone")]
|
||||
#elif XBOX
|
||||
[assembly: AssemblyProduct("Jellyfish.Virtu.Xna.Xbox")]
|
||||
#else
|
||||
[assembly: AssemblyProduct("Jellyfish.Virtu.Xna")]
|
||||
#endif
|
||||
[assembly: AssemblyCompany("Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")]
|
||||
|
||||
[assembly: AssemblyVersion("0.8.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.8.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.8.3.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("89a50370-1ed9-4cf1-ad08-043b6e6f3c90")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
using Jellyfish.Library;
|
||||
|
||||
[assembly: AssemblyTitle("Virtu")]
|
||||
[assembly: AssemblyDescription("Apple IIe Emulator")]
|
||||
#if WINDOWS_PHONE
|
||||
[assembly: AssemblyProduct("Jellyfish.Virtu.Xna.Phone")]
|
||||
#elif XBOX
|
||||
[assembly: AssemblyProduct("Jellyfish.Virtu.Xna.Xbox")]
|
||||
#else
|
||||
[assembly: AssemblyProduct("Jellyfish.Virtu.Xna")]
|
||||
#endif
|
||||
[assembly: AssemblyCompany("Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")]
|
||||
|
||||
[assembly: AssemblyVersion("0.8.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.8.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.8.3.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("89a50370-1ed9-4cf1-ad08-043b6e6f3c90")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
|
|
|
@ -1,55 +1,55 @@
|
|||
using System;
|
||||
using Jellyfish.Library;
|
||||
using Microsoft.Xna.Framework.Audio;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class XnaAudioService : AudioService
|
||||
{
|
||||
public XnaAudioService(Machine machine, GameBase game) :
|
||||
base(machine)
|
||||
{
|
||||
if (game == null)
|
||||
{
|
||||
throw new ArgumentNullException("game");
|
||||
}
|
||||
|
||||
_game = game;
|
||||
|
||||
_dynamicSoundEffect.BufferNeeded += OnDynamicSoundEffectBufferNeeded;
|
||||
_game.Exiting += (sender, e) => _dynamicSoundEffect.Stop();
|
||||
|
||||
_dynamicSoundEffect.SubmitBuffer(SampleZero);
|
||||
_dynamicSoundEffect.Play();
|
||||
}
|
||||
|
||||
public override void SetVolume(double volume) // machine thread
|
||||
{
|
||||
_dynamicSoundEffect.Volume = (float)volume;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_dynamicSoundEffect.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void OnDynamicSoundEffectBufferNeeded(object sender, EventArgs e) // audio thread
|
||||
{
|
||||
//if (_count++ % (1000 / SampleLatency) == 0)
|
||||
//{
|
||||
// DebugService.WriteLine("OnDynamicSoundEffectBufferNeeded");
|
||||
//}
|
||||
|
||||
Update(SampleSize, (source, count) => _dynamicSoundEffect.SubmitBuffer(source, 0, count));
|
||||
}
|
||||
|
||||
private GameBase _game;
|
||||
private DynamicSoundEffectInstance _dynamicSoundEffect = new DynamicSoundEffectInstance(SampleRate, (AudioChannels)SampleChannels);
|
||||
//private int _count;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using Jellyfish.Library;
|
||||
using Microsoft.Xna.Framework.Audio;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class XnaAudioService : AudioService
|
||||
{
|
||||
public XnaAudioService(Machine machine, GameBase game) :
|
||||
base(machine)
|
||||
{
|
||||
if (game == null)
|
||||
{
|
||||
throw new ArgumentNullException("game");
|
||||
}
|
||||
|
||||
_game = game;
|
||||
|
||||
_dynamicSoundEffect.BufferNeeded += OnDynamicSoundEffectBufferNeeded;
|
||||
_game.Exiting += (sender, e) => _dynamicSoundEffect.Stop();
|
||||
|
||||
_dynamicSoundEffect.SubmitBuffer(SampleZero);
|
||||
_dynamicSoundEffect.Play();
|
||||
}
|
||||
|
||||
public override void SetVolume(double volume) // machine thread
|
||||
{
|
||||
_dynamicSoundEffect.Volume = (float)volume;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_dynamicSoundEffect.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void OnDynamicSoundEffectBufferNeeded(object sender, EventArgs e) // audio thread
|
||||
{
|
||||
//if (_count++ % (1000 / SampleLatency) == 0)
|
||||
//{
|
||||
// DebugService.WriteLine("OnDynamicSoundEffectBufferNeeded");
|
||||
//}
|
||||
|
||||
Update(SampleSize, (source, count) => _dynamicSoundEffect.SubmitBuffer(source, 0, count));
|
||||
}
|
||||
|
||||
private GameBase _game;
|
||||
private DynamicSoundEffectInstance _dynamicSoundEffect = new DynamicSoundEffectInstance(SampleRate, (AudioChannels)SampleChannels);
|
||||
//private int _count;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,64 +1,64 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class XnaGamePortService : GamePortService
|
||||
{
|
||||
public XnaGamePortService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Update() // main thread
|
||||
{
|
||||
_lastState = _state;
|
||||
_state = GamePad.GetState(PlayerIndex.One);
|
||||
|
||||
if (_state.IsConnected && (_state != _lastState))
|
||||
{
|
||||
var left = _state.ThumbSticks.Left;
|
||||
var right = _state.ThumbSticks.Right;
|
||||
var dpad = _state.DPad;
|
||||
|
||||
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
|
||||
|
||||
Joystick0 = GetJoystick(ref left, ref dpad);
|
||||
Joystick1 = GetJoystick(ref right);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private static Joystick GetJoystick(ref Vector2 thumbstick)
|
||||
{
|
||||
bool isUp = (thumbstick.Y > JoystickDeadZone);
|
||||
bool isLeft = (thumbstick.X < -JoystickDeadZone);
|
||||
bool isRight = (thumbstick.X > JoystickDeadZone);
|
||||
bool isDown = (thumbstick.Y < -JoystickDeadZone);
|
||||
|
||||
return new Joystick(isUp, isLeft, isRight, isDown);
|
||||
}
|
||||
|
||||
private static Joystick GetJoystick(ref Vector2 thumbstick, ref GamePadDPad dpad)
|
||||
{
|
||||
bool isUp = ((thumbstick.Y > JoystickDeadZone) || (dpad.Up == ButtonState.Pressed));
|
||||
bool isLeft = ((thumbstick.X < -JoystickDeadZone) || (dpad.Left == ButtonState.Pressed));
|
||||
bool isRight = ((thumbstick.X > JoystickDeadZone) || (dpad.Right == ButtonState.Pressed));
|
||||
bool isDown = ((thumbstick.Y < -JoystickDeadZone) || (dpad.Down == ButtonState.Pressed));
|
||||
|
||||
return new Joystick(isUp, isLeft, isRight, isDown);
|
||||
}
|
||||
|
||||
private const int PaddleScale = 128;
|
||||
private const float JoystickDeadZone = 0.5f;
|
||||
|
||||
private GamePadState _state;
|
||||
private GamePadState _lastState;
|
||||
}
|
||||
}
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class XnaGamePortService : GamePortService
|
||||
{
|
||||
public XnaGamePortService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Update() // main thread
|
||||
{
|
||||
_lastState = _state;
|
||||
_state = GamePad.GetState(PlayerIndex.One);
|
||||
|
||||
if (_state.IsConnected && (_state != _lastState))
|
||||
{
|
||||
var left = _state.ThumbSticks.Left;
|
||||
var right = _state.ThumbSticks.Right;
|
||||
var dpad = _state.DPad;
|
||||
|
||||
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
|
||||
|
||||
Joystick0 = GetJoystick(ref left, ref dpad);
|
||||
Joystick1 = GetJoystick(ref right);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private static Joystick GetJoystick(ref Vector2 thumbstick)
|
||||
{
|
||||
bool isUp = (thumbstick.Y > JoystickDeadZone);
|
||||
bool isLeft = (thumbstick.X < -JoystickDeadZone);
|
||||
bool isRight = (thumbstick.X > JoystickDeadZone);
|
||||
bool isDown = (thumbstick.Y < -JoystickDeadZone);
|
||||
|
||||
return new Joystick(isUp, isLeft, isRight, isDown);
|
||||
}
|
||||
|
||||
private static Joystick GetJoystick(ref Vector2 thumbstick, ref GamePadDPad dpad)
|
||||
{
|
||||
bool isUp = ((thumbstick.Y > JoystickDeadZone) || (dpad.Up == ButtonState.Pressed));
|
||||
bool isLeft = ((thumbstick.X < -JoystickDeadZone) || (dpad.Left == ButtonState.Pressed));
|
||||
bool isRight = ((thumbstick.X > JoystickDeadZone) || (dpad.Right == ButtonState.Pressed));
|
||||
bool isDown = ((thumbstick.Y < -JoystickDeadZone) || (dpad.Down == ButtonState.Pressed));
|
||||
|
||||
return new Joystick(isUp, isLeft, isRight, isDown);
|
||||
}
|
||||
|
||||
private const int PaddleScale = 128;
|
||||
private const float JoystickDeadZone = 0.5f;
|
||||
|
||||
private GamePadState _state;
|
||||
private GamePadState _lastState;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,330 +1,330 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class XnaKeyboardService : KeyboardService
|
||||
{
|
||||
public XnaKeyboardService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsKeyDown(int key)
|
||||
{
|
||||
return IsKeyDown((Keys)key);
|
||||
}
|
||||
|
||||
public override void Update() // main thread
|
||||
{
|
||||
_lastState = _state;
|
||||
_state = Microsoft.Xna.Framework.Input.Keyboard.GetState();
|
||||
|
||||
var gamePadState = GamePad.GetState(PlayerIndex.One);
|
||||
bool gamePadControl = (gamePadState.Buttons.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
|
||||
{
|
||||
if (_state.IsKeyDown(key))
|
||||
{
|
||||
IsAnyKeyDown = true;
|
||||
if (!_lastState.IsKeyDown(key))
|
||||
{
|
||||
_lastKey = key;
|
||||
_lastTime = DateTime.UtcNow.Ticks;
|
||||
_repeatTime = RepeatDelay;
|
||||
OnKeyDown(key, gamePadControl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (key == _lastKey)
|
||||
{
|
||||
_lastKey = Keys.None;
|
||||
}
|
||||
if (_lastState.IsKeyDown(key))
|
||||
{
|
||||
OnKeyUp(key, gamePadControl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_lastKey != Keys.None) // repeat last key
|
||||
{
|
||||
long time = DateTime.UtcNow.Ticks;
|
||||
if (time - _lastTime >= _repeatTime)
|
||||
{
|
||||
_lastTime = time;
|
||||
_repeatTime = RepeatSpeed;
|
||||
OnKeyDown(_lastKey, gamePadControl);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
base.Update();
|
||||
}
|
||||
|
||||
private bool IsKeyDown(Keys key)
|
||||
{
|
||||
return _state.IsKeyDown(key);
|
||||
}
|
||||
|
||||
private void OnKeyDown(Keys key, bool gamePadControl)
|
||||
{
|
||||
//DebugService.WriteLine(string.Concat("OnKeyDn: Key=", key));
|
||||
|
||||
int asciiKey = GetAsciiKey(key, gamePadControl);
|
||||
if (asciiKey >= 0)
|
||||
{
|
||||
Machine.Keyboard.Latch = asciiKey;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnKeyUp(Keys key, bool gamePadControl)
|
||||
{
|
||||
//DebugService.WriteLine(string.Concat("OnKeyUp: Key=", key));
|
||||
|
||||
bool control = IsKeyDown(Keys.LeftControl) || IsKeyDown(Keys.RightControl);
|
||||
|
||||
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();
|
||||
}
|
||||
#if WINDOWS
|
||||
else if ((control && (key == Keys.Subtract)) || (gamePadControl && (key == Keys.D0)))
|
||||
{
|
||||
Machine.Video.ToggleFullScreen();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
[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 capsLock = shift ^ _capsLock;
|
||||
bool green = IsKeyDown(Keys.ChatPadGreen);
|
||||
bool orange = IsKeyDown(Keys.ChatPadOrange);
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case Keys.Left:
|
||||
return 0x08;
|
||||
|
||||
case Keys.Tab:
|
||||
return 0x09;
|
||||
|
||||
case Keys.Down:
|
||||
return 0x0A;
|
||||
|
||||
case Keys.Up:
|
||||
return 0x0B;
|
||||
|
||||
case Keys.Enter:
|
||||
return 0x0D;
|
||||
|
||||
case Keys.Right:
|
||||
return 0x15;
|
||||
|
||||
case Keys.Escape:
|
||||
return 0x1B;
|
||||
|
||||
case Keys.Back:
|
||||
return control ? -1 : 0x7F;
|
||||
|
||||
case Keys.Space:
|
||||
return ' ';
|
||||
|
||||
case Keys.D1:
|
||||
return shift ? '!' : '1';
|
||||
|
||||
case Keys.D2:
|
||||
return control ? 0x00 : shift ? '@' : '2';
|
||||
|
||||
case Keys.D3:
|
||||
return shift ? '#' : '3';
|
||||
|
||||
case Keys.D4:
|
||||
return shift ? '$' : '4';
|
||||
|
||||
case Keys.D5:
|
||||
return shift ? '%' : '5';
|
||||
|
||||
case Keys.D6:
|
||||
return control ? 0x1E : shift ? '^' : '6';
|
||||
|
||||
case Keys.D7:
|
||||
return shift ? '&' : '7';
|
||||
|
||||
case Keys.D8:
|
||||
return gamePadControl ? -1 : shift ? '*' : '8';
|
||||
|
||||
case Keys.D9:
|
||||
return gamePadControl ? -1 : shift ? '(' : '9';
|
||||
|
||||
case Keys.D0:
|
||||
return gamePadControl ? -1 : shift ? ')' : '0';
|
||||
|
||||
case Keys.A:
|
||||
return control ? 0x01 : green ? '~' : capsLock ? 'A' : 'a';
|
||||
|
||||
case Keys.B:
|
||||
return control ? 0x02 : green ? '|' : orange ? '+' : capsLock ? 'B' : 'b';
|
||||
|
||||
case Keys.C:
|
||||
return control ? 0x03 : capsLock ? 'C' : 'c';
|
||||
|
||||
case Keys.D:
|
||||
return control ? 0x04 : green ? '{' : capsLock ? 'D' : 'd';
|
||||
|
||||
case Keys.E:
|
||||
return control ? 0x05 : capsLock ? 'E' : 'e';
|
||||
|
||||
case Keys.F:
|
||||
return control ? 0x06 : green ? '}' : capsLock ? 'F' : 'f';
|
||||
|
||||
case Keys.G:
|
||||
return control ? 0x07 : capsLock ? 'G' : 'g';
|
||||
|
||||
case Keys.H:
|
||||
return control ? 0x08 : green ? '/' : orange ? '\\' : capsLock ? 'H' : 'h';
|
||||
|
||||
case Keys.I:
|
||||
return control ? 0x09 : green ? '*' : capsLock ? 'I' : 'i';
|
||||
|
||||
case Keys.J:
|
||||
return control ? 0x0A : green ? '\'' : orange ? '"' : capsLock ? 'J' : 'j';
|
||||
|
||||
case Keys.K:
|
||||
return control ? 0x0B : green ? '[' : capsLock ? 'K' : 'k';
|
||||
|
||||
case Keys.L:
|
||||
return control ? 0x0C : green ? ']' : capsLock ? 'L' : 'l';
|
||||
|
||||
case Keys.M:
|
||||
return control ? 0x0D : green ? '>' : capsLock ? 'M' : 'm';
|
||||
|
||||
case Keys.N:
|
||||
return control ? 0x0E : green ? '<' : capsLock ? 'N' : 'n';
|
||||
|
||||
case Keys.O:
|
||||
return control ? 0x0F : green ? '(' : capsLock ? 'O' : 'o';
|
||||
|
||||
case Keys.P:
|
||||
return control ? 0x10 : green ? ')' : orange ? '=' : capsLock ? 'P' : 'p';
|
||||
|
||||
case Keys.Q:
|
||||
return control ? 0x11 : green ? '!' : capsLock ? 'Q' : 'q';
|
||||
|
||||
case Keys.R:
|
||||
return control ? 0x12 : green ? '#' : orange ? '$' : capsLock ? 'R' : 'r';
|
||||
|
||||
case Keys.S:
|
||||
return control ? 0x13 : capsLock ? 'S' : 's';
|
||||
|
||||
case Keys.T:
|
||||
return control ? 0x14 : green ? '%' : capsLock ? 'T' : 't';
|
||||
|
||||
case Keys.U:
|
||||
return control ? 0x15 : green ? '&' : capsLock ? 'U' : 'u';
|
||||
|
||||
case Keys.V:
|
||||
return control ? 0x16 : green ? '-' : orange ? '_' : capsLock ? 'V' : 'v';
|
||||
|
||||
case Keys.W:
|
||||
return control ? 0x17 : green ? '@' : capsLock ? 'W' : 'w';
|
||||
|
||||
case Keys.X:
|
||||
return control ? 0x18 : capsLock ? 'X' : 'x';
|
||||
|
||||
case Keys.Y:
|
||||
return control ? 0x19 : green ? '^' : capsLock ? 'Y' : 'y';
|
||||
|
||||
case Keys.Z:
|
||||
return control ? 0x1A : green ? '`' : capsLock ? 'Z' : 'z';
|
||||
|
||||
case Keys.OemSemicolon:
|
||||
return shift ? ':' : ';';
|
||||
|
||||
case Keys.OemQuestion:
|
||||
return shift ? '?' : '/';
|
||||
|
||||
case Keys.OemTilde:
|
||||
return shift ? '~' : '`';
|
||||
|
||||
case Keys.OemOpenBrackets:
|
||||
return shift ? '{' : '[';
|
||||
|
||||
case Keys.OemBackslash:
|
||||
case Keys.OemPipe:
|
||||
return control ? 0x1C : shift ? '|' : '\\';
|
||||
|
||||
case Keys.OemCloseBrackets:
|
||||
return control ? 0x1D : shift ? '}' : ']';
|
||||
|
||||
case Keys.OemQuotes:
|
||||
return shift ? '"' : '\'';
|
||||
|
||||
case Keys.OemMinus:
|
||||
return control ? 0x1F : shift ? '_' : '-';
|
||||
|
||||
case Keys.OemPlus:
|
||||
return shift ? '+' : '=';
|
||||
|
||||
case Keys.OemComma:
|
||||
return shift ? '<' : green ? ':' : orange ? ';' : ',';
|
||||
|
||||
case Keys.OemPeriod:
|
||||
return shift ? '>' : green ? '?' : '.';
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static readonly Keys[] KeyValues =
|
||||
#if WINDOWS_PHONE || XBOX
|
||||
(from key in
|
||||
(from field in typeof(Keys).GetFields() // missing Enum.GetValues; use reflection
|
||||
where field.IsLiteral
|
||||
select (Keys)field.GetValue(typeof(Keys)))
|
||||
where (key != Keys.None) // filter Keys.None
|
||||
select key).ToArray();
|
||||
#else
|
||||
(from key in (Keys[])Enum.GetValues(typeof(Keys))
|
||||
where (key != Keys.None) // filter Keys.None
|
||||
select key).ToArray();
|
||||
#endif
|
||||
private static readonly long RepeatDelay = TimeSpan.FromMilliseconds(500).Ticks;
|
||||
private static readonly long RepeatSpeed = TimeSpan.FromMilliseconds(32).Ticks;
|
||||
|
||||
private KeyboardState _state;
|
||||
private KeyboardState _lastState;
|
||||
private bool _capsLock;
|
||||
private Keys _lastKey;
|
||||
private long _lastTime;
|
||||
private long _repeatTime;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class XnaKeyboardService : KeyboardService
|
||||
{
|
||||
public XnaKeyboardService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsKeyDown(int key)
|
||||
{
|
||||
return IsKeyDown((Keys)key);
|
||||
}
|
||||
|
||||
public override void Update() // main thread
|
||||
{
|
||||
_lastState = _state;
|
||||
_state = Microsoft.Xna.Framework.Input.Keyboard.GetState();
|
||||
|
||||
var gamePadState = GamePad.GetState(PlayerIndex.One);
|
||||
bool gamePadControl = (gamePadState.Buttons.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
|
||||
{
|
||||
if (_state.IsKeyDown(key))
|
||||
{
|
||||
IsAnyKeyDown = true;
|
||||
if (!_lastState.IsKeyDown(key))
|
||||
{
|
||||
_lastKey = key;
|
||||
_lastTime = DateTime.UtcNow.Ticks;
|
||||
_repeatTime = RepeatDelay;
|
||||
OnKeyDown(key, gamePadControl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (key == _lastKey)
|
||||
{
|
||||
_lastKey = Keys.None;
|
||||
}
|
||||
if (_lastState.IsKeyDown(key))
|
||||
{
|
||||
OnKeyUp(key, gamePadControl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_lastKey != Keys.None) // repeat last key
|
||||
{
|
||||
long time = DateTime.UtcNow.Ticks;
|
||||
if (time - _lastTime >= _repeatTime)
|
||||
{
|
||||
_lastTime = time;
|
||||
_repeatTime = RepeatSpeed;
|
||||
OnKeyDown(_lastKey, gamePadControl);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
base.Update();
|
||||
}
|
||||
|
||||
private bool IsKeyDown(Keys key)
|
||||
{
|
||||
return _state.IsKeyDown(key);
|
||||
}
|
||||
|
||||
private void OnKeyDown(Keys key, bool gamePadControl)
|
||||
{
|
||||
//DebugService.WriteLine(string.Concat("OnKeyDn: Key=", key));
|
||||
|
||||
int asciiKey = GetAsciiKey(key, gamePadControl);
|
||||
if (asciiKey >= 0)
|
||||
{
|
||||
Machine.Keyboard.Latch = asciiKey;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnKeyUp(Keys key, bool gamePadControl)
|
||||
{
|
||||
//DebugService.WriteLine(string.Concat("OnKeyUp: Key=", key));
|
||||
|
||||
bool control = IsKeyDown(Keys.LeftControl) || IsKeyDown(Keys.RightControl);
|
||||
|
||||
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();
|
||||
}
|
||||
#if WINDOWS
|
||||
else if ((control && (key == Keys.Subtract)) || (gamePadControl && (key == Keys.D0)))
|
||||
{
|
||||
Machine.Video.ToggleFullScreen();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
[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 capsLock = shift ^ _capsLock;
|
||||
bool green = IsKeyDown(Keys.ChatPadGreen);
|
||||
bool orange = IsKeyDown(Keys.ChatPadOrange);
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case Keys.Left:
|
||||
return 0x08;
|
||||
|
||||
case Keys.Tab:
|
||||
return 0x09;
|
||||
|
||||
case Keys.Down:
|
||||
return 0x0A;
|
||||
|
||||
case Keys.Up:
|
||||
return 0x0B;
|
||||
|
||||
case Keys.Enter:
|
||||
return 0x0D;
|
||||
|
||||
case Keys.Right:
|
||||
return 0x15;
|
||||
|
||||
case Keys.Escape:
|
||||
return 0x1B;
|
||||
|
||||
case Keys.Back:
|
||||
return control ? -1 : 0x7F;
|
||||
|
||||
case Keys.Space:
|
||||
return ' ';
|
||||
|
||||
case Keys.D1:
|
||||
return shift ? '!' : '1';
|
||||
|
||||
case Keys.D2:
|
||||
return control ? 0x00 : shift ? '@' : '2';
|
||||
|
||||
case Keys.D3:
|
||||
return shift ? '#' : '3';
|
||||
|
||||
case Keys.D4:
|
||||
return shift ? '$' : '4';
|
||||
|
||||
case Keys.D5:
|
||||
return shift ? '%' : '5';
|
||||
|
||||
case Keys.D6:
|
||||
return control ? 0x1E : shift ? '^' : '6';
|
||||
|
||||
case Keys.D7:
|
||||
return shift ? '&' : '7';
|
||||
|
||||
case Keys.D8:
|
||||
return gamePadControl ? -1 : shift ? '*' : '8';
|
||||
|
||||
case Keys.D9:
|
||||
return gamePadControl ? -1 : shift ? '(' : '9';
|
||||
|
||||
case Keys.D0:
|
||||
return gamePadControl ? -1 : shift ? ')' : '0';
|
||||
|
||||
case Keys.A:
|
||||
return control ? 0x01 : green ? '~' : capsLock ? 'A' : 'a';
|
||||
|
||||
case Keys.B:
|
||||
return control ? 0x02 : green ? '|' : orange ? '+' : capsLock ? 'B' : 'b';
|
||||
|
||||
case Keys.C:
|
||||
return control ? 0x03 : capsLock ? 'C' : 'c';
|
||||
|
||||
case Keys.D:
|
||||
return control ? 0x04 : green ? '{' : capsLock ? 'D' : 'd';
|
||||
|
||||
case Keys.E:
|
||||
return control ? 0x05 : capsLock ? 'E' : 'e';
|
||||
|
||||
case Keys.F:
|
||||
return control ? 0x06 : green ? '}' : capsLock ? 'F' : 'f';
|
||||
|
||||
case Keys.G:
|
||||
return control ? 0x07 : capsLock ? 'G' : 'g';
|
||||
|
||||
case Keys.H:
|
||||
return control ? 0x08 : green ? '/' : orange ? '\\' : capsLock ? 'H' : 'h';
|
||||
|
||||
case Keys.I:
|
||||
return control ? 0x09 : green ? '*' : capsLock ? 'I' : 'i';
|
||||
|
||||
case Keys.J:
|
||||
return control ? 0x0A : green ? '\'' : orange ? '"' : capsLock ? 'J' : 'j';
|
||||
|
||||
case Keys.K:
|
||||
return control ? 0x0B : green ? '[' : capsLock ? 'K' : 'k';
|
||||
|
||||
case Keys.L:
|
||||
return control ? 0x0C : green ? ']' : capsLock ? 'L' : 'l';
|
||||
|
||||
case Keys.M:
|
||||
return control ? 0x0D : green ? '>' : capsLock ? 'M' : 'm';
|
||||
|
||||
case Keys.N:
|
||||
return control ? 0x0E : green ? '<' : capsLock ? 'N' : 'n';
|
||||
|
||||
case Keys.O:
|
||||
return control ? 0x0F : green ? '(' : capsLock ? 'O' : 'o';
|
||||
|
||||
case Keys.P:
|
||||
return control ? 0x10 : green ? ')' : orange ? '=' : capsLock ? 'P' : 'p';
|
||||
|
||||
case Keys.Q:
|
||||
return control ? 0x11 : green ? '!' : capsLock ? 'Q' : 'q';
|
||||
|
||||
case Keys.R:
|
||||
return control ? 0x12 : green ? '#' : orange ? '$' : capsLock ? 'R' : 'r';
|
||||
|
||||
case Keys.S:
|
||||
return control ? 0x13 : capsLock ? 'S' : 's';
|
||||
|
||||
case Keys.T:
|
||||
return control ? 0x14 : green ? '%' : capsLock ? 'T' : 't';
|
||||
|
||||
case Keys.U:
|
||||
return control ? 0x15 : green ? '&' : capsLock ? 'U' : 'u';
|
||||
|
||||
case Keys.V:
|
||||
return control ? 0x16 : green ? '-' : orange ? '_' : capsLock ? 'V' : 'v';
|
||||
|
||||
case Keys.W:
|
||||
return control ? 0x17 : green ? '@' : capsLock ? 'W' : 'w';
|
||||
|
||||
case Keys.X:
|
||||
return control ? 0x18 : capsLock ? 'X' : 'x';
|
||||
|
||||
case Keys.Y:
|
||||
return control ? 0x19 : green ? '^' : capsLock ? 'Y' : 'y';
|
||||
|
||||
case Keys.Z:
|
||||
return control ? 0x1A : green ? '`' : capsLock ? 'Z' : 'z';
|
||||
|
||||
case Keys.OemSemicolon:
|
||||
return shift ? ':' : ';';
|
||||
|
||||
case Keys.OemQuestion:
|
||||
return shift ? '?' : '/';
|
||||
|
||||
case Keys.OemTilde:
|
||||
return shift ? '~' : '`';
|
||||
|
||||
case Keys.OemOpenBrackets:
|
||||
return shift ? '{' : '[';
|
||||
|
||||
case Keys.OemBackslash:
|
||||
case Keys.OemPipe:
|
||||
return control ? 0x1C : shift ? '|' : '\\';
|
||||
|
||||
case Keys.OemCloseBrackets:
|
||||
return control ? 0x1D : shift ? '}' : ']';
|
||||
|
||||
case Keys.OemQuotes:
|
||||
return shift ? '"' : '\'';
|
||||
|
||||
case Keys.OemMinus:
|
||||
return control ? 0x1F : shift ? '_' : '-';
|
||||
|
||||
case Keys.OemPlus:
|
||||
return shift ? '+' : '=';
|
||||
|
||||
case Keys.OemComma:
|
||||
return shift ? '<' : green ? ':' : orange ? ';' : ',';
|
||||
|
||||
case Keys.OemPeriod:
|
||||
return shift ? '>' : green ? '?' : '.';
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static readonly Keys[] KeyValues =
|
||||
#if WINDOWS_PHONE || XBOX
|
||||
(from key in
|
||||
(from field in typeof(Keys).GetFields() // missing Enum.GetValues; use reflection
|
||||
where field.IsLiteral
|
||||
select (Keys)field.GetValue(typeof(Keys)))
|
||||
where (key != Keys.None) // filter Keys.None
|
||||
select key).ToArray();
|
||||
#else
|
||||
(from key in (Keys[])Enum.GetValues(typeof(Keys))
|
||||
where (key != Keys.None) // filter Keys.None
|
||||
select key).ToArray();
|
||||
#endif
|
||||
private static readonly long RepeatDelay = TimeSpan.FromMilliseconds(500).Ticks;
|
||||
private static readonly long RepeatSpeed = TimeSpan.FromMilliseconds(32).Ticks;
|
||||
|
||||
private KeyboardState _state;
|
||||
private KeyboardState _lastState;
|
||||
private bool _capsLock;
|
||||
private Keys _lastKey;
|
||||
private long _lastTime;
|
||||
private long _repeatTime;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,67 +1,67 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Jellyfish.Library;
|
||||
using Microsoft.Xna.Framework.Storage;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class XnaStorageService : StorageService
|
||||
{
|
||||
public XnaStorageService(Machine machine, GameBase game) :
|
||||
base(machine)
|
||||
{
|
||||
if (game == null)
|
||||
{
|
||||
throw new ArgumentNullException("game");
|
||||
}
|
||||
|
||||
_game = game;
|
||||
}
|
||||
|
||||
public override void Load(string path, Action<Stream> reader)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (var storageContainer = OpenContainer())
|
||||
{
|
||||
using (var stream = storageContainer.OpenFile(path))
|
||||
{
|
||||
reader(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public override void Save(string path, Action<Stream> writer)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException("writer");
|
||||
}
|
||||
|
||||
using (var storageContainer = OpenContainer())
|
||||
{
|
||||
using (var stream = storageContainer.OpenFile(path))
|
||||
{
|
||||
writer(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private StorageContainer OpenContainer()
|
||||
{
|
||||
return _storageDevice.Value.EndOpenContainer(_storageDevice.Value.BeginOpenContainer(_game.Name, null, null));
|
||||
}
|
||||
|
||||
private GameBase _game;
|
||||
private Lazy<StorageDevice> _storageDevice = new Lazy<StorageDevice>(() => StorageDevice.EndShowSelector(StorageDevice.BeginShowSelector(null, null)));
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.IO;
|
||||
using Jellyfish.Library;
|
||||
using Microsoft.Xna.Framework.Storage;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class XnaStorageService : StorageService
|
||||
{
|
||||
public XnaStorageService(Machine machine, GameBase game) :
|
||||
base(machine)
|
||||
{
|
||||
if (game == null)
|
||||
{
|
||||
throw new ArgumentNullException("game");
|
||||
}
|
||||
|
||||
_game = game;
|
||||
}
|
||||
|
||||
public override void Load(string path, Action<Stream> reader)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (var storageContainer = OpenContainer())
|
||||
{
|
||||
using (var stream = storageContainer.OpenFile(path))
|
||||
{
|
||||
reader(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public override void Save(string path, Action<Stream> writer)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException("writer");
|
||||
}
|
||||
|
||||
using (var storageContainer = OpenContainer())
|
||||
{
|
||||
using (var stream = storageContainer.OpenFile(path))
|
||||
{
|
||||
writer(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private StorageContainer OpenContainer()
|
||||
{
|
||||
return _storageDevice.Value.EndOpenContainer(_storageDevice.Value.BeginOpenContainer(_game.Name, null, null));
|
||||
}
|
||||
|
||||
private GameBase _game;
|
||||
private Lazy<StorageDevice> _storageDevice = new Lazy<StorageDevice>(() => StorageDevice.EndShowSelector(StorageDevice.BeginShowSelector(null, null)));
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue