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);
}
}
Related
I am using IStylusSyncPlugin added to RealTimeStylus plugins to get X,Y,Pressure and timer tick from stylus. This works fine until the window on which I collect this data loses focus. After that, even if focus get back to window, the StylusSyncPlugin does not receiving data. Do anyone have any idea what can i do, to fix this problem? I've found, that stylus events from main window (for ex. PreviewStylusMove) are still firing, but points from these events does not contains timestamp.
A simple code example which could be helpful to reproduce this issue:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
RealTimeStylus rts = new RealTimeStylus(new WindowInteropHelper(this).Handle);
rts.AsyncPluginCollection.Add(new SyncStylusPlugin());
rts.Enabled = true;
}
class SyncStylusPlugin : IStylusSyncPlugin
{
public DataInterestMask DataInterest => DataInterestMask.Packets;
public void Packets(RealTimeStylus sender, PacketsData data)
{
Console.WriteLine("Packets arrived");
}
public void StylusDown(RealTimeStylus sender, StylusDownData data) { }
public void StylusUp(RealTimeStylus sender, StylusUpData data) { }
public void CustomStylusDataAdded(RealTimeStylus sender, CustomStylusData data) { }
public void Error(RealTimeStylus sender, ErrorData data) { }
public void InAirPackets(RealTimeStylus sender, InAirPacketsData data) { }
public void RealTimeStylusDisabled(RealTimeStylus sender, RealTimeStylusDisabledData data) { }
public void RealTimeStylusEnabled(RealTimeStylus sender, RealTimeStylusEnabledData data) { }
public void StylusButtonDown(RealTimeStylus sender, StylusButtonDownData data) { }
public void StylusButtonUp(RealTimeStylus sender, StylusButtonUpData data) { }
public void StylusInRange(RealTimeStylus sender, StylusInRangeData data) { }
public void StylusOutOfRange(RealTimeStylus sender, StylusOutOfRangeData data) { }
public void SystemGesture(RealTimeStylus sender, SystemGestureData data) { }
public void TabletAdded(RealTimeStylus sender, TabletAddedData data) { }
public void TabletRemoved(RealTimeStylus sender, TabletRemovedData data) { }
}
}
I've found, that click on application icon at taskbar making RealTimeStylus work again. Is there any way to fire the same events like mouse do when clicking on this icon? Which events should be fired?
EDIT:
During reading microsoft docs about RealTimeStylus I've found, that "When you create a RealTimeStylus object, you have the option of attaching it to a window handle or to a control. Attaching the RealTimeStylus object to a window handle requires additional permissions. For more information about these permissions, see Partial Trust Considerations for the StylusInput APIs." "The RealTimeStylus that takes the handle parameter requires the UIPermissionWindow.AllWindows and SecurityPermissionFlag.UnmanagedCode permissions, in addition to the permissions required by the constructor that takes the attachedControl parameter." Do anyone know how to check, if Window has these permissions, and how to track them to check if Window loses them sometimes on focus lost?
EDIT2:
I tried to set UIPermission by adding [UIPermission(SecurityAction.Demand, Window =UIPermissionWindow.AllWindows)] to main window class and also by setting new UIPermission(UIPermissionWindow.AllWindows).Demand(); in main window constructor, but it changes nothing.
EDIT3:
Next thing that I have noticed is that, the StylusInRange and StylusOutOfRange events are working everytime, even if window has no focus.
I have a WinForms application wherein I have my main application with a separate class that is part of the solution. In the class which is defining a User control with Dev Express buttons, I have defined my event delegate, event, method and eventargs.
In the main program, i have defined my listener.
I am getting a null value in my event method and cannot see why. I have reviewed this a number of times and as far as I can see, it is completely correct.
I would appreciate any comments/corrections that would be useful here.
This is the code in my class.
public partial class XtraUserControl1 : XtraUserControl, IAnyControlEdit
{
public delegate void ButtonClickedEventHandler(object sender, ClickEventArgs e);
public event ButtonClickedEventHandler ButtonClicked;
public XtraUserControl1()
{
InitializeComponent();
}
public void OnButtonClicked(ClickEventArgs e)
{
if (ButtonClicked != null)
{
ButtonClicked(this, e);
}
}
public class ClickEventArgs : EventArgs
{
public readonly SimpleButton buttonClicked;
public ClickEventArgs(SimpleButton button)
{
this.buttonClicked = button;
}
}
This is the main code where I have defined the listener.
private void frmEHHeaders_Load(object sender, EventArgs e)
{
// Create the button group from the User Control XtraUserControl1 and add it to the grid repository
btnGroup = new User_Controls.XtraUserControl1();
RepositoryItemAnyControl riAny = new RepositoryItemAnyControl();
riAny.Control = btnGroup;
grdEHHeaders.RepositoryItems.Add(riAny);
colButtons.ColumnEdit = riAny;
// Add event handlers
this.grdEHHeaders.Views[0].MouseDown += gridView1_MouseDown;
gridView1.CustomRowCellEdit += GridView1_CustomRowCellEdit;
// Listener for the button class
btnGroup.ButtonClicked += new User_Controls.XtraUserControl1.ButtonClickedEventHandler(btnGroup_ButtonClicked);
GetData();
}
private void btnGroup_ButtonClicked(object sender, User_Controls.XtraUserControl1.ClickEventArgs e )
{
SimpleButton myButton = e.buttonClicked;
MessageBox.Show("You clicked " + myButton.Text);
}
I have 2 forms, UserInterface and Client I'm passing checkbox2.Checked info to Client but it only works however it was at launch. When I tick or untick and close and reopenClient it wont notice the change.
Modifiers is Public on checkbox2 at UserInterface form.
Here is Client code:
public partial class Client : Form
{
private UserInterface ui1;
public Client()
{
InitializeComponent();
}
public void CheckBoxCheck()
{
if (ui1.checkBox2.Checked == true)
{
MessageBox.Show("true");
}
else
{
MessageBox.Show("false");
}
}
}
If the checkbox is ticked at launch Client will show "true" but if I click it (untick) and run Client it will still show "true".
What do I need to add or modify so checkbox2 will be updated in realtime. Thank you.
Note: I'm pretty new with coding, explanations are appreciated.
I'll be building on noMad17's answer, you have to subscribe to your CheckBox event in your UserInterface form. But the change is that now we will send the CheckBox that was clicked in the event. So this code is for your UserInterface form:
public event EventHandler SomeEvent;
protected void OnSomeEvent(object sender, EventArgs e)
{
EventHandler eh = SomeEvent;
if(eh != null)
{
eh(sender, e);
}
}
private void checkBox2_CheckedChanged(object sender, EventArgs e)
{
OnSomeEvent(sender, e);
}
Now for the Client, it needs to know what a UserInterface is so we have to pass UserInterface to the Client in the constructor, otherwise it won't initialize. Also here we are gonna work out the CheckBox event that the parent form is gonna give us. And in the end we have to unsubscribe the event. So this code is for your Client:
public partial class Client : Form
{
private UserInterface ui1;
public Client(UserInterface ui1)
{
InitializeComponent();
this.ui1 = ui1;
ui1.SomeEvent += UI1_SomeEvent;
}
private void UI1_SomeEvent(object sender, EventArgs e)
{
//Your code...
CheckBox c = sender as CheckBox;
if(c.Checked == true)
{
MessageBox.Show("true");
}
else
{
MessageBox.Show("false");
}
}
private void Client_FormClosing(object sender, FormClosingEventArgs e)
{
ui1.SomeEvent -= UI1_SomeEvent;
}
}
Your Forms should be connected. It looks like ui1 is a different instance of UserInterface form.
There are different approaches to pass the data between forms and it depends on your demands.
For instance you could create UserInterface form inside of Client. And use the Show() method to show it.
You should probably be making use of the Checkbox.Checked event inside UserInterface class and then fire a custom event that your Client can subscribe to.
public event EventHandler<EventArgs> CheckboxCheckedChanged;
protected void OnCheckboxCheckedChanged(EventArgs e)
{
if (CheckboxCheckedChanged != null)
CheckboxCheckedChanged(this, e);
}
private void checkbox2_CheckedChanged(object sender, EventArgs e)
{
OnCheckboxCheckedChanged(e);
}
And then in Client:
ui1.CheckboxCheckedChanged += ui1_CheckboxCheckedChanged;
private void ui1_CheckboxCheckedChanged(object sender, CheckBoxEventArgs e)
{
// Your code here
}
I have a form with two controls A and B
, A has a key-down event and i show a message box when 'S' is pressed on A control.
And i want to show another message when 'S' is pressed in any other control.
how can I do this ?
Simply what I want is : I should be able to handle a Key-down event after all child controls.
and I should be able to know whether the Event is handle in a child control in Form-level Key-down.
I tried enabling Key-preview but when Key-preview is enabled Form-level event get's fired before child control events. I want child controls first, Then Form level one
I want form level Event to be fired after focused control's key down event is fired.
and I want to check in Form-level event whether the event is handled in focused controls key-down event.
What methods can I use for this ?
Please enlighten me.
you can do the following
here a sample code
Add new project call it EventSample
Add a UserControl call it AControl
Add a UserControl call it BControl
make the AControl BackColor Blue and BControl Red in order to
distinguish from the form
//Form1 code
namespace EventSample
{
public delegate void AfterChildEventHandler(Control control,Keys key);
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
aControl1.OnChildFireEvent += OnChildFireEvent;
bControl1.OnChildFireEvent += OnChildFireEvent;
}
void OnChildFireEvent(Control control, Keys key)
{
MessageBox.Show("Form fired event from " + control.GetType().Name);
}
}
}
//AControl code
namespace EventSample
{
public partial class AControl : UserControl
{
public event AfterChildEventHandler OnChildFireEvent;
public AControl()
{
InitializeComponent();
}
private void AControl_KeyDown(object sender, KeyEventArgs e)
{
MessageBox.Show("A Control fired Key down");
if (OnChildFireEvent != null)
OnChildFireEvent(this, e.KeyCode);
}
}
}
//BControl code
public partial class BControl : UserControl
{
public event AfterChildEventHandler OnChildFireEvent;
public BControl()
{
InitializeComponent();
}
private void BControl_KeyDown(object sender, KeyEventArgs e)
{
MessageBox.Show("B Control fired Key down");
if (OnChildFireEvent != null)
OnChildFireEvent(this, e.KeyCode);
}
}
EDITED
another solution you can make it with less code
define a static event
handle this event inside the form
let each control to invoke this event
namespace EventSample
{
public delegate void AfterChildEventHandler(Control control, Keys key);
public class GlobalEvent
{
public static event AfterChildEventHandler OnChildEventFire;
public static void Invoke(Control control, Keys key)
{
if (OnChildEventFire != null)
OnChildEventFire(control, key);
}
}
}
changes in the A Control
namespace EventSample
{
public partial class AControl : UserControl
{
public AControl()
{
InitializeComponent();
}
private void AControl_KeyDown(object sender, KeyEventArgs e)
{
MessageBox.Show("A Control fired Key down");
GlobalEvent.Invoke(this, e.KeyCode);
}
}
}
changes in the B Control
namespace EventSample
{
public partial class BControl : UserControl
{
public BControl()
{
InitializeComponent();
}
private void BControl_KeyDown(object sender, KeyEventArgs e)
{
MessageBox.Show("B Control fired Key down");
GlobalEvent.Invoke(this, e.KeyCode);
}
}
}
Build the sample and run and try to press any key on A or B then you will find that A will fire then the form
hope it will help you
Here is my class with event handler:
public delegate void MyKeyEventHandler(object sender, KeyEventArgs e);
public class KeyEvent
{
public event MyKeyEventHandler keyEvent;
public string key = "";
protected virtual void KeyPressed(KeyEventArgs e)
{
MyKeyEventHandler handler = keyEvent;
if (handler != null)
handler(this, e);
}
public KeyEvent()
{
keyEvent += new MyKeyEventHandler(keyPressed);
}
private void keyPressed(object sender, KeyEventArgs e)
{
key = e.KeyCode.ToString();
}
}
And in my Form1 I have this code: (EDITED)
KeyEvent ke = new KeyEvent();
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(ke.key);
}
When I run form and press key on keyboard and then click on button it pop up empty MessageBox. What I want is everytime I press a key on keyboard a MessageBox to pop up and show me which key I pressed. This code is just for testing, I don't want just to pop up message box, I need the key for other things.
Note: To handle the events on Form1 is not a solution, I need to handle the events in class. I making a libray.
It will not be possible for you to create a class that is capable of just automatically listening for events generated by its parent. How would that work? What would happen if you created a new KeyEvent class using something that wasn't a Form and didn't raise events?
You are going to need to give your KeyEvent class a reference to whatever thing that you want to monitor key events for. I realize that your intention is to create some third-party library, so you'd like to keep things as generic as possible in order to maximize its reuse. Since you are dependent on the KeyDown event, using Control is the most generic you can be. This is because it is where the KeyDown event is actually defined.
Let me show you what I mean...
1) Modify the constructor of your KeyEvent class to accept an instance of Control
public class KeyEvent
{
// You don't need to declare an internal event
public string key = "";
private Control _control;
public KeyEvent(Control control)
{
// Here is where we save the reference of Control that was passed to the class.
// This will enable you to access the instance of the Form or whatever else
// you want to use, which is helpful for unregistering events during cleanup
_control = control;
// Wire up your event handler to this SPECIFIC instance of Control.
// This will cause your `keyPressed` method to execute whenever
// the control raises the KeyDown event. All of the middleman
// event handling you are doing is unnecessary.
_control.KeyDown += keyPressed;
}
private void keyPressed(object sender, KeyEventArgs e)
{
key = e.KeyCode.ToString();
}
}
2) Modify the parent in which you are creating this KeyEvent to pass itself into the KeyEvent
// Now you pass 'this' into the constructor. This can be a Form, or any other
// Winforms control that may inherit from Control (which is all of them)
KeyEvent ke = new KeyEvent(this);
private void button1_Click(object sender, EventArgs e)
{
// At this point, ke.Key will always display the last
// key pressed in the Form when the button is clicked.
MessageBox.Show(ke.key);
}
You can do something like this:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 f = new Form1();
f.KeyPreview = true;
f.KeyDown += f_KeyDown;
Application.Run(f);
}
static void f_KeyDown(object sender, KeyEventArgs e)
{
MessageBox.Show(e.KeyValue.ToString());
}
}
If you enable KeyPreview you will receive all keyDowns even of the controls placed on the Form. If you set it to false you only get the KeyDown when the Form has focus.
As you can see in the code you can connect any KeyDownEventHandler method in any class to the Form.
As there where questions left:
public class FormKeyListener
{
private Form formToListen = null;
public void SetFormToListen(Form form)
{
if (formToListen != null)
formToListen.KeyDown -= formToListen_KeyDown; // Unregister from old form if present
formToListen = form;
formToListen.KeyDown += formToListen_KeyDown; // Attach to new form
}
void formToListen_KeyDown(object sender, KeyEventArgs e)
{
MessageBox.Show(e.KeyValue.ToString());
}
}
Which can be call this way somewhere in your code:
FormKeyListener fkl = new FormKeyListener();
Form1 f = new Form1();
f.KeyPreview = true;
fkl.SetFormToListen(f);