I've been using the MouseKeyHook NuGet package for a project where a single key press needs to be monitored to provide explicit functionality. The prototype application I have written, checks the required key is pressed and then sets the Handled property to true. The key I'm testing with is LaunchApplication2, now the problem I'm having is the key press isn't always surpressed, at the moment if Microsoft Word or Excel is in focus then the calculator launches!
The code is as follows:
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private IKeyboardMouseEvents keyboardHookListener;
private SolidColorBrush inactiveBrush = new SolidColorBrush(Colors.White);
private SolidColorBrush activeBrush = new SolidColorBrush(Colors.LightGreen);
private bool pressed = false;
public MainWindow()
{
InitializeComponent();
this.Background = inactiveBrush;
this.keyboardHookListener = Hook.GlobalEvents();
this.keyboardHookListener.KeyDown += keyboardHookListener_KeyDown;
this.keyboardHookListener.KeyUp += keyboardHookListener_KeyUp;
}
void keyboardHookListener_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
{
if (e.KeyData == System.Windows.Forms.Keys.LaunchApplication2)
{
if (pressed)
{
this.Background = inactiveBrush;
this.displayLabel.Content = string.Empty;
this.pressed = false;
System.Diagnostics.Debug.WriteLine("*********Finished*********");
}
}
}
void keyboardHookListener_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
// Filter to specific buttons using the KeyData property of the event arguments.
if (e.KeyData == System.Windows.Forms.Keys.LaunchApplication2)
{
e.Handled = true;
e.SuppressKeyPress = true;
// Use a flag to stop code executing multiple times as whilst a key is pressed the KeyDown keeps firing.
if (!pressed)
{
System.Diagnostics.Debug.WriteLine("*********Started*********");
this.pressed = true;
this.Background = activeBrush;
this.displayLabel.Content = e.KeyData.ToString();
}
}
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
this.keyboardHookListener.KeyDown -= this.keyboardHookListener_KeyDown;
this.keyboardHookListener.KeyUp -= this.keyboardHookListener_KeyUp;
this.keyboardHookListener.Dispose();
}
}
I've tried using the SuppressKeyPress property as well but that doesn't have any effect. Any explanations or proposals to fix it would be great!
Related
I'm using KeyDown and KeyUp handlers on Window.Current.CoreWindow to catch keystrokes in a VNC application for UWP. This works great with one exception: alt (VirtualKey.Menu/LeftMenu/RightMenu) never is sent to my application. In addition, alt+letter results in neither being sent to the handlers.
I assume that this is because some accelerator handler is eating these events before they reach CoreWindow. Is there any way around this?
Try to use Dispatcher.AcceleratorKeyActivated instead, it handles Alt key.
Also, it seems there is an issue with CoreWindow. More details on MSDN
Here an example of how I managed to solve this issue in Xamarin Forms.
// A model to store the values of the key event.
public class KeyEventArgs : EventArgs
{
public bool IsAltKeyPressed { get; set; }
public string Key { get; set; }
}
// UWP Custom render
public class MyPageViewRenderer : PageRenderer
{
/// <summary>
/// Monitor windows core ui keypress when MyPageView is showing
/// </summary>
public MyPageViewRenderer() : base()
{
// When ExplorePage appears then attach to the ui core keydown event
Loaded += (object sender, RoutedEventArgs e) =>
{
CoreWindow.GetForCurrentThread().Dispatcher.AcceleratorKeyActivated += Dispatcher_AcceleratorKeyActivated;
};
// When ExplorePage disappears then detach from the ui core keydown event
Unloaded += (object sender, RoutedEventArgs e) =>
{
CoreWindow.GetForCurrentThread().Dispatcher.AcceleratorKeyActivated -= Dispatcher_AcceleratorKeyActivated;
};
}
private void Dispatcher_AcceleratorKeyActivated(CoreDispatcher sender, AcceleratorKeyEventArgs args)
{
if ((args.EventType == CoreAcceleratorKeyEventType.KeyDown || args.EventType == CoreAcceleratorKeyEventType.SystemKeyDown)
&& !args.KeyStatus.WasKeyDown)
{
bool isAltKeyPressed = args.KeyStatus.IsMenuKeyDown;
(Element as MyPageView).MyPageView_KeyPressed(Element, new KeyEventArgs { IsAltKeyPressed = isAltKeyPressed, Key = args.VirtualKey.ToString() });
}
}
}
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MyPageView : ContentPage
{
public MyPageView()
{
InitializeComponent();
this.Focus();
}
public void MyPageView_KeyPressed(object sender, KeyEventArgs e)
{
(this.BindingContext as MyPageViewModel).CommandOnKeyPress?.Execute(e);
}
}
I'm porting an app to Univeral Windows Platform (Windows 10).
Android has a onLongPress event. Is there an equivalent for UWP?
I found there is a Holding event which I tried to use something like this:
private void Rectangle_Holding(object sender, HoldingRoutedEventArgs e)
{
if (e.HoldingState == HoldingState.Started)
{
Debug.WriteLine("Holding started!");
}
}
Problem is the event is not triggered on Windows Desktop, when mouse is used instead of touch.
Mouse input doesn't produce Holding events by default, you should use RightTapped event to show the context menu, it is triggered when user long presses in a touch device and right clicks in a mouse device.
Take a look at GestureRecognizer.Holding and Detect Simple Touch Gestures, you can achieve that using the following code
public sealed partial class MainPage : Page
{
GestureRecognizer gestureRecognizer = new GestureRecognizer();
public MainPage()
{
this.InitializeComponent();
gestureRecognizer.GestureSettings = Windows.UI.Input.GestureSettings.HoldWithMouse;
}
void gestureRecognizer_Holding(GestureRecognizer sender, HoldingEventArgs args)
{
MyTextBlock.Text = "Hello";
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
gestureRecognizer.Holding += gestureRecognizer_Holding;
}
private void Grid_PointerPressed(object sender, PointerRoutedEventArgs e)
{
var ps = e.GetIntermediatePoints(null);
if (ps != null && ps.Count > 0)
{
gestureRecognizer.ProcessDownEvent(ps[0]);
e.Handled = true;
}
}
private void Grid_PointerMoved(object sender, PointerRoutedEventArgs e)
{
gestureRecognizer.ProcessMoveEvents(e.GetIntermediatePoints(null));
e.Handled = true;
}
private void Grid_PointerReleased(object sender, PointerRoutedEventArgs e)
{
var ps = e.GetIntermediatePoints(null);
if (ps != null && ps.Count > 0)
{
gestureRecognizer.ProcessUpEvent(ps[0]);
e.Handled = true;
gestureRecognizer.CompleteGesture();
}
}
}
What method is to be used in order to detect whether a checkbox was touched by a user to change the isChecked status in my windows phone app? In my code I manually set a checkbox on start up and the callback gets fired right away, while I only want to fire the callback if the user interacted with the view.
public CheckBoxPage()
{
InitializeComponent();
AvailableCheckBox.IsChecked = true; //name of the checkbox
}
private void CheckBox_Checked(object sender, RoutedEventArgs e)//event handler
{
MessageBox.Show("Changed");
}
Use a variable to keep track of whether the page is loaded or not and only have the handler do stuff if it's loaded.
private bool _isLoaded = false;
public CheckBoxPage()
{
InitializeComponent();
AvailableCheckBox.IsChecked = true;
_isLoaded = true; // enable the AvailableCheckBox_Checked handler
}
void AvailableCheckBox_Checked(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return; // stop here if not loaded yet
// everything is loaded so let's execute some stuff
MessageBox.Show("Changed");
}
Use the Click method:
private void AvailableCheckBox_Click(object sender, RoutedEventArgs e)
{
if (AvailableCheckBox.IsChecked == true)
{
// Checked
}
}
Add the handler after you've decided if the Checkbox should be checked.
public CheckBoxPage()
{
InitializeComponent();
AvailableCheckBox.IsChecked = true;
AvailableCheckBox.Checked += AvailableCheckBox_Checked;
}
void AvailableCheckBox_Checked(object sender, RoutedEventArgs e)
{
MessageBox.Show("Changed");
}
I have ax windows media player in my windows forms application. When the user double clicks on it, it becomes full screen.
PROBLEM: I want the user to be able to go back to normal screen when he presses the "escape key".
I have put a keydown event on the ax media player. This key down event works when in normal mode, but fails when the media player is made full screen.
WMPLarge.KeyDownEvent += new AxWMPLib._WMPOCXEvents_KeyDownEventHandler(Form1_KeyDown);
private void Form1_KeyDown(object sender, AxWMPLib._WMPOCXEvents_KeyDownEvent e)
{
if (e.nKeyCode == 27)
{
MessageBox.Show("");
WMPLarge.fullScreen = false;
WMPSmall.fullScreen = false;
}
}
How can I achieve this ?
Here is one code snippet I used, I hope that helps.
public partial class Form16 : Form,IMessageFilter
{
public Form16()
{
InitializeComponent();
}
private void Form16_Load(object sender, EventArgs e)
{
this.axWindowsMediaPlayer1.URL = #"D:\MyVideo\myfile.wmv";
Application.AddMessageFilter(this);
}
private void Form16_FormClosing(object sender, FormClosingEventArgs e)
{
Application.RemoveMessageFilter(this);
}
#region IMessageFilter Members
private const UInt32 WM_KEYDOWN = 0x0100;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_KEYDOWN)
{
Keys keyCode = (Keys)(int)m.WParam & Keys.KeyCode;
if (keyCode == Keys.Escape)
{
this.axWindowsMediaPlayer1.fullScreen = false;
}
return true;
}
return false;
}
#endregion
}
I have a checkbox shown as button. I want to make it flash when it is checked. From what Ive found, i think the simplest way is to use a timer to rotate the background color of the button.
Where I am stuck is finding the back color of the checked button. Can someone tell me what the back color is changed to by default (via designer) when the button is checked? Without that I cannot get the timer to begin the oscillation.
What I have is a Mute Button. When the mute is active i want the button to flash until it is pressed again to turn the mute off.
In case I'm wrong and the back color actually does not change, what changes about the button to make it appear pressed?
code:
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
instructorTimer.Enabled = true;
}
private void instructorTimer_Tick(object sender, EventArgs e)
{
// interval is 2000
if (checkBox1.BackColor == System.Drawing.SystemColors.Control)
checkBox1.BackColor = System.Drawing.SystemColors.ControlDark;
else
checkBox1.BackColor = System.Drawing.SystemColors.Control;
}
Maybe SystemColors.Control is what you are looking for.
Make sure you have the tick event hooked up. It looks suspect:
private void Form1_Load(object sender, EventArgs e) {
timer1.Tick += instructorTimer_Tick;
}
I would also change the color immediately, for instant feedback:
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
checkBox1.BackColor = SystemColors.ControlDark;
timer1.Enabled = true;
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
checkBox1.BackColor = Color.Green;
Application.DoEvents();
TimeSpan ts = new TimeSpan();
do
{
}
while (ts.Milliseconds == 2000);
checkBox1.BackColor = SystemColors.Control;
}
If you're willing to use a UserControl instead of trying to repurpose Button - the following should work great and you can extend it if something doesn't work like you like:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace FlashyButton
{
public partial class FlashyButton : UserControl
{
private CheckState _Checked = CheckState.Unchecked;
[Browsable(true)]
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
lblText.Text = value;
Invalidate();
}
}
public FlashyButton()
{
this.CausesValidation = true;
InitializeComponent();
lblText.MouseClick += (sender, e) => { OnMouseClick(null); };
}
public void SetFont(Font WhichFont)
{
this.Font = WhichFont;
}
public CheckState GetCheckedState()
{
return this._Checked;
}
public void SetCheckedState(CheckState NewCheckState)
{
this._Checked = NewCheckState;
}
protected override void OnMouseClick(MouseEventArgs e)
{
this._Checked = (this._Checked == CheckState.Checked) ? CheckState.Unchecked : CheckState.Checked;
this.BorderStyle = (this._Checked == CheckState.Checked) ? System.Windows.Forms.BorderStyle.Fixed3D : System.Windows.Forms.BorderStyle.FixedSingle;
tmrRedraw.Enabled = (this._Checked == CheckState.Checked);
if (this._Checked == CheckState.Unchecked)
{
this.BackColor = SystemColors.Control;
}
this.Invalidate(); //Force redraw
base.OnMouseClick(e);
}
private float Percent = 100;
private void tmrRedraw_Tick(object sender, EventArgs e)
{
Percent -= 2;
if (Percent < -100) Percent = 100;
this.BackColor = Color.FromArgb(
255,
Lerp(255, SystemColors.Control.R, (int)Math.Abs(Percent)),
Lerp(0, SystemColors.Control.G, (int)Math.Abs(Percent)),
Lerp(0, SystemColors.Control.B, (int)Math.Abs(Percent))
);
}
private int Lerp(int Start, int End, int Percent)
{
return ((int) ((float)(End - Start) * ((float)Percent / 100f)) + Start);
}
}
}
And here is the .Designer code as well (just replace what you already have when you make a new control by this name)
namespace FlashyButton
{
partial class FlashyButton
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.lblText = new System.Windows.Forms.Label();
this.tmrRedraw = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// lblText
//
this.lblText.AutoSize = true;
this.lblText.Location = new System.Drawing.Point(4, 4);
this.lblText.Name = "lblText";
this.lblText.Size = new System.Drawing.Size(55, 17);
this.lblText.TabIndex = 0;
this.lblText.Text = "Sample";
//
// tmrRedraw
//
this.tmrRedraw.Interval = 10;
this.tmrRedraw.Tick += new System.EventHandler(this.tmrRedraw_Tick);
//
// FlashyButton
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoSize = true;
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.Controls.Add(this.lblText);
this.Name = "FlashyButton";
this.Size = new System.Drawing.Size(148, 148);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label lblText;
private System.Windows.Forms.Timer tmrRedraw;
}
}
This worked for me when I had a CheckBox with Appearance = Button and FlatStyle = Flat and wanted it flashing when checked:
private void timer_Flashing_Tick(object sender, EventArgs e)
{
if (checkBox_Refresh.Checked)
{
if (checkBox_Refresh.FlatAppearance.CheckedBackColor == Color.Red)
{
checkBox_Refresh.FlatAppearance.CheckedBackColor = Color.Transparent;
}
else
{
checkBox_Refresh.FlatAppearance.CheckedBackColor = Color.Red;
}
}
}