|
|
a6a507 |
using System;
|
|
|
a6a507 |
using System.Collections.Generic;
|
|
|
a6a507 |
|
|
|
a6a507 |
namespace Assistance {
|
|
|
a6a507 |
public class KeyHistory<t> where T: IComparable, new() {</t>
|
|
|
a6a507 |
public class Holder: IDisposable {
|
|
|
a6a507 |
public readonly KeyHistory<t> history;</t>
|
|
|
a6a507 |
public readonly long ticks;
|
|
|
a6a507 |
public readonly double timeOffset;
|
|
|
a6a507 |
|
|
|
a6a507 |
private readonly long heldTicks;
|
|
|
a6a507 |
private bool disposed = false;
|
|
|
a6a507 |
|
|
|
a6a507 |
public Holder(KeyHistory<t> history, long ticks, double timeOffset = 0.0) {</t>
|
|
|
a6a507 |
this.history = history;
|
|
|
a6a507 |
this.ticks = ticks;
|
|
|
a6a507 |
this.timeOffset = timeOffset;
|
|
|
a6a507 |
heldTicks = history.hold(ticks);
|
|
|
a6a507 |
}
|
|
|
a6a507 |
|
|
|
a62e15 |
public Holder offset(double timeOffset) {
|
|
|
a62e15 |
return Geometry.isEqual(timeOffset, 0.0)
|
|
|
a62e15 |
? this
|
|
|
a62e15 |
: new Holder(history, ticks, this.timeOffset + timeOffset);
|
|
|
a62e15 |
}
|
|
|
a62e15 |
|
|
|
a6a507 |
public KeyState<t>.Holder get(double time) {</t>
|
|
|
a6a507 |
long dticks = (long)Math.Ceiling(Timer.frequency*(time + timeOffset));
|
|
|
a6a507 |
KeyState<t> state = history.get(ticks + dticks);</t>
|
|
|
a6a507 |
return new KeyState<t>.Holder(state, ticks, timeOffset + time);</t>
|
|
|
a6a507 |
}
|
|
|
a6a507 |
|
|
|
a6a507 |
public void Dispose() {
|
|
|
a6a507 |
Dispose(true);
|
|
|
a6a507 |
GC.SuppressFinalize(this);
|
|
|
a6a507 |
}
|
|
|
a6a507 |
|
|
|
a6a507 |
protected virtual void Dispose(bool disposing) {
|
|
|
a6a507 |
if (disposed) return;
|
|
|
a6a507 |
history.release(heldTicks);
|
|
|
a6a507 |
disposed = true;
|
|
|
a6a507 |
}
|
|
|
a6a507 |
|
|
|
a6a507 |
~Holder()
|
|
|
a6a507 |
{ Dispose(false); }
|
|
|
a6a507 |
}
|
|
|
a6a507 |
|
|
|
a6a507 |
private readonly List<keystate<t>> states = new List<keystate<t>>() { new KeyState<t>() };</t></keystate<t></keystate<t>
|
|
|
a6a507 |
private readonly List<long> locks = new List<long>();</long></long>
|
|
|
a6a507 |
|
|
|
a6a507 |
public KeyState<t> current</t>
|
|
|
a6a507 |
{ get { return states[ states.Count - 1 ]; } }
|
|
|
a6a507 |
|
|
|
589f9a |
public KeyState<t> change(bool press, T value, long ticks) {</t>
|
|
|
a6a507 |
states.Add(current.change(press, value, ticks));
|
|
|
a6a507 |
autoRemove();
|
|
|
589f9a |
return current;
|
|
|
a6a507 |
}
|
|
|
a6a507 |
public KeyState<t> press(T value, long ticks)</t>
|
|
|
a6a507 |
{ return change(true, value, ticks); }
|
|
|
a6a507 |
public KeyState<t> release(T value, long ticks)</t>
|
|
|
a6a507 |
{ return change(false, value, ticks); }
|
|
|
a6a507 |
|
|
|
a6a507 |
private int findLock(long ticks) {
|
|
|
a6a507 |
// locks[a] <= ticks < locks[b]
|
|
|
0f2bf8 |
if (locks.Count == 0) return -1;
|
|
|
a6a507 |
int a = 0;
|
|
|
0f2bf8 |
int b = locks.Count - 1;
|
|
|
589f9a |
if (locks[a] < ticks) return -1;
|
|
|
a6a507 |
if (ticks >= locks[b]) return b;
|
|
|
589f9a |
while(true) {
|
|
|
a6a507 |
int c = (a + b)/2;
|
|
|
a6a507 |
if (a == c) break;
|
|
|
a6a507 |
if (ticks < locks[c]) b = c; else a = c;
|
|
|
a6a507 |
}
|
|
|
a6a507 |
return a;
|
|
|
a6a507 |
}
|
|
|
a6a507 |
|
|
|
a6a507 |
private void autoRemove() {
|
|
|
a6a507 |
long ticks = locks.Count > 0 ? locks[0] : long.MaxValue;
|
|
|
a6a507 |
while(states.Count > 1 && (states[0].ticks < ticks || states[0].isEmpty))
|
|
|
a6a507 |
states.RemoveAt(0);
|
|
|
a6a507 |
}
|
|
|
a6a507 |
|
|
|
a6a507 |
private long hold(long ticks) {
|
|
|
a62e15 |
long heldTicks = Math.Max(ticks, states[0].ticks);
|
|
|
a6a507 |
locks.Insert(findLock(heldTicks) + 1, heldTicks);
|
|
|
a6a507 |
return heldTicks;
|
|
|
a6a507 |
}
|
|
|
a6a507 |
|
|
|
a6a507 |
private void release(long heldTicks) {
|
|
|
a6a507 |
int i = findLock(heldTicks);
|
|
|
a6a507 |
if (i >= 0 && locks[i] == heldTicks) locks.RemoveAt(i);
|
|
|
a6a507 |
autoRemove();
|
|
|
a6a507 |
}
|
|
|
a6a507 |
|
|
|
a6a507 |
private KeyState<t> get(long ticks) {</t>
|
|
|
a6a507 |
// state[a].ticks <= ticks < state[b].ticks
|
|
|
a6a507 |
int a = 0;
|
|
|
a6a507 |
int b = states.Count - 1;
|
|
|
a6a507 |
if (states[a].ticks < ticks) return new KeyState<t>();</t>
|
|
|
589f9a |
if (ticks >= states[b].ticks) return states[b];
|
|
|
589f9a |
while(true) {
|
|
|
a6a507 |
int c = (a + b)/2;
|
|
|
a6a507 |
if (a == c) break;
|
|
|
a6a507 |
if (ticks < states[c].ticks) b = c; else a = c;
|
|
|
a6a507 |
}
|
|
|
a6a507 |
return states[a];
|
|
|
a6a507 |
}
|
|
|
a6a507 |
}
|
|
|
a6a507 |
}
|
|
|
a6a507 |
|