Files
crtr/Assets/Cryville/Common/Unity/Input/InputManager.cs
2022-09-30 17:32:21 +08:00

195 lines
5.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Reflection;
namespace Cryville.Common.Unity.Input {
/*public class InputManager {
int newId = 0;
int GetNewId() {
newId++;
return newId;
}
PointerHandler ptrHandler;
readonly Queue<PointerInfo> ptrEv = new Queue<PointerInfo>();
readonly Dictionary<int, PointerInfo> ptr
= new Dictionary<int, PointerInfo>();
double originTime;
void Callback(int id, PointerInfo info) {
/*if (info.Phase != PointerPhase.Update)
Logger.Log(
"main", 0, "Input",
"[{0}, p{1}] {2} {3} {4} at {5} (cs:{6}, ori:{7}, prs:{8})",
info.EventTime, info.ProcessTime, info.Type,
id, info.Phase, info.Position,
info.ContactSize, info.Orientation, info.Pressure
);*
lock (ptrEv) {
ptrEv.Enqueue(info);
ptr[id] = info;
}
}
public void Init() {
try {
if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
if (WindowsPointerHandler.IsSupported()) {
ptrHandler = new WindowsPointerHandler(true, GetNewId, Callback);
Logger.Log("main", 1, "Input", "Initialized windows pointer handler");
}
else if (UnityTouchHandler.IsSupported()) {
ptrHandler = new UnityTouchHandler(GetNewId, Callback);
Logger.Log("main", 1, "Input", "Initialized multi-platform pointer handler");
}
}
else if (Application.platform == RuntimePlatform.Android) {
/*if (AndroidTouchHandler.IsSupported()) {
}
else*
if (UnityTouchHandler.IsSupported()) {
ptrHandler = new UnityTouchHandler(GetNewId, Callback);
Logger.Log("main", 1, "Input", "Initialized multi-platform pointer handler");
}
}
else {
/*if (UnityPointerHandler.IsSupported()) {
enableUnityTouch();
}*
}
}
catch (Exception ex) {
Logger.Log("main", 4, "Input", "An error occured while initializing pointer handler:\n{0}", ex);
}
if (ptrHandler == null) Logger.Log("main", 3, "Input", "Pointer input is not supported on this device");
}
public void Activate() {
if (ptrHandler != null) ptrHandler.Activate();
}
public void Deactivate() {
if (ptrHandler != null) ptrHandler.Deactivate();
ptr.Clear(); ptrEv.Clear();
}
public void Dispose() {
ptrHandler.Dispose();
}
public void EnumeratePtrEvents(Action<PointerInfo> callback) {
lock (ptrEv) {
while (ptrEv.Count > 0) {
var raw = ptrEv.Dequeue();
raw.OffsetTime(originTime);
callback(raw);
}
}
}
public void EnumeratePointers(Action<PointerInfo> callback) {
lock (ptrEv) {
var upid = new List<int>();
var rmid = new List<int>();
foreach (var p in ptr) {
var raw = p.Value;
if (raw.Phase == PointerPhase.Stationary)
raw.EventTime = raw.ProcessTime = Time;
else raw.OffsetTime(originTime);
callback(raw);
if (raw.Phase == PointerPhase.Begin || raw.Phase == PointerPhase.Update)
upid.Add(p.Key);
if (raw.Phase == PointerPhase.End || raw.Phase == PointerPhase.Cancel)
rmid.Add(p.Key);
}
foreach (var i in upid) {
var p = ptr[i];
p.Phase = PointerPhase.Stationary;
ptr[i] = p;
}
foreach (var i in rmid) ptr.Remove(i);
// Logger.Log("main", 0, "Input", "Ptr count {0}", ptr.Count);
}
}
public double Time {
get {
if (ptrHandler != null) return ptrHandler.GetCurrentTimestamp() - originTime;
else return 0;
}
}
public void SyncTime(double t) {
if (ptrHandler != null) {
originTime = ptrHandler.GetCurrentTimestamp() - t;
Logger.Log("main", 0, "Input", "Sync time {0}", originTime);
}
}
}*/
public class InputManager {
static readonly List<Type> HandlerRegistries = new List<Type> {
typeof(WindowsPointerHandler),
typeof(UnityKeyHandler<UnityKeyboardReceiver>),
typeof(UnityKeyHandler<UnityMouseButtonReceiver>),
typeof(UnityMouseHandler),
typeof(UnityTouchHandler),
};
readonly List<InputHandler> _handlers = new List<InputHandler>();
readonly Dictionary<InputHandler, double> _timeOrigins = new Dictionary<InputHandler, double>();
readonly object _lock = new object();
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;
_handlers.Add(h);
_timeOrigins.Add(h, 0);
Logger.Log("main", 1, "Input", "Initialized {0}", ReflectionHelper.GetSimpleName(t));
}
catch (TargetInvocationException ex) {
Logger.Log("main", 1, "Input", "Cannot initialize {0}: {1}", ReflectionHelper.GetSimpleName(t), ex.InnerException.Message);
}
}
}
public void Activate() {
lock (_lock) {
_events.Clear();
}
foreach (var h in _handlers) h.Activate();
}
public void SyncTime(double time) {
foreach (var h in _handlers) {
_timeOrigins[h] = time - h.GetCurrentTimestamp();
}
}
public void Deactivate() {
foreach (var h in _handlers) h.Deactivate();
}
void Callback(InputIdentifier id, InputVector vec) {
lock (_lock) {
double timeOrigin = _timeOrigins[id.Source.Handler];
vec.Time += timeOrigin;
InputVector vec0;
if (_vectors.TryGetValue(id, out vec0)) {
_events.Add(new InputEvent {
Id = id,
From = vec0,
To = vec,
});
if (vec.IsNull) _vectors.Remove(id);
else _vectors[id] = vec;
}
else {
_events.Add(new InputEvent {
Id = id,
From = new InputVector(vec.Time),
To = vec,
});
_vectors.Add(id, vec);
}
}
}
public void EnumerateEvents(Action<InputEvent> cb) {
lock (_lock) {
foreach (var ev in _events) cb(ev);
_events.Clear();
}
}
}
}