using System.Security.Principal;
using Mindmagma.Curses;
namespace ANSI_Fahrplan;
public class InputHandler {
///
/// Handler called by the input handler routine when a key is pressed
///
/// Sender object of event callback
/// Event arguments with details like the pressed key code
public delegate void KeypressEventHandler (object sender, NCursesKeyPressEventArgs e);
// Event fired when key is pressed
public event KeypressEventHandler? OnKeyPress;
// Similar to OnKeyPress, but called before any regular OnKeyPress event handlers are called
public event KeypressEventHandler? OnKeyPressPrivileged;
// When this variable is set, no event handlers will be called except this one
// Once e.CancelNextEvent is true from this event, it will be set to null again
private KeypressEventHandler? _rawKeyPressHandler;
public KeypressEventHandler? RawKeyPressHandler { get { return _rawKeyPressHandler; }}
private nint _targetWindow;
public nint TargetWindow { get { return _targetWindow; }}
private CancellationTokenSource? listeningRoutineCts;
private Task? listeningTask;
///
/// Class constructor
///
/// Window for which to listen to key presses
public InputHandler (nint targetWindow) {
_targetWindow = targetWindow;
}
///
/// Start listening to key presses and call registered callbacks
/// Window to listen to key presses in
///
public void StartListening () {
if (IsListening ()) return;
listeningRoutineCts = new CancellationTokenSource ();
listeningTask = Task.Run (_ListeningRoutine);
while (listeningTask.Status == TaskStatus.WaitingToRun) Thread.Sleep (50);
}
///
/// Stop listening to key presses
///
public void StopListening () {
if (! IsListening ()) return;
if (listeningRoutineCts is null) return;
if (listeningTask is null) return;
listeningRoutineCts.Cancel ();
listeningTask.Wait ();
listeningTask = null;
NCurses.Keypad (TargetWindow, false);
}
///
/// Returns the current listening status of the input event handler
///
/// True if the event handler routine is listening to key presses
public bool IsListening () {
return listeningTask is not null && (
listeningTask.Status == TaskStatus.Running ||
listeningTask.Status == TaskStatus.WaitingForActivation
);
}
///
/// Enable temporary raw keypress event handler to forward
/// all keypressed directly to a specific function
///
/// Event handler to pass key presses to
/// Screen to pass key char duty to
public void EnableRawEventHandler (KeypressEventHandler eventHandler, nint? window = null) {
if (window is not null) {
StopListening ();
_targetWindow = (nint) window;
StartListening ();
}
_rawKeyPressHandler = eventHandler;
}
///
/// Disables the temporary raw keypress event handler
/// Screen to pass key char duty back to
///
public void DisableRawEventHandler (nint? screen = null) {
if (RawKeyPressHandler is null) return;
if (screen is not null) {
StopListening ();
_targetWindow = (nint) screen;
StartListening ();
}
_rawKeyPressHandler = null;
}
///
/// Prepares the window for proper key press reading
///
private void WindowSetup () {
NCurses.Keypad (TargetWindow, true);
NCurses.NoDelay (TargetWindow, false);
}
///
/// Actual keypress handler being called as Task by StartListening ()
///
private void _ListeningRoutine () {
if (listeningRoutineCts is null) return;
WindowSetup ();
while (!listeningRoutineCts.Token.IsCancellationRequested) {
int keyCode = NCurses.WindowGetChar (TargetWindow);
// Do nothing until the key code is larger than -1
if (keyCode < 0) continue;
var eventArgs = new NCursesKeyPressEventArgs (keyCode, TargetWindow);
// If enabled, forward all key pressed directly to raw keypress event handler
if (RawKeyPressHandler is not null) {
RawKeyPressHandler (this, eventArgs);
continue;
}
var skipRegularEventHandlers = false;
// Handle any registered privileged key handlers
if (OnKeyPressPrivileged is not null) {
foreach (KeypressEventHandler h in OnKeyPressPrivileged.GetInvocationList ()) {
h (this, eventArgs);
if (eventArgs.CancelNextEvent == true) {
skipRegularEventHandlers = true;
break;
}
}
}
// Handle any regular registered key handlers
if (OnKeyPress is not null && !skipRegularEventHandlers) {
foreach (KeypressEventHandler h in OnKeyPress.GetInvocationList ()) {
h (this, eventArgs);
if (eventArgs.CancelNextEvent == true) continue ;
}
}
}
listeningRoutineCts.Dispose ();
listeningRoutineCts = null;
}
}
public class NCursesKeyPressEventArgs : EventArgs {
private int _keyCode;
public int KeyCode { get { return _keyCode; }}
private nint _targetWindow;
public nint TargetWindow { get { return _targetWindow; }}
public bool CancelNextEvent { get; set; } = false;
public NCursesKeyPressEventArgs (int keyCode, nint targetWindow) {
_keyCode = keyCode;
_targetWindow = targetWindow;
}
}