Implement input proxy. Change input callback delegate to event. Prevents repeated (de)activation.
This commit is contained in:
@@ -4,7 +4,7 @@ using UnityEngine;
|
||||
namespace Cryville.Common.Unity.Input {
|
||||
public delegate void InputEventDelegate(InputIdentifier id, InputVector vec);
|
||||
public abstract class InputHandler : IDisposable {
|
||||
public InputEventDelegate Callback { private get; set; }
|
||||
public event InputEventDelegate OnInput;
|
||||
|
||||
~InputHandler() {
|
||||
Dispose(false);
|
||||
@@ -14,15 +14,27 @@ namespace Cryville.Common.Unity.Input {
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public abstract void Activate();
|
||||
public abstract void Deactivate();
|
||||
public bool Activated { get; private set; }
|
||||
public void Activate() {
|
||||
if (Activated) return;
|
||||
Activated = true;
|
||||
ActivateImpl();
|
||||
}
|
||||
protected abstract void ActivateImpl();
|
||||
public void Deactivate() {
|
||||
if (!Activated) return;
|
||||
Activated = false;
|
||||
DeactivateImpl();
|
||||
}
|
||||
protected abstract void DeactivateImpl();
|
||||
public abstract void Dispose(bool disposing);
|
||||
public abstract bool IsNullable(int type);
|
||||
public abstract byte GetDimension(int type);
|
||||
public abstract string GetTypeName(int type);
|
||||
public abstract double GetCurrentTimestamp();
|
||||
protected void OnInput(int type, int id, InputVector vec) {
|
||||
if (Callback != null) Callback(new InputIdentifier { Source = new InputSource { Handler = this, Type = type }, Id = id }, vec);
|
||||
protected void Feed(int type, int id, InputVector vec) {
|
||||
var del = OnInput;
|
||||
if (del != null) del(new InputIdentifier { Source = new InputSource { Handler = this, Type = type }, Id = id }, vec);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -17,12 +17,11 @@ namespace Cryville.Common.Unity.Input {
|
||||
readonly Dictionary<InputIdentifier, InputVector> _vectors = new Dictionary<InputIdentifier, InputVector>();
|
||||
readonly List<InputEvent> _events = new List<InputEvent>();
|
||||
public InputManager() {
|
||||
var cb = new InputEventDelegate(Callback);
|
||||
foreach (var t in HandlerRegistries) {
|
||||
try {
|
||||
if (!typeof(InputHandler).IsAssignableFrom(t)) continue;
|
||||
var h = (InputHandler)ReflectionHelper.InvokeEmptyConstructor(t);
|
||||
h.Callback = Callback;
|
||||
h.OnInput += OnInput;
|
||||
_handlers.Add(h);
|
||||
_timeOrigins.Add(h, 0);
|
||||
Logger.Log("main", 1, "Input", "Initialized {0}", ReflectionHelper.GetSimpleName(t));
|
||||
@@ -46,7 +45,7 @@ namespace Cryville.Common.Unity.Input {
|
||||
public void Deactivate() {
|
||||
foreach (var h in _handlers) h.Deactivate();
|
||||
}
|
||||
void Callback(InputIdentifier id, InputVector vec) {
|
||||
void OnInput(InputIdentifier id, InputVector vec) {
|
||||
lock (_lock) {
|
||||
double timeOrigin = _timeOrigins[id.Source.Handler];
|
||||
vec.Time += timeOrigin;
|
||||
|
@@ -9,19 +9,19 @@ namespace Cryville.Common.Unity.Input {
|
||||
|
||||
public UnityKeyHandler() { }
|
||||
|
||||
public override void Activate() {
|
||||
protected override void ActivateImpl() {
|
||||
receiver = new GameObject("__keyrecv__");
|
||||
recvcomp = receiver.AddComponent<T>();
|
||||
recvcomp.SetCallback(OnInput);
|
||||
recvcomp.SetCallback(Feed);
|
||||
}
|
||||
|
||||
public override void Deactivate() {
|
||||
protected override void DeactivateImpl() {
|
||||
if (receiver) GameObject.Destroy(receiver);
|
||||
}
|
||||
|
||||
public override void Dispose(bool disposing) {
|
||||
if (disposing) {
|
||||
Deactivate();
|
||||
DeactivateImpl();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -12,18 +12,18 @@ namespace Cryville.Common.Unity.Input {
|
||||
}
|
||||
}
|
||||
|
||||
public override void Activate() {
|
||||
protected override void ActivateImpl() {
|
||||
receiver = new GameObject("__mouserecv__");
|
||||
receiver.AddComponent<UnityMouseReceiver>().SetHandler(this);
|
||||
}
|
||||
|
||||
public override void Deactivate() {
|
||||
protected override void DeactivateImpl() {
|
||||
if (receiver) GameObject.Destroy(receiver);
|
||||
}
|
||||
|
||||
public override void Dispose(bool disposing) {
|
||||
if (disposing) {
|
||||
Deactivate();
|
||||
DeactivateImpl();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Cryville.Common.Unity.Input {
|
||||
double time = Time.timeAsDouble;
|
||||
Vector2 pos = unity::Input.mousePosition;
|
||||
pos.y = Screen.height - pos.y;
|
||||
handler.OnInput(0, 0, new InputVector(time, pos));
|
||||
handler.Feed(0, 0, new InputVector(time, pos));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -12,18 +12,18 @@ namespace Cryville.Common.Unity.Input {
|
||||
}
|
||||
}
|
||||
|
||||
public override void Activate() {
|
||||
protected override void ActivateImpl() {
|
||||
receiver = new GameObject("__touchrecv__");
|
||||
receiver.AddComponent<UnityPointerReceiver>().SetHandler(this);
|
||||
}
|
||||
|
||||
public override void Deactivate() {
|
||||
protected override void DeactivateImpl() {
|
||||
if (receiver) GameObject.Destroy(receiver);
|
||||
}
|
||||
|
||||
public override void Dispose(bool disposing) {
|
||||
if (disposing) {
|
||||
Deactivate();
|
||||
DeactivateImpl();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,11 +61,11 @@ namespace Cryville.Common.Unity.Input {
|
||||
pos.y = Screen.height - pos.y;
|
||||
var vec = new InputVector(time, pos);
|
||||
if (t.phase == TouchPhase.Began || t.phase == TouchPhase.Stationary || t.phase == TouchPhase.Moved) {
|
||||
handler.OnInput(0, t.fingerId, vec);
|
||||
handler.Feed(0, t.fingerId, vec);
|
||||
}
|
||||
else if (t.phase == TouchPhase.Ended || t.phase == TouchPhase.Canceled) {
|
||||
handler.OnInput(0, t.fingerId, vec);
|
||||
handler.OnInput(0, t.fingerId, new InputVector(time));
|
||||
handler.Feed(0, t.fingerId, vec);
|
||||
handler.Feed(0, t.fingerId, new InputVector(time));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -56,40 +56,18 @@ namespace Cryville.Common.Unity.Input {
|
||||
}
|
||||
}
|
||||
|
||||
public override void Activate() {
|
||||
RegisterWindowProc(WndProc);
|
||||
if (!NativeMethods.RegisterTouchWindow(hMainWindow, NativeMethods.TOUCH_WINDOW_FLAGS.TWF_WANTPALM)) {
|
||||
throw new InvalidOperationException("Failed to register touch window");
|
||||
}
|
||||
DisablePressAndHold();
|
||||
}
|
||||
|
||||
public override void Deactivate() {
|
||||
EnablePressAndHold();
|
||||
if (!NativeMethods.UnregisterTouchWindow(hMainWindow)) {
|
||||
throw new InvalidOperationException("Failed to unregister touch window");
|
||||
}
|
||||
UnregisterWindowProc();
|
||||
}
|
||||
|
||||
void RegisterWindowProc(WndProcDelegate windowProc) {
|
||||
newWndProc = windowProc;
|
||||
newWndProcPtr = Marshal.GetFunctionPointerForDelegate(newWndProc);
|
||||
oldWndProcPtr = SetWindowLongPtr(hMainWindow, -4, newWndProcPtr);
|
||||
}
|
||||
|
||||
void UnregisterWindowProc() {
|
||||
SetWindowLongPtr(hMainWindow, -4, oldWndProcPtr);
|
||||
newWndProcPtr = IntPtr.Zero;
|
||||
newWndProc = null;
|
||||
}
|
||||
|
||||
public const int TABLET_DISABLE_PRESSANDHOLD = 0x00000001;
|
||||
public const int TABLET_DISABLE_PENTAPFEEDBACK = 0x00000008;
|
||||
public const int TABLET_DISABLE_PENBARRELFEEDBACK = 0x00000010;
|
||||
public const int TABLET_DISABLE_FLICKS = 0x00010000;
|
||||
|
||||
protected void DisablePressAndHold() {
|
||||
protected override void ActivateImpl() {
|
||||
newWndProc = WndProc;
|
||||
newWndProcPtr = Marshal.GetFunctionPointerForDelegate(newWndProc);
|
||||
oldWndProcPtr = SetWindowLongPtr(hMainWindow, -4, newWndProcPtr);
|
||||
if (!NativeMethods.RegisterTouchWindow(hMainWindow, NativeMethods.TOUCH_WINDOW_FLAGS.TWF_WANTPALM)) {
|
||||
throw new InvalidOperationException("Failed to register touch window");
|
||||
}
|
||||
pressAndHoldAtomID = NativeMethods.GlobalAddAtom(PRESS_AND_HOLD_ATOM);
|
||||
NativeMethods.SetProp(hMainWindow, PRESS_AND_HOLD_ATOM,
|
||||
TABLET_DISABLE_PRESSANDHOLD | // disables press and hold (right-click) gesture
|
||||
@@ -99,11 +77,17 @@ namespace Cryville.Common.Unity.Input {
|
||||
);
|
||||
}
|
||||
|
||||
protected void EnablePressAndHold() {
|
||||
protected override void DeactivateImpl() {
|
||||
if (pressAndHoldAtomID != 0) {
|
||||
NativeMethods.RemoveProp(hMainWindow, PRESS_AND_HOLD_ATOM);
|
||||
NativeMethods.GlobalDeleteAtom(pressAndHoldAtomID);
|
||||
}
|
||||
if (!NativeMethods.UnregisterTouchWindow(hMainWindow)) {
|
||||
throw new InvalidOperationException("Failed to unregister touch window");
|
||||
}
|
||||
SetWindowLongPtr(hMainWindow, -4, oldWndProcPtr);
|
||||
newWndProcPtr = IntPtr.Zero;
|
||||
newWndProc = null;
|
||||
}
|
||||
|
||||
const string UnityWindowClassName = "UnityWndClass";
|
||||
@@ -158,7 +142,7 @@ namespace Cryville.Common.Unity.Input {
|
||||
}
|
||||
|
||||
public override void Dispose(bool disposing) {
|
||||
Deactivate();
|
||||
DeactivateImpl();
|
||||
if (usePointerMessage)
|
||||
NativeMethods.EnableMouseInPointer(false);
|
||||
Instance = null;
|
||||
@@ -244,7 +228,7 @@ namespace Cryville.Common.Unity.Input {
|
||||
default: type = 0; break;
|
||||
}
|
||||
if (rawpinfo.pointerFlags.HasFlag(NativeMethods.POINTER_FLAGS.POINTER_FLAG_CANCELED)) {
|
||||
OnInput(type, id, new InputVector(time));
|
||||
Feed(type, id, new InputVector(time));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -253,11 +237,11 @@ namespace Cryville.Common.Unity.Input {
|
||||
switch ((WindowMessages)msg) {
|
||||
case WindowMessages.WM_POINTERDOWN:
|
||||
case WindowMessages.WM_POINTERUPDATE:
|
||||
OnInput(type, id, vec);
|
||||
Feed(type, id, vec);
|
||||
break;
|
||||
case WindowMessages.WM_POINTERUP:
|
||||
OnInput(type, id, vec);
|
||||
OnInput(type, id, new InputVector(time));
|
||||
Feed(type, id, vec);
|
||||
Feed(type, id, new InputVector(time));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -332,11 +316,11 @@ namespace Cryville.Common.Unity.Input {
|
||||
|
||||
if (touch.dwFlags.HasFlag(NativeMethods.TOUCHINPUT_Flags.TOUCHEVENTF_MOVE) ||
|
||||
touch.dwFlags.HasFlag(NativeMethods.TOUCHINPUT_Flags.TOUCHEVENTF_DOWN)) {
|
||||
OnInput(255, id, vec);
|
||||
Feed(255, id, vec);
|
||||
}
|
||||
else if (touch.dwFlags.HasFlag(NativeMethods.TOUCHINPUT_Flags.TOUCHEVENTF_UP)) {
|
||||
OnInput(255, id, vec);
|
||||
OnInput(255, id, new InputVector(time));
|
||||
Feed(255, id, vec);
|
||||
Feed(255, id, new InputVector(time));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,16 +1,28 @@
|
||||
using Cryville.Common.Unity.Input;
|
||||
using Cryville.Common;
|
||||
using Cryville.Common.Pdt;
|
||||
using Cryville.Common.Unity.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Logger = Cryville.Common.Logger;
|
||||
|
||||
namespace Cryville.Crtr {
|
||||
public class InputProxy {
|
||||
readonly PdtEvaluator _etor;
|
||||
readonly PdtRuleset _ruleset;
|
||||
readonly Dictionary<string, InputProxyEntry> _hash1 = new Dictionary<string, InputProxyEntry>();
|
||||
readonly Dictionary<InputSource, InputProxyEntry> _hash2 = new Dictionary<InputSource, InputProxyEntry>();
|
||||
readonly Dictionary<string, InputProxyEntry> _tproxies = new Dictionary<string, InputProxyEntry>();
|
||||
readonly Dictionary<InputSource, InputProxyEntry> _sproxies = new Dictionary<InputSource, InputProxyEntry>();
|
||||
readonly Dictionary<string, int> _use = new Dictionary<string, int>();
|
||||
readonly Dictionary<string, List<string>> _rev = new Dictionary<string, List<string>>();
|
||||
readonly Dictionary<InputIdentifier, InputVector> _vecs = new Dictionary<InputIdentifier, InputVector>();
|
||||
public event EventHandler<ProxyChangedEventArgs> ProxyChanged;
|
||||
public InputProxy(PdtRuleset ruleset) {
|
||||
unsafe {
|
||||
fixed (byte* ptr = _vecbuf) {
|
||||
*(int*)(ptr + 3 * sizeof(float)) = PdtInternalType.Number;
|
||||
}
|
||||
}
|
||||
_etor = ChartPlayer.etor;
|
||||
_ruleset = ruleset;
|
||||
foreach (var i in ruleset.inputs) {
|
||||
_use.Add(i.Key, 0);
|
||||
@@ -23,27 +35,30 @@ namespace Cryville.Crtr {
|
||||
}
|
||||
}
|
||||
}
|
||||
#region Settings
|
||||
public void Set(InputProxyEntry proxy) {
|
||||
var name = proxy.Target;
|
||||
if (_hash1.ContainsKey(name)) Remove(proxy);
|
||||
if (_tproxies.ContainsKey(name)) Remove(proxy);
|
||||
if (_use[proxy.Target] > 0)
|
||||
throw new InvalidOperationException("Input already assigned");
|
||||
if (proxy.Source != null) {
|
||||
_hash1.Add(proxy.Target, proxy);
|
||||
_hash2.Add(proxy.Source.Value, proxy);
|
||||
proxy.Source.Value.Handler.OnInput += OnInput;
|
||||
_tproxies.Add(proxy.Target, proxy);
|
||||
_sproxies.Add(proxy.Source.Value, proxy);
|
||||
IncrementUseRecursive(name);
|
||||
IncrementReversedUseRecursive(name);
|
||||
}
|
||||
}
|
||||
void Remove(InputProxyEntry proxy) {
|
||||
var name = proxy.Target;
|
||||
_hash2.Remove(_hash1[name].Source.Value);
|
||||
_hash1.Remove(name);
|
||||
proxy.Source.Value.Handler.OnInput -= OnInput;
|
||||
_sproxies.Remove(_tproxies[name].Source.Value);
|
||||
_tproxies.Remove(name);
|
||||
DecrementUseRecursive(name);
|
||||
DecrementReversedUseRecursive(name);
|
||||
}
|
||||
public bool IsUsed(InputSource src) {
|
||||
return _hash2.ContainsKey(src);
|
||||
return _sproxies.ContainsKey(src);
|
||||
}
|
||||
void IncrementUseRecursive(string name) {
|
||||
BroadcastProxyChanged(name);
|
||||
@@ -80,8 +95,47 @@ namespace Cryville.Crtr {
|
||||
}
|
||||
}
|
||||
void BroadcastProxyChanged(string name) {
|
||||
ProxyChanged(this, new ProxyChangedEventArgs(name, _hash1.ContainsKey(name) ? _hash1[name].Source : null, _use[name] > 0));
|
||||
ProxyChanged(this, new ProxyChangedEventArgs(name, _tproxies.ContainsKey(name) ? _tproxies[name].Source : null, _use[name] > 0));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Handling
|
||||
public void Activate() { foreach (var src in _sproxies.Keys) src.Handler.Activate(); }
|
||||
public void Deactivate() { foreach (var src in _sproxies.Keys) src.Handler.Deactivate(); }
|
||||
void OnInput(InputIdentifier id, InputVector vec) {
|
||||
InputProxyEntry proxy;
|
||||
if (_sproxies.TryGetValue(id.Source, out proxy)) {
|
||||
OnInput(id, vec, proxy.Target);
|
||||
}
|
||||
}
|
||||
static readonly int _var_value = IdentifierManager.SharedInstance.Request("value");
|
||||
static readonly PropOp.Arbitrary _arbop = new PropOp.Arbitrary();
|
||||
readonly byte[] _vecbuf = new byte[3 * sizeof(float) + sizeof(int)];
|
||||
unsafe void OnInput(InputIdentifier id, InputVector vec, string target) {
|
||||
_etor.ContextCascadeInsert();
|
||||
fixed (byte* ptr = _vecbuf) {
|
||||
*(Vector3*)ptr = vec.Vector;
|
||||
}
|
||||
_etor.ContextCascadeUpdate(_var_value, new PropSrc.Arbitrary(PdtInternalType.Vector, _vecbuf));
|
||||
OnInput(id, target);
|
||||
_etor.ContextCascadeDiscard();
|
||||
}
|
||||
unsafe void OnInput(InputIdentifier id, string target) {
|
||||
var def = _ruleset.inputs[target];
|
||||
if (def.pass != null) {
|
||||
foreach (var p in def.pass) {
|
||||
_arbop.Name = _var_value;
|
||||
_etor.ContextCascadeInsert();
|
||||
_etor.Evaluate(_arbop, p.Value);
|
||||
OnInput(id, p.Key);
|
||||
_etor.ContextCascadeDiscard();
|
||||
}
|
||||
}
|
||||
else {
|
||||
Logger.Log("main", 0, "Input/Proxy", "input recv {0}", target);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class ProxyChangedEventArgs : EventArgs {
|
||||
@@ -100,45 +154,4 @@ namespace Cryville.Crtr {
|
||||
public string Target { get; set; }
|
||||
public byte[] Mapping { get; private set; }
|
||||
}
|
||||
|
||||
public sealed class InputProxyHandler : InputHandler {
|
||||
readonly InputDefinition _def;
|
||||
|
||||
public InputProxyHandler(InputDefinition def, InputHandler src) : base() {
|
||||
_def = def;
|
||||
src.Callback = OnInput;
|
||||
}
|
||||
|
||||
public override void Activate() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Deactivate() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Dispose(bool disposing) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override bool IsNullable(int type) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override byte GetDimension(int type) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override string GetTypeName(int type) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override double GetCurrentTimestamp() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void OnInput(InputIdentifier id, InputVector vec) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user