Update Cryville.Input. Fix cleanup logic for input proxy.

This commit is contained in:
2023-05-07 21:30:00 +08:00
parent dad399facf
commit b4984c0b3a
10 changed files with 119 additions and 27 deletions

View File

@@ -148,21 +148,25 @@ namespace Cryville.Crtr {
#region Handling #region Handling
public void Activate() { public void Activate() {
_activeCounts.Clear();
_vect.Clear(); _vecs.Clear(); _vect.Clear(); _vecs.Clear();
foreach (var src in _sproxies) { foreach (var src in _sproxies) {
_activeCounts.Add(src.Key, 0);
var isrc = src.Value.Source; var isrc = src.Value.Source;
if (isrc != null) { if (isrc != null) {
isrc.Value.Handler.OnInput += OnInput; isrc.Value.Handler.OnInput += OnInput;
isrc.Value.Handler.OnBatch += OnBatch;
} }
} }
_targetActiveCount.Clear();
foreach (var i in _ruleset.inputs) {
if (i.Value.pass == null) _targetActiveCount.Add(i.Key, 0);
}
} }
public void Deactivate() { public void Deactivate() {
foreach (var src in _sproxies) { foreach (var src in _sproxies) {
var isrc = src.Value.Source; var isrc = src.Value.Source;
if (isrc != null) { if (isrc != null) {
isrc.Value.Handler.OnInput -= OnInput; isrc.Value.Handler.OnInput -= OnInput;
isrc.Value.Handler.OnBatch -= OnBatch;
} }
} }
} }
@@ -233,7 +237,7 @@ namespace Cryville.Crtr {
} }
} }
readonly Dictionary<InputHandler, double> _timeOrigins = new Dictionary<InputHandler, double>(); readonly Dictionary<InputHandler, double> _timeOrigins = new Dictionary<InputHandler, double>();
readonly Dictionary<InputSource, int> _activeCounts = new Dictionary<InputSource, int>(); readonly Dictionary<Identifier, int> _targetActiveCount = new Dictionary<Identifier, int>();
readonly Dictionary<InputIdentifier, float> _vect = new Dictionary<InputIdentifier, float>(); readonly Dictionary<InputIdentifier, float> _vect = new Dictionary<InputIdentifier, float>();
readonly Dictionary<ProxiedInputIdentifier, PropSrc> _vecs = new Dictionary<ProxiedInputIdentifier, PropSrc>(); readonly Dictionary<ProxiedInputIdentifier, PropSrc> _vecs = new Dictionary<ProxiedInputIdentifier, PropSrc>();
double? _lockTime = null; double? _lockTime = null;
@@ -255,7 +259,7 @@ namespace Cryville.Crtr {
InputProxyEntry proxy; InputProxyEntry proxy;
if (_sproxies.TryGetValue(id.Source, out proxy)) { if (_sproxies.TryGetValue(id.Source, out proxy)) {
_etor.ContextCascadeInsert(); _etor.ContextCascadeInsert();
float ft, tt = (float)(_lockTime != null ? _lockTime.Value : (frame.Time - _timeOrigins[id.Source.Handler])); float ft, tt = (float)GetSyncedTime(frame.Time, id.Source.Handler);
if (!_vect.TryGetValue(id, out ft)) ft = tt; if (!_vect.TryGetValue(id, out ft)) ft = tt;
if (frame.IsNull) { if (frame.IsNull) {
_etor.ContextCascadeUpdate(_var_value, PropSrc.Null); _etor.ContextCascadeUpdate(_var_value, PropSrc.Null);
@@ -299,16 +303,42 @@ namespace Cryville.Crtr {
PropSrc fv, tv = _etor.ContextCascadeLookup(_var_value); PropSrc fv, tv = _etor.ContextCascadeLookup(_var_value);
if (!_vecs.TryGetValue(pid, out fv)) fv = PropSrc.Null; if (!_vecs.TryGetValue(pid, out fv)) fv = PropSrc.Null;
if (fv.Type != PdtInternalType.Null || tv.Type != PdtInternalType.Null) { if (fv.Type != PdtInternalType.Null || tv.Type != PdtInternalType.Null) {
if (fv.Type == PdtInternalType.Null) _activeCounts[id.Source]++; if (fv.Type == PdtInternalType.Null) {
_targetActiveCount[target]++;
}
_etor.ContextCascadeInsert(); _etor.ContextCascadeInsert();
_etor.ContextCascadeUpdate(_var_fv, fv); _etor.ContextCascadeUpdate(_var_fv, fv);
_etor.ContextCascadeUpdate(_var_tv, tv); _etor.ContextCascadeUpdate(_var_tv, tv);
_judge.Feed(target, ft, tt); _judge.Feed(target, ft, tt);
_etor.ContextCascadeDiscard(); _etor.ContextCascadeDiscard();
if (tv.Type == PdtInternalType.Null) _activeCounts[id.Source]--; if (tv.Type == PdtInternalType.Null) {
_vecs.Remove(pid);
_targetActiveCount[target]--;
}
else _vecs[pid] = tv;
} }
}
}
void OnBatch(InputHandler handler, double time) {
lock (_etor) {
foreach (var vec in _vecs) {
if (vec.Key.Source.Source.Handler != handler) continue;
InputProxyEntry proxy;
if (!_sproxies.TryGetValue(vec.Key.Source.Source, out proxy)) continue;
Cleanup(proxy.Target, (float)GetSyncedTime(time, handler));
}
}
}
void Cleanup(Identifier target, float tt, int depth = 0) {
if (depth >= MAX_DEPTH) throw new InputProxyException("Input propagation limit reached\nThe ruleset has invalid input definitions");
var def = _ruleset.inputs[target];
if (def.pass != null) {
foreach (var p in def.pass) {
Cleanup(p.Key, tt, depth + 1);
}
}
else if (_targetActiveCount[target] == 0) {
_judge.Cleanup(target, tt); _judge.Cleanup(target, tt);
_vecs[pid] = tv;
} }
} }
public void SyncTime(double time) { public void SyncTime(double time) {
@@ -317,11 +347,12 @@ namespace Cryville.Crtr {
_timeOrigins[h] = h.GetCurrentTimestamp() - time; _timeOrigins[h] = h.GetCurrentTimestamp() - time;
} }
} }
const double batchDelayTolerance = 0.02;
public void ForceTick() { public void ForceTick() {
foreach (var s in _sproxies) { lock (_etor) {
var src = s.Key; foreach (var s in _sproxies) {
if (_activeCounts[src] == 0) { var handler = s.Key.Handler;
OnInput(new InputIdentifier { Source = src, Id = 0 }, new InputFrame(_lockTime != null ? _lockTime.Value : src.Handler.GetCurrentTimestamp())); Cleanup(s.Value.Target, (float)GetSyncedTime(handler.GetCurrentTimestamp() - batchDelayTolerance, handler));
} }
} }
} }
@@ -333,6 +364,9 @@ namespace Cryville.Crtr {
} }
return result / _sproxies.Count; return result / _sproxies.Count;
} }
double GetSyncedTime(double time, InputHandler handler) {
return _lockTime != null ? _lockTime.Value : (time - _timeOrigins[handler]);
}
public void LockTime() { _lockTime = GetTimestampAverage(); } public void LockTime() { _lockTime = GetTimestampAverage(); }
public void UnlockTime() { _lockTime = null; } public void UnlockTime() { _lockTime = null; }
#endregion #endregion

View File

@@ -42,6 +42,7 @@ namespace Cryville.Input.Unity.Android {
try { try {
double timeSecs = time / 1e9; double timeSecs = time / 1e9;
Feed(0, id, new InputFrame(timeSecs, new InputVector(x, y, z, w))); Feed(0, id, new InputFrame(timeSecs, new InputVector(x, y, z, w)));
Batch(timeSecs);
} }
catch (Exception ex) { catch (Exception ex) {
Logger.Log("main", 4, "Input", "An error occurred while handling an Android sensor event: {0}", ex); Logger.Log("main", 4, "Input", "An error occurred while handling an Android sensor event: {0}", ex);

View File

@@ -42,9 +42,14 @@ namespace Cryville.Input.Unity.Android {
internal override void OnFeed(int id, int action, long time, float x, float y, float z, float w) { internal override void OnFeed(int id, int action, long time, float x, float y, float z, float w) {
try { try {
double timeSecs = time / 1000.0; double timeSecs = time / 1000.0;
Feed(0, id, new InputFrame(timeSecs, new InputVector(x, y))); if (action == -2) {
if (action == 1 /*ACTION_UP*/ || action == 3 /*ACTION_CANCEL*/ || action == 6 /*ACTION_POINTER_UP*/) Batch(timeSecs);
Feed(0, id, new InputFrame(timeSecs)); }
else {
Feed(0, id, new InputFrame(timeSecs, new InputVector(x, y)));
if (action == 1 /*ACTION_UP*/ || action == 3 /*ACTION_CANCEL*/ || action == 6 /*ACTION_POINTER_UP*/)
Feed(0, id, new InputFrame(timeSecs));
}
} }
catch (Exception ex) { catch (Exception ex) {
Logger.Log("main", 4, "Input", "An error occurred while handling an Android touch event: {0}", ex); Logger.Log("main", 4, "Input", "An error occurred while handling an Android touch event: {0}", ex);

View File

@@ -44,6 +44,7 @@ public final class TouchProxy extends Proxy implements View.OnTouchListener {
feed(id, action, time, x, y); feed(id, action, time, x, y);
} }
} }
feed(0, -2, time);
return false; return false;
} }
} }

View File

@@ -20,7 +20,8 @@ namespace Cryville.Input.Unity {
protected override void Activate() { protected override void Activate() {
_receiver = new GameObject("__guiRecv__"); _receiver = new GameObject("__guiRecv__");
_recvComp = _receiver.AddComponent<T>(); _recvComp = _receiver.AddComponent<T>();
_recvComp.SetCallback(Feed); _recvComp.SetFeedCallback(Feed);
_recvComp.SetBatchCallback(Batch);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -63,19 +64,30 @@ namespace Cryville.Input.Unity {
/// <summary> /// <summary>
/// The callback function to be called when a new input frame is received. /// The callback function to be called when a new input frame is received.
/// </summary> /// </summary>
protected Action<int, int, InputFrame> Callback; protected Action<int, int, InputFrame> Feed;
/// <summary>
/// The set of currently active keys.
/// </summary>
protected readonly HashSet<int> ActiveKeys = new HashSet<int>();
/// <summary> /// <summary>
/// Sets the callback function to be called when a new input frame is received. /// Sets the callback function to be called when a new input frame is received.
/// </summary> /// </summary>
/// <param name="h">The callback function to be called when a new input frame is received.</param> /// <param name="h">The callback function to be called when a new input frame is received.</param>
public void SetCallback(Action<int, int, InputFrame> h) { public void SetFeedCallback(Action<int, int, InputFrame> h) {
Callback = h; Feed = h;
} }
/// <summary> /// <summary>
/// The callback function to be called when the current input batch is finished receiving.
/// </summary>
protected Action<double> Batch;
/// <summary>
/// Sets the callback function to be called when the current input batch is finished receiving.
/// </summary>
/// <param name="h">The callback function to be called when the current input batch is finished receiving.</param>
public void SetBatchCallback(Action<double> h) {
Batch = h;
}
/// <summary>
/// The set of currently active keys.
/// </summary>
protected readonly HashSet<int> ActiveKeys = new HashSet<int>();
/// <summary>
/// Gets the friendly name of the specified key. /// Gets the friendly name of the specified key.
/// </summary> /// </summary>
/// <param name="key">The key.</param> /// <param name="key">The key.</param>
@@ -87,8 +99,9 @@ namespace Cryville.Input.Unity {
void Update() { void Update() {
double time = Time.realtimeSinceStartupAsDouble; double time = Time.realtimeSinceStartupAsDouble;
foreach (var k in ActiveKeys) { foreach (var k in ActiveKeys) {
Callback(k, 0, new InputFrame(time, new InputVector())); Feed(k, 0, new InputFrame(time, new InputVector()));
} }
Batch(time);
} }
} }
@@ -105,13 +118,13 @@ namespace Cryville.Input.Unity {
switch (e.type) { switch (e.type) {
case EventType.KeyDown: case EventType.KeyDown:
if (!ActiveKeys.Contains(key)) { if (!ActiveKeys.Contains(key)) {
Callback(key, 0, new InputFrame(time, new InputVector())); Feed(key, 0, new InputFrame(time, new InputVector()));
ActiveKeys.Add(key); ActiveKeys.Add(key);
} }
break; break;
case EventType.KeyUp: case EventType.KeyUp:
ActiveKeys.Remove(key); ActiveKeys.Remove(key);
Callback(key, 0, new InputFrame(time)); Feed(key, 0, new InputFrame(time));
break; break;
} }
} }
@@ -134,13 +147,13 @@ namespace Cryville.Input.Unity {
switch (e.type) { switch (e.type) {
case EventType.MouseDown: case EventType.MouseDown:
if (!ActiveKeys.Contains(key)) { if (!ActiveKeys.Contains(key)) {
Callback(key, 0, new InputFrame(time, new InputVector())); Feed(key, 0, new InputFrame(time, new InputVector()));
ActiveKeys.Add(key); ActiveKeys.Add(key);
} }
break; break;
case EventType.MouseUp: case EventType.MouseUp:
ActiveKeys.Remove(key); ActiveKeys.Remove(key);
Callback(key, 0, new InputFrame(time)); Feed(key, 0, new InputFrame(time));
break; break;
} }
} }

View File

@@ -79,6 +79,7 @@ namespace Cryville.Input.Unity {
double time = Time.realtimeSinceStartupAsDouble; double time = Time.realtimeSinceStartupAsDouble;
Vector3 pos = unity::Input.mousePosition; Vector3 pos = unity::Input.mousePosition;
_handler.Feed(0, 0, new InputFrame(time, new InputVector(pos.x, pos.y))); _handler.Feed(0, 0, new InputFrame(time, new InputVector(pos.x, pos.y)));
_handler.Batch(time);
} }
} }
} }

View File

@@ -86,6 +86,7 @@ namespace Cryville.Input.Unity {
_handler.Feed(0, t.fingerId, new InputFrame(time)); _handler.Feed(0, t.fingerId, new InputFrame(time));
} }
} }
_handler.Batch(time);
} }
} }
} }

Binary file not shown.

View File

@@ -34,6 +34,13 @@
<param name="identifier">The input identifier of <paramref name="frame" />.</param> <param name="identifier">The input identifier of <paramref name="frame" />.</param>
<param name="frame">The new input frame.</param> <param name="frame">The new input frame.</param>
</member> </member>
<member name="T:Cryville.Input.InputBatchHandler">
<summary>
Represents the method that will handle the <see cref="E:Cryville.Input.InputHandler.OnBatch" /> event.
</summary>
<param name="handler">The input handler.</param>
<param name="time">The timestamp of the batch in seconds.</param>
</member>
<member name="T:Cryville.Input.InputHandler"> <member name="T:Cryville.Input.InputHandler">
<summary> <summary>
Input handler. Input handler.
@@ -44,6 +51,11 @@
Occurs when a new input frame is sent. Occurs when a new input frame is sent.
</summary> </summary>
</member> </member>
<member name="E:Cryville.Input.InputHandler.OnBatch">
<summary>
Occurs when an input batch is finished sending.
</summary>
</member>
<member name="M:Cryville.Input.InputHandler.Finalize"> <member name="M:Cryville.Input.InputHandler.Finalize">
<inheritdoc /> <inheritdoc />
</member> </member>
@@ -114,6 +126,12 @@
<param name="id">The ID of the input frame.</param> <param name="id">The ID of the input frame.</param>
<param name="frame">The input frame.</param> <param name="frame">The input frame.</param>
</member> </member>
<member name="M:Cryville.Input.InputHandler.Batch(System.Double)">
<summary>
Marks the end of the current input batch and starts a new batch.
</summary>
<param name="time">The timestamp of the input batch in seconds.</param>
</member>
<member name="T:Cryville.Input.InputIdentifier"> <member name="T:Cryville.Input.InputIdentifier">
<summary> <summary>
Input identifier. Input identifier.

View File

@@ -36,6 +36,13 @@
</param> </param>
<param name="frame">新的输入帧。</param> <param name="frame">新的输入帧。</param>
</member> </member>
<member name="T:Cryville.Input.InputBatchHandler">
<summary>
表示处理 <see cref="E:Cryville.Input.InputHandler.OnBatch" /> 事件的方法。
</summary>
<param name="handler">输入处理器。</param>
<param name="time">输入批次的时间戳(秒)。</param>
</member>
<member name="T:Cryville.Input.InputHandler"> <member name="T:Cryville.Input.InputHandler">
<summary> <summary>
输入处理器。 输入处理器。
@@ -46,6 +53,11 @@
在新的输入帧被发送时发生。 在新的输入帧被发送时发生。
</summary> </summary>
</member> </member>
<member name="E:Cryville.Input.InputHandler.OnBatch">
<summary>
在输入批次完成发送时发生。
</summary>
</member>
<member name="M:Cryville.Input.InputHandler.Finalize"> <member name="M:Cryville.Input.InputHandler.Finalize">
<inheritdoc /> <inheritdoc />
</member> </member>
@@ -124,6 +136,12 @@
<param name="id">输入帧的 ID。</param> <param name="id">输入帧的 ID。</param>
<param name="frame">输入帧。</param> <param name="frame">输入帧。</param>
</member> </member>
<member name="M:Cryville.Input.InputHandler.Batch(System.Double)">
<summary>
将当前的输入批次标记结束并开始新的批次。
</summary>
<param name="time">输入批次的时间戳(秒)。</param>
</member>
<member name="T:Cryville.Input.InputIdentifier"> <member name="T:Cryville.Input.InputIdentifier">
<summary> <summary>
输入标识。 输入标识。