Implement input proxy. Change input callback delegate to event. Prevents repeated (de)activation.

This commit is contained in:
2022-11-06 00:50:09 +08:00
parent 7f02b75b29
commit 8f98cb63cb
7 changed files with 119 additions and 111 deletions

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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();
}
}

View File

@@ -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));
}
}
}

View File

@@ -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));
}
}
}

View File

@@ -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));
}
}