I've created a custom form for a numeric keyboard which implements the following code:
private void btn1_Click(object sender, EventArgs e)
{
PressKey(Keys.D1);
}
[DllImport("user32.dll", SetLastError = true)]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
public static void PressKey(Keys key)
{
const int KEYEVENTF_EXTENDEDKEY = 0x1;
keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY, (UIntPtr)0);
}
I've also used the following block
protected override bool ShowWithoutActivation
{
get { return true; }
}
It works as charm for notepad, word or other editors (and also using the basic SendKeys method), but in my app, in the grid cell i intend to use it (or other editable control) it fails to insert a value.
Accidentally i've found that it can insert a value only once, when the cell is not on edit mode, but it has focus.
Any example of virtual keyboard implementation from one form to another would be highly appreciated
(Too long for a comment, but maybe not enough for an answer)
We had once to develop such a keyboard, and we used the SendKeys class from the .Net Framework (which is merely a wrapper for the SendInput Win32 API call).
The keyboard form was overriding the Property CreateParams so we could explicitly tell it not to take the focus (or the keys are send to the keyboard form...)
protected override CreateParams CreateParams
{
get
{
var CreateParams cp = base.CreateParams;
cp.ExStyle = cp.ExStyle | WS_EX_NOACTIVATE;
return cp;
}
}
Note: We noticed that some programs like Ultra VNC (used for remote control) prevent the correct usage of the keyboard. I guess UltraVNC is rerouting the input keys through its driver and something is lost during the way, but never found out what.
Related
Okay, so you know how in Windows Vista and Windows 7 MS changed the Hand Cursor (the one that shows up when you hover over a hyperlink), and added more detail to it so it's antialiased and nice and smooth around the edges?
Well, why isn't it like that in Windows Forms apps?
I'm sick off looking at a crappy hand cursor that looks like it was drawn by a caveman.
Is there a way to programmatically tell it to display the one that's actually installed in the system? I looked in the Cursors folder in my Windows directory, and the old hand cursor isn't even there! So why is WinForms still using the old one? How can I 'upgrade' it?
Yes, the WinForms controls still use the old-school hand cursor, as shipped with Windows 98/2000. It lacks the anti-aliasing effects that the one included with the Aero cursors does. This is because the .NET Framework includes its own hard-coded cursor, which it uses instead of the system default. I presume this is because early versions of .NET were targeting operating systems like Windows 95 that didn't come bundled with this cursor, but haven't done the archaeology to prove it.
Fortunately, it's easy enough to force it to use the right one. You just have to tell the operating system you want it to use the default hand cursor, and then it will be correct no matter what version of Windows the user runs your program on, and even if they've changed their mouse cursors from the default theme.
The simplest way of doing that is to subclass the existing control, override the WndProc function to intercept the WM_SETCURSOR message, and tell it to use the system IDC_HAND cursor. You just need a little bit of P/Invoke magic.
The following code is an example of how that might look using the LinkLabel control:
public class LinkLabelEx : LinkLabel
{
private const int WM_SETCURSOR = 0x0020;
private const int IDC_HAND = 32649;
[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern IntPtr SetCursor(IntPtr hCursor);
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_SETCURSOR)
{
// Set the cursor to use the system hand cursor
SetCursor(LoadCursor(IntPtr.Zero, IDC_HAND));
// Indicate that the message has been handled
m.Result = IntPtr.Zero;
return;
}
base.WndProc(ref m);
}
}
Excuse me for resurrecting a year-old thread!!!
After messing around with the original solution and taking a look at the reflected LinkLabel source code, I "finally" found a quick yet clean way of doing it :
using System.Runtime.InteropServices;
namespace System.Windows.Forms {
public class LinkLabelEx : LinkLabel {
private const int IDC_HAND = 32649;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);
private static readonly Cursor SystemHandCursor = new Cursor(LoadCursor(IntPtr.Zero, IDC_HAND));
protected override void OnMouseMove(MouseEventArgs e) {
base.OnMouseMove(e);
// If the base class decided to show the ugly hand cursor
if(OverrideCursor == Cursors.Hand) {
// Show the system hand cursor instead
OverrideCursor = SystemHandCursor;
}
}
}
}
This class actually does what we want: It shows the proper system hand cursor without flickering and does this only on the LinkArea of the control.
This post solves problems of the other posts:
It respects to the link location and shows the hand just when cursor is on link
It doesn't flicker on mouse move
You need to change the cursor to system hand cursor. To do so, you need to handle WM_SETCURSOR and check if OverrideCursor is Cursors.Hand then change it to the system cursor by calling SetCursor:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class MyLinkLabel : LinkLabel
{
const int IDC_HAND = 32649;
const int WM_SETCURSOR = 0x0020;
const int HTCLIENT = 1;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
static extern IntPtr SetCursor(HandleRef hcursor);
static readonly Cursor SystemHandCursor =
new Cursor(LoadCursor(IntPtr.Zero, IDC_HAND));
protected override void WndProc(ref Message msg)
{
if (msg.Msg == WM_SETCURSOR)
WmSetCursor(ref msg);
else
base.WndProc(ref msg);
}
void WmSetCursor(ref Message m)
{
if (m.WParam == (IsHandleCreated ? Handle : IntPtr.Zero) &&
(unchecked((int)(long)m.LParam) & 0xffff) == HTCLIENT) {
if (OverrideCursor != null) {
if (OverrideCursor == Cursors.Hand)
SetCursor(new HandleRef(SystemHandCursor, SystemHandCursor.Handle));
else
SetCursor(new HandleRef(OverrideCursor, OverrideCursor.Handle));
}
else {
SetCursor(new HandleRef(Cursor, Cursor.Handle));
}
}
else {
DefWndProc(ref m);
}
}
}
Sorry for getting this old post back, but i also have some kind of solution for this.
If you need to apply the systemcursor application wide without touching old controls, use this at applicationstart:
private static void TrySetCursorsDotHandToSystemHandCursor()
{
try
{
typeof(Cursors).GetField("hand", BindingFlags.Static | BindingFlags.NonPublic)
.SetValue(null, SystemHandCursor);
}
catch { }
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);
private static readonly Cursor SystemHandCursor = new Cursor(LoadCursor(IntPtr.Zero, 32649 /*IDC_HAND*/));
Doing that without creating a new control wee need to change the Control's Cursor AND create a custom linklabel or else it wouldn't work
we create the custom linklabel by adding a label changing the font underline and changing it's fore color and add an click event
Private Const IDC_HAND As Integer = 32649
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function LoadCursor(ByVal hInstance As IntPtr, ByVal lpCursorName As Integer) As IntPtr
End Function
Private Shared ReadOnly SystemHandCursor As Cursor = New Cursor(LoadCursor(IntPtr.Zero, IDC_HAND))
'add the cursor to custom linklabel
CustomLinkLabel1.Cursor = SystemHandCursor
sorry only have vb .net code you might use an online converter
EDIT: some code was missing
I have a program which runs in the background, and when something happens a message box appears, I want to have it so clicking yes will switch to a specified program.
I just can't find what ClassName and CaptionName work with it, I need it to work with the game World of Warcraft.
The Window Title is "Wold of Warcraft" on Task manager its called "World of Warcraft Retail", when I inspect its' properties it says "Wow-64" Properties, on properties it says product name is "World of Warcraft" so I've tried every combination of these and nothing works. The code works if I put:
BringToFront("Notepad", "Untitled - Notepad");
So it works, I just don't know what I need for it to apply to WoW.
My code is:
[DllImport("User32.dll")]
public static extern Int32 SetForegroundWindow(int hWnd);
[DllImport("user32.dll")]
public static extern int FindWindow(string lpClassName, string lpWindowName);
private void BringToFront(string className, string CaptionName)
{
SetForegroundWindow(FindWindow(className, CaptionName));
}
private void Alert()
{
string title = "WoW Queue Alert: Message";
string message = "The Queue is ready to accept!";
MessageBoxButtons buttons = MessageBoxButtons.YesNo;
DialogResult result;
result = MessageBox.Show(new Form() { TopMost = true }, message, title, buttons, MessageBoxIcon.Information);
if (result == System.Windows.Forms.DialogResult.Yes)
{
BringToFront("World of Warcraft Retail", "World of Warcraft");
}
}
I really don't see anything special about WoW, and going by how the notepad example works the correct code should be:
BringToFront("World of Warcraft Retail", "World of Warcraft");
Being a fullscreen program should affect it, and I can't see there being anyway Blizzard has implemented something to stop this function.
Edit: I just set the ClassName to null and works, as caption name is just the window title. No idea what the ClassName is I tried everything I could find.
You should use some window inspection tool to inspect the window of World of Warcraft to get its Class Name and Window Name. A suggestion would be Spy++ if you installed Visual Studio (it comes along with it). It can help you detect the window's Class Name and Window Name, and Windows Messages sent to that window easily.
For example, the picture below shows all windows in current environment. Highlighted entry is a PowerPoint instance, which has Caption = "Microsoft PowerPoint" and ClassName = "PPTFrameClass".
Another approach will be writing a "always-inactivate" winform and call GetForegroundWindow from that form to get the window handle of the window you want.
To create an "always-inactivate" winform, simply override its CreateParams property:
protected override CreateParams CreateParams
{
get
{
CreateParams p = base.CreateParams;
p.ExStyle |= 0x8000000; // WS_EX_NOACTIVATE - requires Win 2000 or higher
return p;
}
}
By overriding this, the form won't get focus even on a mouse click. Therefore, you could create a button to trigger GetForegroundWindow(). Signature of the function in C# looks like below:
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
which returns the window handle of current fore ground window.
I'm trying to check if a key is pressed, but I get these Error Message:
Error 1 The name 'Keyboard' does not exist in the current context
Error 2 The name 'Key' does not exist in the current context
Can you tell me how to fix it?
public void Main()
{
while(true)
{
if (Keyboard.IsKeyPressed(Key.A))
{
//...
}
return;
}
}
It looks like you are trying to create a global hotkey in the system and your application should respond when it is pressed.
You will need two Win32 API functions RegisterHotKey and UnregisterHotKey.
Looking at your using System.Windows.Input, it seems like you are trying to do this with WPF, which is possible.
Let's start with your fairly basic P/Invokes:
using System.Runtime.InteropServices;
internal static class NativeMethods
{
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr windowHandle, int hotkeyId, uint modifierKeys, uint virtualKey);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr windowHandle, int hotkeyId);
}
Now, when you register your Window, what happens is that a WM_HOTKEY message is sent to your application's message pump. However, WPF abstracts this message pump away from you, so you'll need to add a HwndSourceHook to tap into it.
How do we do all this? Let's start by initializing our HwndSourceHook delegate. Add this snippet to your MainWindow:
using System.Windows.Interop;
static readonly int MyHotKeyId = 0x3000;
static readonly int WM_HOTKEY = 0x312;
void InitializeHook()
{
var windowHelper = new WindowInteropHelper(this);
var windowSource = HwndSource.FromHwnd(windowHelper.Handle);
windowSource.AddHook(MessagePumpHook);
}
IntPtr MessagePumpHook(IntPtr handle, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_HOTKEY)
{
if ((int)wParam == MyHotKeyId)
{
// The hotkey has been pressed, do something!
handled = true;
}
}
return IntPtr.Zero;
}
Alright, so now we have everything in place to respond to the WM_HOTKEY message. However, we need to register our hotkey still! Let's add another couple initialization methods:
void InitializeHotKey()
{
var windowHelper = new WindowInteropHelper(this);
// You can specify modifiers such as SHIFT, ALT, CONTROL, and WIN.
// Remember to use the bit-wise OR operator (|) to join multiple modifiers together.
uint modifiers = (uint)ModifierKeys.None;
// We need to convert the WPF Key enumeration into a virtual key for the Win32 API!
uint virtualKey = (uint)KeyInterop.VirtualKeyFromKey(Key.A);
NativeMethods.RegisterHotKey(windowHelper.Handle, MyHotKeyId, modifiers, virtualKey);
}
void UninitializeHotKey()
{
var windowHelper = new WindowInteropHelper(this);
NativeMethods.UnregisterHotKey(windowHelper.Handle, MyHotKeyId);
}
Alright! Where do we put these? Do not put them in the constructor! Why? Because the Handle will be 0 and invalid! Put them here (in MainWindow):
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
InitializeHook();
InitializeHotKey();
}
You can register multiple hotkeys, un-register and re-register new ones.. it's up to you. Just remember that each hotkey must have a unique ID registered to it. It only makes sense, as your message pump hook has to know which hotkey caused the WM_HOTKEY message!
It's also good practice to unregister all hotkeys when your application closes.
You can use a keyboard hook. Check this out, from this answer to a similar question:
Global keyboard hooks are not the right solution if you only want a
few global hotkeys. A high level keyboard hook means that your dll
will be injected into other applications, and shouldn't be done at all
in managed code. A low level keyboard hook is a bit better, since it
processes the keyboard events in your own application. Still it
requires that every keyboard event is handled by your thread.
The windows API function RegisterHotKey is much better suited for
that.
But using a smple F-Key as global hotkey is problematic since it might
collide with a local hotkey of the application that has focus. So you
should make global hotkeys configurable, so the user can avoid
collisions with his commonly used applications.
If you are trying to do this in a windows forms application, maybe you can add these codes into the Form's KeyDown event(or which key event you need to use):
switch (e.KeyData)
{
//Detects that you pressed the Up Arrow Key, which key do you need, just
//write it here.
case Keys.Up:
//enter code here`
break;
}
You need to add PresentationCore.dll and WindowsBase to references and add to the header of the method [STAThread]
The type of application is not clear. If you have a console application, not a Windows form one, you can try this:
while (true)
if (Console.KeyAvailable)
if (Console.ReadKey(true).Key == ConsoleKey.A)
{
// Do something
}
and read this if you want to have a global hotkey in a windows forms app: http://www.liensberger.it/web/blog/?p=207
I'm wanting to write a virtual keyboard, like windows onscreen keyboard for touchscreen pcs.
But I'm having problem with my virtual keyboard stealing the focus from the application being used. The windows onscreen keyboard mantains the focus on the current application even when the user clicks on it. Is there a way to do the same with windows forms in C#?
The only thing I can do for now is to send a keyboard event to an especific application, like notepad in the following code. If I could make the form not focusable, I could get the current focused window with GetForegroundWindow.
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName,string lpWindowName);
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
private void button1_Click(object sender, EventArgs e)
{
IntPtr calculatorHandle = FindWindow("notepad", null);
SetForegroundWindow(calculatorHandle);
SendKeys.SendWait("111");
}
Is there a way this can be done? Any suggestions of a better way to have the form sending keyboard events to the application being used?
Thanks!!
Its solved!
I've tried the solution from gehho, but I also needed to override the CreateParams method:
private const int WS_EX_NOACTIVATE = 0x08000000;
protected override CreateParams CreateParams
{
get
{
var createParams = base.CreateParams;
createParams.ExStyle |= WS_EX_NOACTIVATE;
return createParams;
}
}
Instead of trying to reset the active window after your one has been clicked, I would rather try to prevent your window from receiving focus/being activated.
Have a look at this article. At the end, the author briefly explains how this can be done:
How can I prevent my window from getting activation and focus when shown?
In Windows Forms 2.0 there is a new property called
ShowWithoutActivation – which you would need to override on the Form.
In native applications you can use SetWindowPos with the
SWP_NOACTIVATE flag or the ShowWindow with the SW_SHOWNA flag.
Furthermore, in this article he provides a code example for Windows Forms:
If you want a full-on form, you can now override a property called
ShowWithoutActivation:
public class NoActivateForm : Form
{
protected override bool ShowWithoutActivation => true;
}
Keep in mind this does not “prevent” activation all the time – you can
still activate by calling the Activate(), Focus()… etc methods. If
you want to prevent clicks on the client area from activating the
window, you can handle the WM_MOUSEACTIVATE message.
private const int WM_MOUSEACTIVATE = 0x0021, MA_NOACTIVATE = 0x0003;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MOUSEACTIVATE)
{
m.Result = (IntPtr)MA_NOACTIVATE;
return;
}
base.WndProc(ref m);
}
I've been assigned to make a custom grid control in C# with windows forms. One thing I'm unsure of is how to handle showing a blinking cursor (caret) to indicate where cell editing is taking place and the next character will be shown.
Does anyone know how this is done with the standard textbox? Is there a standard framework construct that will do this for me?
Obviously I can setup a timer and draw the cursor myself, but I was wondering if there was a better option. Note that this is a completely user drawn control, not a UserControl derivative and that subclassing an existing class is not an option for various reason.
Here you go:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public class MyWidget : Control {
public MyWidget() {
this.BackColor = Color.Yellow;
}
protected override void OnGotFocus(EventArgs e) {
CreateCaret(this.Handle, IntPtr.Zero, 2, this.Height - 2);
SetCaretPos(2, 1);
ShowCaret(this.Handle);
base.OnGotFocus(e);
}
protected override void OnLostFocus(EventArgs e) {
DestroyCaret();
base.OnLostFocus(e);
}
[DllImport("user32.dll", SetLastError = true)]
private static extern bool CreateCaret(IntPtr hWnd, IntPtr hBmp, int w, int h);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool SetCaretPos(int x, int y);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool ShowCaret(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool DestroyCaret();
}
I'll gladly pass the buck on figuring out where to put it.
The MSDN reference about Carets is here. The last time I looked (which was in 2.0 of the framework) carets weren't available as a managed API: and so you need to use the unmanaged API, or paint your own caret.
One thing to remember, when you implement a caret, is that you should not show it whenever your control doesn't have the focus (only one control at a time on the user's desktop, i.e. the control which has the input focus, should ever be showing the input caret).
Why re-invent the wheel? Just display a textbox when the grid needs editing.
Ok, I see you you use custom drawing, but what prevents you from placing a textbox on over it?
If you wanna go the hard way, Microsoft does have some old libraries that can provide a virtual textarea (or something like that, been a very long).