A WPF application has a Test() method that is called when a keyboard shortcut is pressed CTRL+G.
The method call works because the string test is printed to the console, from the first line of the method.
The method should programmatically press the key combination CTRL+A to select the text in any input field, but this does not happen.
I tried 3 ways:
First: The System.Windows.Forms.SendKeys.SendWait() method, which takes a string, where ^ is CTRL - according to documentation
private void Test(object sender, EventArgs e)
{
Console.WriteLine("test");
SendKeys.SendWait("^A");
}
However, there is no pressing.
Second: Implementation via user32.dll, solution taken from here:
[DllImport("user32.dll", SetLastError = true)]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
public static void PressKey(Keys key, bool up)
{
const int KEYEVENTF_EXTENDEDKEY = 0x1;
const int KEYEVENTF_KEYUP = 0x2;
if (up)
keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, (UIntPtr)0);
else
keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY, (UIntPtr)0);
}
private void Test(object sender, EventArgs e)
{
Console.WriteLine("test");
PressKey(Keys.ControlKey, up: false);
PressKey(Keys.A, up: false);
PressKey(Keys.A, up: true);
PressKey(Keys.ControlKey, up: true);
}
But in this case, nothing happens.
Third: Installed the package: Install-Package InputSimulator:
private static void Test(object sender, EventArgs e)
{
Console.WriteLine("test");
var simu = new InputSimulator();
simu.Keyboard.ModifiedKeyStroke(VirtualKeyCode.CONTROL, VirtualKeyCode.VK_A);
}
Full code: https://pastebin.com/ay8vRtjA
There are no errors, what am I doing wrong?
The key combination technically works, but the code executes before you have any time to release the ALT key, making the final combination CTRL + ALT + A instead of CTRL + A. I may be overlooking some simpler solution, but the way I found (mostly) works is:
Intercept the ALT key
If G is pressed while ALT is down, execute the command
If G wasn't pressed, allow the keystroke through and send a simulated ALT (so that hotkeys in other applications can still be activated)
It's a hacky workaround and still messes up some regular functionality (for instance if you press a hotkey like ALT + A to open a menu, the menu will close as soon as you release ALT), but it makes your hotkey work.
I used a library that I created a couple of years back, called InputHelper, to set up a global keyboard hook to intercept the keystrokes and execute the hotkey. I've yet to publish this to NuGet, so for now you'll have to download it via Releases and add the DLL as a reference in your project.
You'll also need to add a reference to System.Windows.Forms.
using System;
using System.Windows;
using System.Windows.Forms;
namespace HotkeyTest
{
public partial class MainWindow : Window
{
InputHelper.Hooks.KeyboardHook kbHook = new InputHelper.Hooks.KeyboardHook();
bool AltHotkeyConsumed = false;
public MainWindow()
{
InitializeComponent();
kbHook.KeyDown += KeyboardHook_KeyDown;
kbHook.KeyUp += KeyboardHook_KeyUp;
}
private void KeyboardHook_KeyUp(object sender, InputHelper.EventArgs.KeyboardHookEventArgs e)
{
if(e.KeyCode == Keys.LMenu || e.KeyCode == Keys.RMenu)
{
if(!AltHotkeyConsumed)
// If no hotkey was consumed, press the key again (otherwise it will just be blocked altogether)
InputHelper.Keyboard.PressKey(e.KeyCode);
else
AltHotkeyConsumed = false;
}
}
private void KeyboardHook_KeyDown(object sender, InputHelper.EventArgs.KeyboardHookEventArgs e)
{
if(e.KeyCode == Keys.LMenu || e.KeyCode == Keys.RMenu)
e.Block = true;
if(e.Modifiers == InputHelper.ModifierKeys.Alt)
{
if(e.KeyCode == Keys.G)
{
Test();
AltHotkeyConsumed = true;
e.Block = true;
}
else
{
e.Block = false;
}
}
}
private static void Test()
{
InputHelper.Keyboard.SetKeyState(Keys.LControlKey, true);
InputHelper.Keyboard.PressKey(Keys.A);
InputHelper.Keyboard.SetKeyState(Keys.LControlKey, false);
}
}
}
Related
I'm asking the question already asked (and even answered) here:
Why are some textboxes not accepting Control + A shortcut to select all by default
But that answer doesn't work for me. I have this code:
public class LoginForm : Form
{
private TextBox tbUsername;
public LoginForm()
{
tbUsername = new TextBox();
tbUsername.ShortcutsEnabled = true;
tbUsername.Multiline = false;
Controls.Add(tbUsername);
}
}
The textbox shows up, I can write on it, I can cut, copy and paste text on it without any problems.
But when I try to press Ctrl+A I only hear a "bling" similar to the bling that you hear if you try to erase text from an empty textbox (try it with your browser's address bar).
Like other answers indicate, Application.EnableVisualStyles() should be called. Also the TextBox.ShortcutsEnabled should be set to true. But if your TextBox.Multiline is enabled then Ctrl+A will not work (see MSDN documentation). Using RichTextBox instead will get around the problem.
Just create a keydown event for that TextBox in question and include this code:
private void tbUsername_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.A)
{
if (sender != null)
((TextBox)sender).SelectAll();
}
}
You could always override the process command keys to get the desired result
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
const int WM_KEYDOWN = 0x100;
var keyCode = (Keys) (msg.WParam.ToInt32() &
Convert.ToInt32(Keys.KeyCode));
if ((msg.Msg == WM_KEYDOWN && keyCode == Keys.A)
&& (ModifierKeys == Keys.Control)
&& tbUsername.Focused)
{
tbUsername.SelectAll();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
Quick answer is that if you are using multiline true you have to explicitly call the select all.
private void tbUsername_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.A && e.Control)
{
tbUsername.SelectAll();
}
}
This happened to me once too, I'm assuming you removed the call for Application.EnableVisualStyles(); from your program? Add it back to the Main() function and everything should work fine.
Textbox has a method SelectAll() and worked well for me. (.net 4.5)
No need to handle WM_KEYDOWN! I know that most examples here (and CodeProject and many other places) all say there is, but it does not cure the beep that results whenever a WM_CHAR arises that is not handled.
Instead, try this:
LRESULT CALLBACK Edit_Prc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){
if(msg==WM_CHAR&&wParam==1){SendMessage(hwnd,EM_SETSEL,0,-1); return 1;}
else return CallWindowProc((void*)WPA,hwnd,msg,wParam,lParam);
}
Remember to subclass the EDIT control to this Edit_Prc() using WPA=SetWindowLong(...) where WPA is the window procedure address for CallWindowProc(...)
I figured this out by experiment, after finding that all the answers I found online insisted on handling WM_KEYDOWN, using GetKeyState(), and ended up with bigger code that failed to stop that annoying beep!
While this answer doesn't deal with dotnet, in cases like this it's usually better to cut to the chase and solve it rather than agonise over which version of a large code wrapper system may or may not do it for you, especially if you want to avoid the risk of fighting against inbuilt behaviour.
Throwing in my two cents. Calling this under keypress is just another option.
private void TxtBox_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == '\x1')
{
TxtBox.SelectAll();
e.Handled = true;
}
}
This is my code, it is working fine
private void mainSimPlus_KeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
if (e.Control == true && e.KeyCode == Keys.A)
{
if (SelectAllTextBox(txt1))
return;
if (SelectAllTextBox(txt2))
return;
}
}
private bool SelectAllTextBox(TextBox txt)
{
if (txt.Focused)
{
txt.SelectAll();
return true;
}
else
return false;
}
I'm making an application in C# With Visual Studio 2010. It is an Windows Forms Application
What I want to do is to trigger an function when 3 keys are pressed. The keys are CTRL, SHIFT and X.
I have this code right now:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
Console.WriteLine(e.KeyValue);
/*
*KeyValue:
*CTRL = 17
*Shift = 16
*X = 88
*/
}
And as you can see, its pretty empty. This is because I don't know it anymore.
I've found on the internet this piece of code, but don't know how to implement it:
[DllImport("user32.dll")]
public static extern int GetKeyboardState(byte[] keystate);
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
byte[] keys = new byte[255];
GetKeyboardState(keys);
if (keys[(int)Keys.Up] == 129 && keys[(int)Keys.Right] == 129)
{
Console.WriteLine("Up Arrow key and Right Arrow key down.");
}
}
So my question to you guys is, how can i check if all the tree keys are pressed at the same time?
Or if you know an better way to make such an hot key, how would that be than?
In the case of CTRL+SHIFT+X, only X is really a proper key; the others are "modifier" keys. So no need to break out the P/Invoke :-) Just do this in your Key_Down handler:
if (e.KeyCode == Keys.X && e.Control && e.Shift) {
// CTRL+SHIFT+X was pressed!
}
In my project there is a Form mainForm in which there are two textBoxes txtUserName and txtPassword and also a button btnLogin.
I have given the following txtUserName properties:
txtUserName Properties
AutoCompleteCustomSource - Collection
--> Administrator
--> Clerk
AutoCompleteMode - Suggest
AutoCompleteSource - CustomSource
btnLogin_Click Event
if (txtUserName.Text.Equals("Administrator") && txtPassword.Text.Equals("123"))
{
//function to access admin features
}
else if (txtUserName.Text.Equals("Clerk") && txtPassword.Text.Equals("123"))
{
//function to access clerk features
}
else
{
MessageBox.Show("Please Enter correct details", "Login Error");
}
I have setted the mainForm keypreview to true and implemented function to keyDown event of mainForm which is shown in the below code:
mainForm_KeyDownEvent
if (e.KeyCode.Equals(Keys.Enter)) //Invokes whenever Enter is pressed
{
btnLogin_Click(sender,e); //login
}
Now my problem is that whenever the focus is on txtUserName and pressing A, dropdown is showing to select "Administrator" (which is defined in collections as I shown in above properties). When I click Enter on keyboard it is showing MessageBox instead of selecting "Administrator". I know that is invoking the keydown event of mainForm. How to disable the keyDown event, when it is on textbox dropdown thing so that I can press enter?
EDIT:
I tried the below code in public form() :(not working)
InitializeComponent();
if (txtUserName.AutoCompleteMode) { /* showing red scribbles */
this.KeyDown -= mainForm_KeyDown;
}
You should not be handling the Enter key at all. You can remove your KeyDown handler, and instead use the AcceptButton property of the form to set the button that gets "clicked" when Enter is pressed. This is already supposed to not "click" the button when another control has already handled the Enter key.
That isn't enough for your situation, because standard Windows behaviour is for the Enter key to press the default button. Press Win+R, for example, to get the Run... dialog, start typing C:\Use, press Down to select C:\Users, press Enter, and see what happens.
In order to override that behaviour, you need to make the text box tell the form that it will be handling the Enter key itself, so that the form won't send it to the default button. This can be done by creating a derived class and overriding IsInputKey:
public class MyTextBox : TextBox
{
protected override bool IsInputKey(Keys keyData)
{
return base.IsInputKey(keyData) || ((keyData & ~Keys.Shift) == Keys.Enter && IsDroppedDown);
}
}
However, TextBox implements autocompletion using the SHAutoComplete function, which automatically creates an IAutoComplete object behind the scenes. That object cannot be accessed, and because of that, the IsDroppedDown property that I used in IsInputKey cannot be created. It would be implemented using IAutoCompleteDropDown.GetDropDownStatus, but since the object is inaccessible, you cannot (reliably) determine whether the dropdown list is showing.
You would need to either implement the auto completion without using the built-in AutoComplete* properties, or you would need to always suppress the Enter key (remove the && IsDroppedDown in the above IsInputKey).
Update: here's how to create an IAutoComplete object manually. The strings Administrator and Clerk are hardcoded. The GetDropDownStatus function is used to suppress any default button's handling of Enter when the drop down list is visible. Feedback welcome.
IAutoComplete.cs:
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
[ComImport]
[Guid("00bb2762-6a77-11d0-a535-00c04fd7d062")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[CoClass(typeof(IAutoCompleteClass))]
interface IAutoComplete
{
void Init(HandleRef hwndEdit, IEnumString punkACL, string pwszRegKeyPath, string pwszQuickComplete);
void Enable(bool fEnable);
}
IAutoComplete2.cs:
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
[Guid("EAC04BC0-3791-11d2-BB95-0060977B464C")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IAutoComplete2
{
void Init(HandleRef hwndEdit, IEnumString punkACL, string pwszRegKeyPath, string pwszQuickComplete);
void Enable(bool fEnable);
void SetOptions(AutoCompleteOptions dwFlag);
AutoCompleteOptions GetOptions();
};
AutoCompleteOptions.cs:
using System;
[Flags]
enum AutoCompleteOptions : int
{
None = 0x00,
AutoSuggest = 0x01,
AutoAppend = 0x02,
Search = 0x04,
FilterPrefixes = 0x08,
UseTab = 0x10,
UpDownKeyDropsList = 0x20,
RtlReading = 0x40,
WordFilter = 0x80,
NoPrefixFiltering = 0x100,
}
IAutoCompleteDropDown.cs:
using System;
using System.Runtime.InteropServices;
using System.Text;
[Guid("3CD141F4-3C6A-11d2-BCAA-00C04FD929DB")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IAutoCompleteDropDown
{
void GetDropDownStatus(out AutoCompleteDropDownFlags dwFlags, out StringBuilder wszString);
void ResetEnumerator();
}
AutoCompleteDropDownFlags.cs:
using System;
[Flags]
enum AutoCompleteDropDownFlags : int
{
None = 0x00,
Visible = 0x01
}
IAutoCompleteClass.cs:
using System;
using System.Runtime.InteropServices;
[ComImport]
[Guid("00BB2763-6A77-11D0-A535-00C04FD7D062")]
class IAutoCompleteClass
{
}
EnumString.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
class EnumString : IEnumString
{
const int E_INVALIDARG = unchecked((int)0x80070057);
const int S_OK = 0;
const int S_FALSE = 1;
int current;
string[] strings;
public EnumString(IEnumerable<string> strings)
{
this.current = 0;
this.strings = strings.ToArray();
}
public void Clone(out IEnumString ppenum)
{
ppenum = new EnumString(strings);
}
public int Next(int celt, string[] rgelt, IntPtr pceltFetched)
{
if (celt < 0)
return E_INVALIDARG;
int num = 0;
while (current < strings.Length && celt != 0)
{
rgelt[num] = strings[current];
current++;
num++;
celt--;
}
if (pceltFetched != IntPtr.Zero)
Marshal.WriteInt32(pceltFetched, num);
if (celt != 0)
return S_FALSE;
return S_OK;
}
public void Reset()
{
current = 0;
}
public int Skip(int celt)
{
if (celt < 0)
return E_INVALIDARG;
if (strings.Length - current > celt)
{
current = strings.Length;
return S_FALSE;
}
current += celt;
return S_OK;
}
}
MyTextBox.cs:
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
public class MyTextBox : TextBox
{
IAutoComplete2 autoComplete;
IAutoCompleteDropDown autoCompleteDropDown;
public bool IsDroppedDown
{
get
{
if (autoCompleteDropDown == null)
return false;
AutoCompleteDropDownFlags dwFlags;
StringBuilder wszString;
autoCompleteDropDown.GetDropDownStatus(out dwFlags, out wszString);
return (dwFlags & AutoCompleteDropDownFlags.Visible) != AutoCompleteDropDownFlags.None;
}
}
protected override void CreateHandle()
{
base.CreateHandle();
autoComplete = (IAutoComplete2)new IAutoComplete();
autoCompleteDropDown = (IAutoCompleteDropDown)autoComplete;
autoComplete.SetOptions(AutoCompleteOptions.AutoSuggest);
autoComplete.Init(new HandleRef(this, this.Handle), new EnumString(new string[] { "Administrator", "Clerk" }), null, null);
}
protected override void DestroyHandle()
{
ReleaseAutoComplete();
base.DestroyHandle();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
ReleaseAutoComplete();
}
base.Dispose(disposing);
}
protected override bool IsInputKey(Keys keyData)
{
return base.IsInputKey(keyData) || ((keyData & ~Keys.Shift) == Keys.Enter && IsDroppedDown);
}
void ReleaseAutoComplete()
{
if (autoComplete != null)
{
Marshal.ReleaseComObject(autoComplete);
autoComplete = null;
autoCompleteDropDown = null;
}
}
}
You need to override the keydown event handler.
protected override void OnKeyDown(KeyEventArgs e)
{
//call original event handler. Remove it if you don't need it at all.
base.OnKeyDown(e);
//Insert your code here....
}
Try this. Hopefully it will not cause any problem on pressing enter while your focus is on txtUsername or else where
If you write a in txtUserName and press enter, Your Admministrator choice will be selected from your autocompletecustomsource using regular expression and focus will go to txtPassword. My regular expression is very flexible you can made it bit restricted as following to match strictly from beginning and also can remove ignore case
Regex rg = new Regex("^" + txtUserName.Text);
private void mainForm_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode.Equals(Keys.Enter))// && !txtUserName.Focus())// && intFlag.Equals(0))
{
if (txtUserName.Text.Length > 0)
{
if (txtUserName.Focused)
{
Regex rg = new Regex(txtUserName.Text, RegexOptions.IgnoreCase);
for (int i = 0; i < txtUserName.AutoCompleteCustomSource.Count; i++)
{
if (rg.IsMatch(txtUserName.AutoCompleteCustomSource[i]))
{
txtUserName.Text = txtUserName.AutoCompleteCustomSource[i];
txtPassword.Focus();
return;
}
}
}
if (txtPassword.Text.Length > 0)
{
btnLogin_Click(null, null); //login
}
else
{
//MessageBox.Show("Please Give a Password");
txtPassword.Focus();
}
}
else
{
//MessageBox.Show("Please Give a username");
txtUserName.Focus();
}
}
//if (txtPassword.ContainsFocus)
//{
// btnLogin_Click(sender, e); //login
//}
//else
//{
// this.txtPassword.Focus();
//}
}
Actually, you have two issues.
First off, set the AutoCompleteMode property of txtUserName to "SuggestAppend" instead of simply "Suggest." This way, if the user types the first letter or two, the correct entry will automatically be appended to the txtUSerName.Text.
Next, modify your Form code as follows:
void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode.Equals(Keys.Enter)) //Invokes whenever Enter is pressed
{
if (txtPassword.ContainsFocus)
{
btnLogin_Click(sender, e); //login
}
else
{
this.txtPassword.Focus();
}
}
}
private void btnLogin_Click(object sender, EventArgs e)
{
if (txtUserName.Text.Equals("Administrator") && txtPassword.Text.Equals("123"))
{
MessageBox.Show("Administrator");
}
else if (txtUserName.Text.Equals("Clerk") && txtPassword.Text.Equals("123"))
{
MessageBox.Show("Clerk");
}
else
{
MessageBox.Show("Please Enter correct details", "Login Error");
}
}
In the above, the Key Down event handling code tests to see if the password text box has the focus (meaning, the user has presumable entered a user name already, and a password, and is ready to submit the data). If so, the btnLogin_Click event is called. Otherwise, (meaning, txtUserName probably has the focus) control is passed to txtPassword to continue data entry.
UPDATE: re - Your comment:
Simply kill the logic in the Key Down Event handler like so:
Revised Event Handling Code:
void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode.Equals(Keys.Enter)) //Invokes whenever Enter is pressed
{
btnLogin_Click(sender, e); //login
}
}
Note, another minor improvement (considering the overall structure of your code) would be to use a combo box for selection of UserName, and set the autocomplete source to "ListItems" then enter your options the same as with the text box. This requires the user to select from the pre-defined list. This still has scaleability issues similar to the previous, but eliminates an unnecessary step for the user if they simply make a typo while entering User Name data.
Remember that users tend to dislike unnecessary interruption by pop-up messages. Allow them to select the appropriate "user name" from a drop down, type in the proper password, and move on.
There are some better ways to do all of this, but this should tune up what you have into working order.
On a final note, let me observe that eventually you will probably want to find a more robust way of performing this sort of validation. Any time you need to add users (which, in your code, appear to be defined more as "groups" you will need to add to your conditional event handling tree.
You might check into persisting usernames and passwords in an encrypted file or database, and load them into a dictionary or something at run time. Then perform a key/value lookup on user/Password.
Or something.
Anyway, hope that helps.
UPDATE 2: The complete code all in one shot. This should behave the way you are asking:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.KeyDown +=new KeyEventHandler(Form1_KeyDown);
}
void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode.Equals(Keys.Enter)) //Invokes whenever Enter is pressed
{
btnLogin_Click(sender, e); //login
}
}
private void btnLogin_Click(object sender, EventArgs e)
{
if (txtUserName.Text.Equals("Administrator") && txtPassword.Text.Equals("123"))
{
MessageBox.Show("Administrator");
}
else if (txtUserName.Text.Equals("Clerk") && txtPassword.Text.Equals("123"))
{
MessageBox.Show("Clerk");
}
else
{
MessageBox.Show("Please Enter correct details", "Login Error");
}
}
}
}
This is not a duplicate. Many similar threads discuss capturing a combination involving a modifier key.
I need to get something triggered when a shortcut key (a combination of Insert+Tab) is pressed from a control, say Button.
Catch:
This involves no modifier key like Alt or Shift for which .NET has built in checking.
This has Tab key which is not caught so easily.
What I tried and came close:
1) KeyDown Event but doesnt capture Tabs..
[DllImport("user32.dll")]
public static extern int GetKeyboardState(byte[] keystate);
static void form_KeyDown(object sender, KeyEventArgs e)
{
if (!(((Form)sender).ActiveControl is Button))
return;
byte[] keys = new byte[255];
GetKeyboardState(keys);
if (keys[(int)Keys.Insert] == 129 && keys[(int)Keys.Tab] == 129)
{
// doesn't work
}
if (keys[(int)Keys.Insert] == 129 && keys[(int)Keys.J] == 129)
{
// works, since here this doesnt involve Tab
}
}
This works with regular combinations, doesnt fire along with Tab.
2) KeyPreview Event which captures Tab key, but I do not know how to get a combination of keys pressed
static void form_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (!(((Form)sender).ActiveControl is Button))
return;
if (e.KeyCode == Keys.Tab)
//works
if (e.KeyCode == Keys.Insert && e.KeyCode == Keys.Tab)
//doesn't hit.
}
Requirement:
1) I am not registering the event from Form class. Instead I have a utility class which creates all required events (along with other shortcuts). I just pass the instance of form to a static function. So I am quite unsure how I should utilize the various key overriding calls. Here is how I do it:
public frmLogin()
{
InitializeComponent();
Utility.SetFormEvents(this);
}
static void SetFormEvents(Form f){
//foreach control...........
}
But I can give up on this..
Thanks..
Tab is considered a command key, you don't actually get notified of it being pressed directly. You could PInvoke the GetKeyState method, but I think it's just easier to recognize that tab is a command key (and override ProcessCmdKey) and keep track of whether the Insert key is up or down. For example:
static bool insertPressed;
static bool tabPressed;
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if(keyData == Keys.Tab)
{
tabPressed = true;
CheckForTabAndInsert();
}
return base.ProcessCmdKey(ref msg, keyData);
}
static void form_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Insert)
{
insertPressed = true;
CheckForTabAndInsert();
insertPressed = false;
}
}
static void form_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Insert) insertPressed = false;
}
The drawback is that you only really get a KeyPress for tab with ProcessCmdKey, so you can only really support Insert+Tab (not Tab+Insert). This is because Tab is used to switch context from one control to another. Depending on your situation (i.e. in the context of a text box), you could make use of the AcceptTab property to possibly just use KeyUp and KeyDown... But, from what you posted, that doesn't appear to be the case.
I have a situation where I would like to move a windows form by holding right mouse button on it's client area; the form it's borderless as i've stated.
I would like to move it "natively" (if possible, otherwise other answers are ok too). I mean the way it behaves when you hold left mouse button on the titlebar (with mouse-move and things like that I get a lot of strange behaviours, but maybe it's just me).
I've read around a lot of things and this post looks helpful
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/b9985b19-cab5-4fba-9dc5-f323d0d37e2f/
I tried various way to use that and watched through http://msdn.microsoft.com/en-us/library/ff468877%28v=VS.85%29.aspx to find other useful things and WM_NCRBUTTONDOWN came in my mind, however the wndproc doesn't detect it, maybe because it's handled by the form?
Any suggestion are appreciated, thanks
Francesco
public partial class DragForm : Form
{
// Offset from upper left of form where mouse grabbed
private Size? _mouseGrabOffset;
public DragForm()
{
InitializeComponent();
}
protected override void OnMouseDown(MouseEventArgs e)
{
if( e.Button == System.Windows.Forms.MouseButtons.Right )
_mouseGrabOffset = new Size(e.Location);
base.OnMouseDown(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
_mouseGrabOffset = null;
base.OnMouseUp(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (_mouseGrabOffset.HasValue)
{
this.Location = Cursor.Position - _mouseGrabOffset.Value;
}
base.OnMouseMove(e);
}
}
You need two P/Invoke methods to get this done.
[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hwnd, int msg, int wparam, int lparam);
[DllImport("user32.dll")]
static extern bool ReleaseCapture();
A couple of constants:
const int WmNcLButtonDown = 0xA1;
const int HtCaption= 2;
Handle the MouseDown event on your form, then do this:
private void Form_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
ReleaseCapture();
SendMessage(this.Handle, WmNcLButtonDown, HtCaption, 0);
}
}
This will send your form the same event it receives when the mouse clicks and holds down the caption area. Move the mouse and the window moves. When you release the mouse button, movement stops. Very easy.