I am trying to adopt solution from Rx observable which publishes a value if certain timeout expires to detect when user presses and releases the Shift key on the form. Because it is a modifier key it doesn't fire up/down evens, especially when focus is on labels.
The idea is to use and reset timer on every key data (which is fired very often).
Project is .Net 4.8 WinForms app. Code:
public partial class Form1 : Form
{
private readonly Subject<bool> _shiftObservable;
public Form1()
{
InitializeComponent();
_shiftObservable = new Subject<bool>();
}
private void Form1_Load(object sender, EventArgs e)
{
lblCurrent.Text = "Load.";
// https://stackoverflow.com/questions/23394441/rx-observable-which-publishes-a-value-if-certain-timeout-expires?noredirect=1&lq=1
var statusSignal = _shiftObservable
.Select(st => st)
.Publish()
.RefCount();
// An observable that produces "bad" after a delay and then "hangs indefinately" after that
var badTimer = Observable
.Return(false)
.Delay(TimeSpan.FromMilliseconds(200))
.Concat(Observable.Never<bool>());
// A repeating badTimer that resets the timer whenever a good signal arrives.
// The "indefinite hang" in badTimer prevents this from restarting the timer as soon
// as it produces a "bad". Which prevents you from getting a string of "bad" messages
// if the statusProvider is silent for many minutes.
var badSignal = badTimer.TakeUntil(statusSignal).Repeat();
// listen to both good and bad signals.
var res = Observable
.Merge(statusSignal, badSignal)
.DistinctUntilChanged()
.Replay(1)
.RefCount()
.ObserveOn(this)
.Subscribe(OnNext, OnError, OnCompleted);
}
private void OnNext(bool state) => lblCurrent.Text = state ? "1" : "0"; // Must be on GUI!
private void OnError(Exception ex) => Debug.WriteLine("Exception!");
private void OnCompleted() => Debug.WriteLine("Completed!");
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.Shift | Keys.ShiftKey))
{
_shiftObservable.OnNext(true);
return true; //return true if you want to suppress the key.
}
return base.ProcessCmdKey(ref msg, keyData);
}
Q1: The problem is that there is the is one "false" event that I can't figure out. When the shift is pressed, it should go "0 -> 1", but it goes "0 -> 1 -> 0 -> 1 ".
Q2: When I run the code, I see those lines go very fast. I understand that I need to specify the scheduler, but not able to find where. Or should I just ignore it?
The thread 0x6d24 has exited with code 0 (0x0).
The thread 0x5180 has exited with code 0 (0x0).
The thread 0x64c8 has exited with code 0 (0x0).
The thread 0x5298 has exited with code 0 (0x0).
The thread 0x3200 has exited with code 0 (0x0).
The thread 0x1c70 has exited with code 0 (0x0).
P.S.: topic is not that descriptive :/