I am quite new to c#, and the first thing i want to do is being familiar with that environment by trying Key's Combination Events.
In particular, alt+k.
I'm working on Microsoft Visual c# 2010 Express.
I want to test if that code works.
If errors are found, please notify me :)
public void begin(object sender, KeyEventArgs ev)
{
if (ev.KeyCode == Keys.K && ev.Modifiers == Keys.Alt)
{
//display a message
}
}
but even if I know theoretically what are the different models of projects that are proposed when clicking on new project and what are their uses, I tried unsuccessfully several models to test that code.
In short, i don't know what models to choose and where to put code for testing that kind of simple code, and more precisely working on events(key+mouse) with a minimalist gui.
Someone could help me to tell me how to concretly get started with events stuff in c#?
Thks in advance :)
The MSDN Documentation has a good example of what you need to do. Here are a few important parts:
Start with a simple "Windows Forms" application. While there are many other types of applications, WinForms is the simplest to start with.
Wire up the KeyPress event. In the Form constructor, you need to tell it what to do when it gets a KeyPress event. If you change the name of your function begin in your question above to Form1_KeyPress (to more-accurately describe what it does), the following code should work:
this.KeyPress += new KeyPressEventHandler(Form1_KeyPress);
Use KeyPressEventArgs instead of KeyEventArgs. It may or may not make a huge difference, but it is good to use the most-specific EventArgs when you can so you can use properties specific to it.
Pay attention to KeyPressEventArgs.Handled. If you have KeyPress (or some other keyboard events) on other objects on your forms, such as buttons or text boxes, you need to say whether the event was handled there or whether it should bubble up to the parent (in your case, to the Form).
EDIT (Thanks #RBarryYoung):
Set this.KeyPreview = true in the form constructor. In order for your form to receive keyboard events that happen on child controls (such as buttons and text boxes) as mentioned in the tip immediately above this one, you need to set this property to true to allow the form to get a first look at Keyboard events that happen on the child. (Note: of course, this tip and the previous one only apply if you want the form to see these events. Sometimes, you might want keyboard shortcuts to be trapped in the child control instead of being handled in the parent.)
It can help you:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.K && this.AcceptButton == null)
{
MessageBox.Show("Key K pressed");
}
return base.ProcessCmdKey(ref msg, keyData);
}
It will detect if key K is pressed in any control of your form and return msgbox
Test it and try make work your way.
Related
I want to intercept a hot-key (specifically CTRL V) which will interact with my application in a certain way. I am able to globally register the hotkey using the RegisterHotKey method. When I press CTRL V I want the focused window/control to also receive the WM_PASTE message. I've tried sending it trough SendMessage but it didn't seem to work. I eventually ended up Unregistering the HotKey, sending ^v to the current window, then re-Registering the hotkey.
private static void Hook_KeyPressed(object sender, KeyPressedEventArgs e)
{
_hook.KeyPressed -= Hook_KeyPressed;
_hook.Dispose();
SendKeys.Send("^v");
_hook = new KeyboardHook();
_hook.RegisterHotKey(global::ClipMaster.ModifierKeys.Control, Keys.V);
_hook.KeyPressed += Hook_KeyPressed;
}
This does the trick, but it blocks the mouse (and the window) for around half a second. I'm also afraid it won't work in certain applications, although I don't know what example I could give.
I'm not sure what you're trying to achieve with that hook since it's impossible to understand it from the code example.
Assuming you do it for auditing reasons (or monitoring of the sort), I'd suggest to review the return value of the WM_HOTKEY message. It can "say" that the message wasn't processed, hence allowing further processing of the Ctrl-V by other logic (e.g. other hooks).
Also, i'd advise to use alternative way to re-send Ctrl-V than SendKeys class which has know timing issues. Did you consider posting a message instead?
I've also found alternative approach to the hooking itself by using lower level key pressing for hooking.
Let me know if it helped.
So, I've finally had to deal with this annoying issue. It seems that it's a known "bug" and there doesn't seem to be a great work-around. I was wondering what seems to be the best work around for this.
A little bit of info. In my form region I have a Winform control and a WPF control. The user can't do certain key combinations on the Winform control (Ctrl-A to select all, Delete key deletes email instead of highlighted text), but everything works fine on the WPF control.
I've tried adding the Winform control to the WPF control using a WindowsFormHost, but that made it worse as it wouldn't register the backspace key after that. I tried capturing the delete event for the email, but I can't get the .BeforeDelete to trigger. Same for the Explorer.BeforeItemCut event. Currently I'm trying to capture the WndProc event to re-direct the key events, but it seems like there should be a better/easier way.
Not sure how to continue from here. Any help in direction is welcomed. Below is my how I'm trying to capture email delete event.
Outlook.MailItem _selEmail;
// This does get triggered
private void Explorer_SelectionChange()
{
var actExplorer = this.Application.ActiveExplorer();
if(this.Application.ActiveExplorer().Selection.Count > 0)
{
var selObject = actExplorer.Selection[1];
if(selObject is Outlook.MailItem)
{
_selEmail = selObject as Outlook.MailItem;
_selEmail.BeforeEmailDelete -=
new Outlook.ItemEvents_10_BeforeDeleteEventHandler(Email_BeforeDelete);
_selEmail.BeforeEmailDelete +=
new Outlook.ItemEvents_10_BeforeDeleteEventHandler(Email_BeforeDelete);
}
}
}
// Haven't gotten this to trigger. The Console.Write("") is there
// only for a breakpoint;
private void Email_BeforeDelete(object sender, ref bool cancel)
{
Console.WriteLine("");
}
First of all, I'd suggest breaking the chain of property and method calls and declare each property or method call on a separate line of code. Thus, you will be able to release underlying COM objects inplace. Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Outlook object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object. You can read more about that in the Systematically Releasing Objects article in MSDN.
Try to turn off the Single key reading using the space bar option in Outlook which allows you to move quickly through your messages in the Reading Pane. The space bar scrolls the current item. At the end of the item, it jumps to the next unread item in your message list.
Finally, using WPF controls on Outlook forms produce a well-known issue. Outlook has a habit of swallowing various keys and not sending them along to your code or form region. The spacebar, tab, backspace keys are among those affected when the keys are pressed in the reading pane. You can find a similar forum thread.
I am developing a Kinect game in C# where the user needs to click 2 buttons at the same time by hovering over one button with each hand.
However, with my current code, when the user hovers with one hand over a button, the other buttons get disabled and the other hand can only click when the first hand stops hovering over a button.
To solve this, I'm thinking of queuing the second click while the first click is being processed. To do this, I have used the following code based on this link
private Queue<System.Windows.Controls.Button> Button_Queue = new Queue<System.Windows.Controls.Button>();
private bool isProcessing = false;
private void Button_Click((object sender, RoutedEventArgs e){
if(isProcessing){
Button_Queue.Enqueue(this);
}
else
{
isProcessing = true;
// code here
isProcessing = false;
while(Button_Queue.Count > 0){
Button_Queue.Dequeue().PerformClick();
}
}
However, the Button_Queue.Enqueue(this) line shows the error
"The best overloaded method match for Queue.Enqueue has invalid
arguments."
I'm guessing this is because the button click event cannot be queued in a queue declared with the type Button.
Do you have any suggestions for how to create this queue of button click events or another way to handle multiple clicks from the user?
You don't need to queue the event. If isProcessing is true, then the other button was already clicked, so you can handle the event for both button clicks from that point on.
You could measure the time between the two clicks, to work out if it validates as a "two buttons clicked at the same time" event.
Have you considered a more low-level approach? The first thing that came to mind was to create two hot areas instead of buttons and monitor whether the user's hands are inside those areas at the same time.
It is unclear to me why another button is disabled when you hand is hovering over another object. Without seeing the code, I would say that you are doing something that would cause that -- and there is no reason to.
Additionally, you should be using interaction concepts centered around a gesture system and not something that is written for a mouse/keyboard input. Using regular UI objects and interacting with them in ways that parallel traditional inputs will only serve to confuse the users.
Have a look at the following two examples, which use a "hover-to-click" and a "press-to-click" interaction
Basic Interaction, for SDK 1.6
Control Basics, for SDK 1.7 (in Kinect for Windows Developer Toolkit)
In both cases, you are using a hit test on custom controls to handle events. Here is an example of a hit test function I use in one of my apps:
private void HitTestHand(HandPosition hand)
{
// quick fix to null pointer exception on exit.
if (Application.Current.MainWindow == null)
return;
Point pt = new Point(hand.X, hand.Y);
IInputElement input = Application.Current.MainWindow.InputHitTest(pt);
if (hand.CurrentElement != input)
{
var inputObject = input as DependencyObject;
var currentObject = hand.CurrentElement as DependencyObject;
// If the new input is a child of the current element then don't fire the leave event.
// It will be fired later when the current input moves to the parent of the current element.
if (hand.CurrentElement != null && Utility.IsElementChild(currentObject, inputObject) == false)
{
// Raise the HandLeaveEvent on the CurrentElement, which at this point is the previous element the hand was over.
hand.CurrentElement.RaiseEvent(new HandInputEventArgs(HoverDwellButton.HandLeaveEvent, hand.CurrentElement, hand));
}
// If the current element is the parent of the new input element then don't
// raise the entered event as it has already been fired.
if (input != null && Utility.IsElementChild(inputObject, currentObject) == false)
{
input.RaiseEvent(new HandInputEventArgs(HoverDwellButton.HandEnterEvent, input, hand));
}
hand.CurrentElement = input;
}
else if (hand.CurrentElement != null)
{
hand.CurrentElement.RaiseEvent(new HandInputEventArgs(HoverDwellButton.HandMoveEvent, hand.CurrentElement, hand));
}
}
Notice that an event is being fired on the element below the hand cursor. Examples of these elements can be found in the two links above (the HoverDwellButton is what I use with the above code sample).
Two events on two different elements, or the same element, can fire at any time with this. You can easily keep track of which user is over which button, if that button is in the process of being pressed, or if it has been pressed.
The key to all this is not using a UI paradigm that isn't designed for gesture systems! Don't try to shoehorn the keyboard/mouse event structure into a gesture based system -- it will only cause you more pain in the long run and cause your users confusion.
No matter what the scenario may be I'm able to recreate this annoying problem 100% of the time.
Create a .Net project, C# or VB.Net. Add a ToolStrip control to the form. Create a few simple DropDownButton(s) that contain at least 2 menu items. Add any other controls you wish, a list box (populate it so it can receive focus correctly) and a ComboBox control. Either assign shortcut keys or enable TabStop on the ToolStrip so that it can receive focus by Keyboard.
Run the project (Debug/Release, which ever you fancy). Use your Keyboard to give the ToolStrip Focus (by tab or shortcut key). Arrow down into a sub item. Now select the escape key to collapse the Toolstrip sub menu. Tab to the ListBox or ComboBox that contains a few Items.
All looks great right? Now use your arrow keys to navigate in these controls... Surprise! your back on the ToolStrip and the control you thought had focus doesn't!
I've tried multiple things to force focus on the ListBox. One example is I'd add the event handler for OnEnter (ListBox.Enter+=...) and add some code like:
ListBox.Focus();
ListBox.Select();
Nothing was a success... It seems like once the menu expands on a toolstrip you will be forever stuck on this control using your Keyboard...
This is important for me to resolve due to the fact that i work with blind users whom use keyboard navigation only... Is this a bug? I cannot reproduce this in MFC...
Any suggestions?
Update
I was able to find a control that doesn't reproduce this strangeness...
System.Windows.Forms.MainMenu is the only "Tool Bar object" that doesn't behave like the others...
I'd still like some feedback on the above though (Help for others and myself)...
Update 2
The underlying issue is within [ToolStripObject].TabFocus property... if set to false all seems to work ok... giving focus back to the control that "looks" like it's focused. But having that capability to allow a blind user to navigate throughout all UI controls via tab is a handy thing to implement... it's too bad this property doesn't work like it should....
I got it to work by overriding the ToolStripMenuItem:
public class ToolStripMenuItemEx : ToolStripMenuItem {
protected override bool ProcessCmdKey(ref Message m, Keys keyData) {
if (keyData == Keys.Escape) {
ToolStripDropDownButton tb = this.OwnerItem as ToolStripDropDownButton;
if (tb != null) {
tb.HideDropDown();
return false;
}
}
return base.ProcessCmdKey(ref m, keyData);
}
}
I want my Win-Forms application (which has many different forms) to accept only certain characters of user input. This restriction should apply to all forms, all input fields, etc. Is there any simple solution to implement this without adding keyboard-events to every single form and even better, without changing any existing form?
First I have thought of a low-level keyboard hook but this would be applied globally to every user input in every application running on the system which isn't the ideal solution, I guess. Any other possibilities or suggestions?
You can do that if you create a custom control for each control you need and set your control to inherit the core controls. For example, this code will prevent clicking on zero:
public class MyTextBox : TextBox
{
protected override void OnKeyUp(KeyEventArgs e)
{
if (e.KeyCode == Keys.D0)
e.SuppressKeyPress = true;
}
}
You can even drag this control from the toolbox (after you build).