Clipboard.GetText overrides clipboard? - c#

Here is what im trying to do:
There is some game which writes some info about item under mouse cursor into clipboard when i press Ctrl-C. Im trying to grab that info and select some stuff i need from it.
Im doing it like this:
//at form load
RegisterHotKey(this.Handle, 0, 0x002, (int)Keys.C);
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312)
{
int id = m.WParam.ToInt32();
if (id == 0)
{
System.Threading.Thread.Sleep(155); //ive thought if i add some delay it would help but it doesnt...
string textFromClipboard = Clipboard.GetText();
if (textFromClipboard.Contains("Itemlevel: "))
{
// do some stuff with data IF it exists in clipboard, doesnt important what i do - i never get here
}
}
}
base.WndProc(ref m);
}
So basically, when i press Ctrl-C in-game without this program on - all works fine, info copied in clipboard. When i turn program on - clipboard stays same as it was before i press Ctrl-C in-game. How do i prevent this? How do i get text from clipboard correctly? Maybe the way i get this text is wrong? Or maybe that registered hotkey interferes with game hotkey so it doesn't work anymore?
update:
Ive figured out some simple solution, but very rough and barbaric. But it works fine.
public static void KeyDown(System.Windows.Forms.Keys key)
{
keybd_event((byte)key, 0x45, 0x0001 | 0, 0);
}
public static void KeyUp(System.Windows.Forms.Keys key)
{
keybd_event((byte)key, 0x45, 0x0001 | 0x0002, 0);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312)
{
int id = m.WParam.ToInt32();
if (id == 0)
{
ToggleHotkeys(false);
KeyDown(Keys.Control);
KeyDown(Keys.C);
KeyUp(Keys.C);
KeyUp(Keys.Control);
System.Threading.Thread.Sleep(155);
//if i comment this sleep - code executes too fast, making first Ctrl-C press
//capture nothing, second press outputs results for first item
//third press - for second item, ...
string textFromClipboard = Clipboard.GetText();
if (textFromClipboard.Contains("Itemlevel: "))
{
//do stuff with data
}
ToggleHotkeys(true);
}
}
base.WndProc(ref m);
}
Maybe there is more clever way to solve this problem?

I would use a ClipBoard monitor so you can get notified whenever the ClipBoard changes:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private ClipBoardMonitor cbm = null;
public Form1()
{
InitializeComponent();
cbm = new ClipBoardMonitor();
cbm.NewText += cbm_NewText;
}
private void cbm_NewText(string txt)
{
Console.WriteLine(txt);
}
}
public class ClipBoardMonitor : NativeWindow
{
private const int WM_DESTROY = 0x2;
private const int WM_DRAWCLIPBOARD = 0x308;
private const int WM_CHANGECBCHAIN = 0x30d;
[DllImport("user32.dll")]
static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("user32.dll")]
static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
public event NewTextEventHandler NewText;
public delegate void NewTextEventHandler(string txt);
private IntPtr NextClipBoardViewerHandle;
public ClipBoardMonitor()
{
this.CreateHandle(new CreateParams());
NextClipBoardViewerHandle = SetClipboardViewer(this.Handle);
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_DRAWCLIPBOARD:
if (Clipboard.ContainsText())
{
if (NewText != null)
{
NewText(Clipboard.GetText());
}
}
SendMessage(NextClipBoardViewerHandle, m.Msg, m.WParam, m.LParam);
break;
case WM_CHANGECBCHAIN:
if (m.WParam.Equals(NextClipBoardViewerHandle))
{
NextClipBoardViewerHandle = m.LParam;
}
else if (!NextClipBoardViewerHandle.Equals(IntPtr.Zero))
{
SendMessage(NextClipBoardViewerHandle, m.Msg, m.WParam, m.LParam);
}
break;
case WM_DESTROY:
ChangeClipboardChain(this.Handle, NextClipBoardViewerHandle);
break;
}
base.WndProc(ref m);
}
}
}

Related

How to remove the text selection highlight from a ComboBox permanently?

I am interested in removing the text selection of ComboBoxes with DropDownStyle = DropDown.
When I add/remove or close the DropPown, then the Item is selected.
I am not able to clear the selected text. Do you have some idea how to do this?
This code does not work:
comboBox.SelectionLenght = 0;
comboBox.SelectionStart = comboBox.Text.Legnth;
comboBox.Select(0,0);
I can see that the text is highlighted after this line:
selectedComboBox.Items.Add(redCompetitorName);
You can defer the execution of the Select() method, calling BeginInvoke() in the SelectedIndexChanged event handler (or SelectionChangedCommitted, if you want this to happen only when a User selects an Item manually).
By deferring the execution (this action is enqueued in the message loop), the Select() action is performed only after the ComboBox.Text has been set and highlighted. So your command is not overridden by the default behavior.
private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
{
// Set the caret to the start of the ComboBox text
BeginInvoke(new Action(()=> comboBox.Select(0, 0)));
// OR - set the caret to the end of the text instead
BeginInvoke(new Action(()=> comboBox.Select(int.MaxValue, 0)));
}
This concept applies in other contexts of course.
You can use this method in other situations, when you need to perform an action, in the UI, that is executed only after the current (or the current sequence of the already scheduled actions) has completed.
If you want a more involved solution that prevents all kind of selection highlights in a ComboBox, you can use a Custom Control derived from ComboBox, get the Handle of its Edit Control, use a NativeWindow to intercept its messages. Override WndProc to handle EM_SETSEL and call PostMessage to remove the selection (only when the starting position is > 0, otherwise you risk to get stuck in a weird auto-loop which has an effect that's usually referred to as StackOverflow :).
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
[DesignerCategory("code")]
public class ComboBoxNoFocus : ComboBox
{
IntPtr editHandle = IntPtr.Zero;
private EditNativeWindow editControl = null;
public ComboBoxNoFocus() { }
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
editHandle = GetComboBoxEditInternal(this.Handle);
editControl = new EditNativeWindow(editHandle);
}
public class EditNativeWindow : NativeWindow
{
private const int EM_SETSEL = 0x0B1;
public EditNativeWindow() : this(IntPtr.Zero) { }
public EditNativeWindow(IntPtr handle)
{
if (handle != IntPtr.Zero) {
this.AssignHandle(handle);
}
}
protected override void WndProc(ref Message m)
{
switch (m.Msg) {
case EM_SETSEL:
int pos = m.LParam.ToInt32();
if (pos > 0) {
PostMessage(this.Handle, EM_SETSEL, 0, 0);
}
return;
default:
// Other operations
break;
}
base.WndProc(ref m);
}
}
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern bool GetComboBoxInfo(IntPtr hWnd, ref COMBOBOXINFO pcbi);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
[StructLayout(LayoutKind.Sequential)]
internal struct COMBOBOXINFO
{
public int cbSize;
public Rectangle rcItem;
public Rectangle rcButton;
public int buttonState;
public IntPtr hwndCombo;
public IntPtr hwndEdit;
public IntPtr hwndList;
public void Init() => this.cbSize = Marshal.SizeOf<COMBOBOXINFO>();
}
internal static IntPtr GetComboBoxEditInternal(IntPtr cboHandle)
{
var cbInfo = new COMBOBOXINFO();
cbInfo.Init();
GetComboBoxInfo(cboHandle, ref cbInfo);
return cbInfo.hwndEdit;
}
}
Set the focus to another control in your form after a new item is selected, using the SelectedIndexChanged event of the Combobox.
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
button1.Focus();
}

intercept CTRL + Letter + Letter

I would like to intercept while I push CTRL + A + A
I read the article
How can I register a global hot key to say CTRL+SHIFT+(LETTER) using WPF and .NET 3.5?
and someone pasted a code originally posted here:
https://www.fluxbytes.com/csharp/how-to-register-a-global-hotkey-for-your-application-in-c/?unapproved=2279&moderation-hash=b3ec34d2621e0be051ed354f09c436d2#comment-2279
Anyway, I tried to change the code adding and "&" but this and some other attempt was wrong.
How can I get if I press CTRL + A + A ?
Thanks for the help!
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace GlobalHotkeyExampleForm
{
public partial class Form1 : Form
{
private void Form1_Load(object sender, EventArgs e)
{
}
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
enum KeyModifier
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
WinKey = 8
}
public Form1()
{
InitializeComponent();
int id = 0; // The id of the hotkey.
RegisterHotKey(this.Handle, id, (int)KeyModifier.Control, Keys.A.GetHashCode()); // Register ctrl + a as global hotkey.
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0x0312)
{
/* Note that the three lines below are not needed if you only want to register one hotkey.
* The below lines are useful in case you want to register multiple keys, which you can use a switch with the id as argument, or if you want to know which key/modifier was pressed for some particular reason. */
Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF); // The key of the hotkey that was pressed.
KeyModifier modifier = (KeyModifier)((int)m.LParam & 0xFFFF); // The modifier of the hotkey that was pressed.
int id = m.WParam.ToInt32(); // The id of the hotkey that was pressed.
MessageBox.Show("Hotkey has been pressed!");
// do something
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
UnregisterHotKey(this.Handle, 0); // Unregister hotkey with id 0 before closing the form. You might want to call this more than once with different id values if you are planning to register more than one hotkey.
}
private void button1_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
This is the solution that I've found to listen Key Pressure.
I took the code from "Dylan's Web" and I changed something:
https://www.dylansweb.com/2014/10/low-level-global-keyboard-hook-sink-in-c-net/
This is the class with a couple of lines more:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Input;
namespace DesktopWPFAppLowLevelKeyboardHook
{
public class LowLevelKeyboardListener
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x101;
private const int WM_SYSKEYDOWN = 0x104;
private const int WM_SYSKEYUP = 0x105;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
public event EventHandler<KeyPressedArgs> OnKeyPressed;
private LowLevelKeyboardProc _proc;
private IntPtr _hookID = IntPtr.Zero;
public LowLevelKeyboardListener()
{
_proc = HookCallback;
}
public void HookKeyboard()
{
_hookID = SetHook(_proc);
}
public void UnHookKeyboard()
{
UnhookWindowsHookEx(_hookID);
}
private IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
int status = 1;
if (OnKeyPressed != null) { OnKeyPressed(this, new KeyPressedArgs(KeyInterop.KeyFromVirtualKey(vkCode), status)); }
}
else if (nCode >= 0 && wParam == (IntPtr)WM_KEYUP || wParam == (IntPtr)WM_SYSKEYUP)
{
int vkCode = Marshal.ReadInt32(lParam);
int status = 0;
if (OnKeyPressed != null) { OnKeyPressed(this, new KeyPressedArgs(KeyInterop.KeyFromVirtualKey(vkCode), status)); }
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
}
public class KeyPressedArgs : EventArgs
{
public Key KeyPressed { get; private set; }
public int KeyStatus { get; private set; }
public KeyPressedArgs(Key key, int status)
{
KeyPressed = key;
KeyStatus = status;
}
}
}
This is the Form:
using DesktopWPFAppLowLevelKeyboardHook;
using System;
using System.Windows.Forms;
namespace AppLowLevelKeyboardHook
{
public partial class Form1 : Form
{
private LowLevelKeyboardListener _listener;
public int ctrlStatus;
public int cStatus;
public Form1()
{
InitializeComponent();
}
private void Window_Loaded(object sender, EventArgs e)
{
_listener = new LowLevelKeyboardListener();
_listener.OnKeyPressed += _listener_OnKeyPressed;
_listener.HookKeyboard();
}
private void _listener_OnKeyPressed(object sender, KeyPressedArgs e)
{
this.textBox_DisplayKeyboardInput.Text += e.KeyPressed.ToString() + e.KeyStatus.ToString();
if (e.KeyStatus == 1 && (e.KeyPressed.ToString() == "LeftCtrl" || e.KeyStatus.ToString() == "RightCtrl"))
{
if (ctrlStatus == 0)
{
ctrlStatus = ctrlStatus + 1;
timer1.Start();
}
}
else if (e.KeyStatus == 1 && e.KeyPressed.ToString() == "C")
{
if (ctrlStatus == 1 && (cStatus == 0 || cStatus == 2))
{
cStatus = cStatus + 1;
}
}
//no need to wait that CTRL will be released
//else if (e.KeyStatus == 0 && (e.KeyPressed.ToString() == "LeftCtrl" || e.KeyStatus.ToString() == "RightCtrl"))
//{
// if (ctrlStatus == 1)
// {
// ctrlStatus = ctrlStatus + 1;
// }
//}
else if (e.KeyStatus == 0 && e.KeyPressed.ToString() == "C")
{
if (ctrlStatus == 1)
{
if (cStatus == 1 || cStatus == 3)
{
cStatus = cStatus + 1;
}
}
}
}
private void timer1_Tick(object sender, EventArgs e)
{
if ((ctrlStatus == 1) && cStatus == 3 || cStatus == 4) //no need to wait that CTRL will be released (ctrlStatus == 2)
{
//do something
label1.Text = "";
label1.Refresh();
label1.Text = Clipboard.GetText(TextDataFormat.UnicodeText);
//\do something
}
ctrlStatus = 0;
cStatus = 0;
timer1.Stop();
}
private void Window_Closing(object sender, FormClosingEventArgs e)
{
_listener.UnHookKeyboard();
}
}
}
PS: originally it was WPF app but mine it's a WFA and KeyInterop is not included.
So I simply added a reference assembly to WindowsBase.dll
Yesterday I'm back on this question and finally, I did what I was searching to do but changing the strategy because with the upper code I didn't really found a solution for my target. I'm going to report why I think it can be useful to someone else and maybe someone has a different solution.
So, on the upper code, I tried to intercept CTRL+C+C and than get what use copy on the Windows Clipboard. But here it's the problem, that code registers the shortkey, so any other software can't continue to use CTRL+C. I tried to unregister the shortkey after to have cached that CTRL+C has been pressed but I've found only problems. Anyway, I don't like "to stole" a shortkey to another app, I prefer to "listen" key while they are pressed.
So here it follows the code with some comments (I'll paste the solution that I've found "listening keys pressed" adding a new answer).
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Text;
namespace GlobalHotkeyExampleForm
{
public partial class Form1 : Form
{
private void Form1_Load(object sender, EventArgs e)
{
}
public int shortkey = 0;
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
enum KeyModifier
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
WinKey = 8
}
public Form1()
{
InitializeComponent();
int id = 0; // The id of the hotkey.
RegisterHotKey(this.Handle, id, (int)KeyModifier.Control, Keys.C.GetHashCode()); // Register CTRL + C as global hotkey.
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0x0312)
{
/* Note that the three lines below are not needed if you only want to register one hotkey.
* The below lines are useful in case you want to register multiple keys, which you can use a switch with the id as argument, or if you want to know which key/modifier was pressed for some particular reason. */
Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF); // The key of the hotkey that was pressed.
KeyModifier modifier = (KeyModifier)((int)m.LParam & 0xFFFF); // The modifier of the hotkey that was pressed.
int id = m.WParam.ToInt32(); // The id of the hotkey that was pressed.
if (modifier == KeyModifier.Control && key == Keys.C)
{
shortkey = shortkey + 1;
label1.Text = (shortkey.ToString());
//if I enebale this code it works partially. The UnregisterHotKey and RegisterHotKey works perfectly and alone also SendKeys works prefectly, but together it doesn't:
//it doesn't recognize that CTRL is still pressed and I don't want to do CTRL C + CTRL C and I don't like "to stole" the shortkey from other apps!;
//I tried to use SendKeys to resend CTRL C or onlt CTRL but it doens't work and it creates only Register problems
//UnregisterHotKey(this.Handle, 0); //unregister the hotkey catching
//SendKeys.Send("^c"); //send key to active application (it doesn't matter if this is the application)
////register the hotkey catching as C only
//RegisterHotKey(this.Handle, id, (int)KeyModifier.Control, Keys.C.GetHashCode());
//SendKeys.Send("^c");
//SendKeys.Send("^");
timer1.Start();
}
//MessageBox.Show("Hotkey has been pressed!");
// do something
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
UnregisterHotKey(this.Handle, 0); // Unregister hotkey with id 0 before closing the form. You might want to call this more than once with different id values if you are planning to register more than one hotkey.
}
private void button1_Click(object sender, EventArgs e)
{
this.Close();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (shortkey == 2)
{
string returnMyText = Clipboard.GetText(TextDataFormat.Text);
}
shortkey = 0;
timer1.Stop();
}
}
}

C# make form hide and then show again

I am trying to make a Windows Forms Application be able to repeatedly show and then hide itself.
The idea is to create a small app that overlays an image on the screen every time a modifier key like Num Lock or Caps lock is pressed. I have the detection of the keyboard keys working flawlessly, but I am not having much luck with creating a form that I can show and then hide repeatedly.
The way I see it, (please correct me if I'm wrong) there are two possible ways to make the form behave like I want it to:
Start the form normally in Program.cs and then hold the logic for hiding and showing the form and displaying the image inside Form1.cs
The form would call this.Hide() and this.Show() to hide and show itself, but whenever I try to do this, I cannot get this.Hide() to hide the form; the form remains visible on top of all of the open windows.
Hold the logic for hiding and showing the form in Program.cs and then just hold the logic to display the image in Form1.cs
I've been toying around with the code from this guide to show and hide the from from Program.cs with a class wrapper for the form, but as it turns out, form.Showdialog() prevents any further code execution until the form is closed.
I've been playing around with the code myself, and neither of the above methods have worked. Am I thinking about this in the wrong way entierly? Can a WFA ever behave in the way I want it to?
The code for this is a bit messy, and I'm not sure what parts are the most relevant here, but I'll do my best to include it here:
Program.cs:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
namespace KeyboardIndicators {
// ApplicationContext wrapper
public abstract class TrayIconApplicationContext : ApplicationContext {
private NotifyIcon lockIcon;
private ContextMenu lockIconContext;
protected TrayIconApplicationContext() {
// Wire up the ApplicationExitHandler to ApplicationExit events
Application.ApplicationExit += this.ApplicationExitHandler;
lockIconContext = new ContextMenu {
};
// Create lockIcon tray icon and make it visible
lockIcon = new NotifyIcon {
ContextMenu = lockIconContext,
Text = Application.ProductName,
Icon = new Icon("icon.ico"),
Visible = true
};
}
protected NotifyIcon LockIcon { get { return lockIcon; } }
protected ContextMenu LockIconContext { get { return lockIconContext; } }
// ApplicationExit event handler
private void ApplicationExitHandler(object sender, EventArgs e) {
this.OnApplicationExit(e);
}
// Performs cleanup to end the application
protected virtual void OnApplicationExit(EventArgs e) {
// TODO(Neil): Add meaningful thread cleanup here soon
if (lockIcon != null) {
lockIcon.Visible = false;
lockIcon.Dispose();
}
if (lockIconContext != null)
LockIconContext.Dispose();
}
}
// TrayIconApplicationContext wrapper for Form1 to control the activation of the form window
class FormApplicationContext : TrayIconApplicationContext {
public FormApplicationContext() {
// Add Exit menu item
MenuItem exit = new MenuItem("E&xit");
this.LockIconContext.MenuItems.Add(exit);
exit.Click += this.ExitContextMenuClickHandler;
//KeyboardIndicators indicators = new KeyboardIndicators();
//indicators.RunListener();
{
using(Form form = new Form1("NumLock", true))
form.ShowDialog();
}
}
private void ExitContextMenuClickHandler(object sender, EventArgs eventArgs) {
this.ExitThread();
}
}
public class KeyboardIndicators {
class LockState {
// Is the numlock key on?
public bool Num;
// Is the capslock key on?
public bool Caps;
// Is the scroll lock key on?
public bool Scroll;
}
public void RunListener() {
try {
// Store the old keyboard lock state
LockState prevState = new LockState() {
Num = Control.IsKeyLocked(Keys.NumLock),
Caps = Control.IsKeyLocked(Keys.CapsLock),
Scroll = Control.IsKeyLocked(Keys.Scroll)
};
while (true) {
// Store the new keyboard lock state
LockState newState = new LockState() {
Num = Control.IsKeyLocked(Keys.NumLock),
Caps = Control.IsKeyLocked(Keys.CapsLock),
Scroll = Control.IsKeyLocked(Keys.Scroll)
};
//TODO(Neil): Handle simultaneous presses better, i.e. queue the balloon tips
if (newState.Num != prevState.Num) {
Form1 form = new Form1("NumLock", newState.Num);
} else if (newState.Caps != prevState.Caps) {
Form1 form = new Form1("CapsLock", newState.Caps);
} else if (newState.Scroll != prevState.Scroll) {
Form1 form = new Form1("ScrollLock", newState.Scroll);
}
// Set the previous lock state to the new one in prep for the next iteration
prevState = newState;
// Sleep for 500ms
Thread.Sleep(500);
}
} catch (ThreadAbortException) { /* No need to do anything, just catch the ThreadAbortException.*/ }
}
}
static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1("NumLock", true));
Application.Run(new FormApplicationContext());
}
}
}
Form1.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace KeyboardIndicators {
public partial class Form1 : Form {
public Form1(String activatedModifier, bool lockState) {
InitializeComponent();
ShowForm(activatedModifier);
//this.Show();
//this.Hide();
}
public void ShowForm(String activatedModifier) {
PictureBox pictureBox = new PictureBox();
Image myBitmap = Image.FromFile("cube.png");
Size bitmapSize = new Size(myBitmap.Width, myBitmap.Height);
switch (activatedModifier) {
case "NumLock":
break;
case "CapsLock":
break;
case "ScrollLock":
break;
}
this.Size = bitmapSize;
pictureBox.ClientSize = bitmapSize;
pictureBox.Image = myBitmap;
pictureBox.Dock = DockStyle.Fill;
this.Controls.Add(pictureBox);
this.FormBorderStyle = FormBorderStyle.None;
}
protected override CreateParams CreateParams {
get {
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT
return createParams;
}
}
}
}
As an example I have created a Winforms Application which displays "NUM" and / or "CAPS" if any of those keys is pressed otherwise the form is hidden.
The detection of the keys is based on the C# Low Level Keyboard Hook.
Program.cs
using System;
using System.Windows.Forms;
namespace WinFormsKeyHook
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
Form1.cs
Note: Add a label named 'label1' to Form1 in Designer.
using System.Collections.Generic;
using System.Windows.Forms;
namespace WinFormsKeyHook
{
public partial class Form1 : Form
{
private static bool _caps;
private static bool _num;
public Form1()
{
InitializeComponent();
KeyboardHook kh = new KeyboardHook();
kh.KeysToObserve.AddRange(new List<Keys> { Keys.CapsLock, Keys.NumLock });
kh.InstallHook();
kh.KeyDown = key => ProcessKeyDown(key);
_caps = Control.IsKeyLocked(Keys.CapsLock);
_num = Control.IsKeyLocked(Keys.NumLock);
}
private void ProcessKeyDown(Keys key)
{
if (key == Keys.CapsLock)
{
_caps = !_caps;
}
if (key == Keys.NumLock)
{
_num = !_num;
}
this.ShowState(_num, _caps);
}
internal void ShowState(bool num, bool caps)
{
if (!num && !caps)
{
this.Hide();
return;
}
this.label1.Text = "";
this.label1.Text += num ? "NUM " : "";
this.label1.Text += caps ? "CAPS" : "";
if (!this.Visible)
{
this.Show();
}
}
}
}
KeyboardHook.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WinFormsKeyHook
{
public class KeyboardHook
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private IntPtr _hookID = IntPtr.Zero;
public List<Keys> KeysToObserve { get; set; } = new List<Keys>();
public Action<Keys> KeyDown;
public void InstallHook()
{
_hookID = SetHook(HookCallback);
}
~KeyboardHook()
{
UnhookWindowsHookEx(_hookID);
}
public IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
public IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
var key = (Keys)vkCode;
Console.WriteLine(key);
KeyDown(key);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
}

Why isn't "protected override void WndProc(ref Message m)" working

I've been trying to figure this out for a very long time now; I've searched this several times and read more articles and questions on this than I can recall and I can't seem to figure out exactly what's going wrong. This is a small program that I've been trying to compile to test generating a hotkey to be used by an application.
The source for the test I've been trying to figure out is as follows:
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
namespace Prg
{
class MainClass
{
[DllImport("User32.dll")]
private static extern int RegisterHotKey(IntPtr hWnd, int id, int
fsModifiers, int vk);
[DllImport("User32.dll")]
private static extern int UnregisterHotKey(IntPtr hWnd, int id);
public static Form f1 = new Form();
public static int Register(Form f)
{
IntPtr ip = f.Handle;
return RegisterHotKey(ip, 1, 0, (int)Keys.Escape);
}
public static void b1_click(object sender, EventArgs e)
{
//Blah Blah stuff
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312)
{
MessageBox.Show("wow");
}
base.WndProc(ref m);
}
public static void Main()
{
Button b1 = new Button();
b1.Location = new Point(10, 10);
b1.Text = "wow";
b1.Click += new EventHandler(b1_click);
f1.Width = 200;
f1.Height = 200;
f1.Controls.Add(b1);
f1.ShowDialog();
Register(f1);
}
}
}
I have been compiling with csc.exe using C# 4.0. Every time I try and compile this, or similar code, I keep getting this error:
Main.csx(37,27): error CS0115:
'Prg.MainClass.WndProc(System.Windows.Forms.Message)': no suitable method found to override
Every example of using User32.dll to register a hotkey has had the "protected override WndProc" method inside it and everyone has been saying it worked just fine for them, but I can't figure out why it won't work for the life of me. If someone could help me solve this problem it would be greatly appreciated. I'm using Windows 7 Professional 64-bit, and the path to csc.exe is C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe
Thanks :)
Edit
I've gotten it to compile now, However the issue now is that it doesn't seem to be registering and kind of hotkey or at least not picking up the KeyPress at all. Is there an error in my code?
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
namespace Prg
{
class MainClass : Form
{
[DllImport("User32.dll")]
private static extern int RegisterHotKey(IntPtr hWnd, int id, int
fsModifiers, int vk);
[DllImport("User32.dll")]
private static extern int UnregisterHotKey(IntPtr hWnd, int id);
public static Form f1 = new Form();
public static int Register(Form f)
{
IntPtr ip = f.Handle;
return RegisterHotKey(ip, 1, 0, (int)Keys.Escape);
}
public static void b1_click(object sender, EventArgs e)
{
//Blah Blah stuff
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312)
{
MessageBox.Show("wow");
}
base.WndProc(ref m);
}
public static void Main()
{
Button b1 = new Button();
b1.Location = new Point(10, 10);
b1.Text = "wow";
b1.Click += new EventHandler(b1_click);
f1.Width = 200;
f1.Height = 200;
f1.Controls.Add(b1);
f1.ShowDialog();
Register(f1);
}
}
}
I've tried several different solutions but none of them have gotten the Hot Key to work at all. I've even tried re-writing the source to use Application.Run(new MainClass()); but it still didn't detect the Keypress even when the form was focused.
Edit
The Problem is solved thanks to zzxyz for helping get it to compile, and Antoine for helping me fix my mistakes in the code. Thanks guys. This is the code that compiles and works, for anyone who may have had the same problems or just prefers to learn by example. Thanks again.
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
namespace Prg
{
class MainClass : Form
{
[DllImport("User32.dll")]
private static extern int RegisterHotKey(IntPtr hWnd, int id, int
fsModifiers, int vk);
[DllImport("User32.dll")]
private static extern int UnregisterHotKey(IntPtr hWnd, int id);
public static MainClass f1 = new MainClass();
public static int Register(Form f)
{
IntPtr ip = f.Handle;
return RegisterHotKey(ip, 1, 0, (int)Keys.Escape);
}
public static void b1_click(object sender, EventArgs e)
{
//Blah Blah stuff
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312)
{
MessageBox.Show("wow");
}
base.WndProc(ref m);
}
public static void Main()
{
Button b1 = new Button();
b1.Location = new Point(10, 10);
b1.Text = "wow";
b1.Click += new EventHandler(b1_click);
f1.Width = 200;
f1.Height = 200;
f1.Controls.Add(b1);
Register(f1);
f1.ShowDialog();
}
}
}
2 mistakes:
you must register the hotkeys before showing your f1. Swap the last 2 lines
currently, you override WndProc for MainClass, not for every form. So your form f1 inherits the base Form.WndProc, not your overriden one. So just declare f1 as MainClass, and it will work.

Global keylistener

The program is working at background and listening keyboard(like keylogger)
First I select a string on pdf or etc. Then I pressed the ctrl + rbutton the program must be pop up and it can be get my selected string.
For this;
[DllImport("User32.dll")]
private static extern short GetAsyncKeyState(System.Windows.Forms.Keys vKey);
[DllImport("User32.dll")]
private static extern short GetAsyncKeyState(System.Int32 vKey);
string key = "";
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Interval = 5;
foreach (System.Int32 i in Enum.GetValues(typeof(Keys)))
{
int x = GetAsyncKeyState(i);
if ((x == 1) || (x == -32767))
{
keyBuffer += Enum.GetName(typeof(Keys), i);
}
}
if (keyBuffer != "")
{
keyBuffer = keyBuffer.ToLower();
if (keyBuffer.Contains("lcontrolkeyrbutton"))
{
// do somethings
keyBuffer = "";
}
}
}
But after first performing, ctrl + rbutton it doesn't work. What's the wrong? And how can i get the selected string into my program?
Sounds like you want a clipboard hook (in addition to your global key hook). Take a look here: Clipboard event C#
If you want to capture the string without the user copying it into the clipboard manually, you could send ctrl+c to the application yourself: http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.aspx
You need to SendKeyEvent(Ctrl+C) of MainWindowsHandle First, then Using Clipboard capture your text to your Project.
Here is the program funcional and tested
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CtrLetterCopy
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
const int WM_COMMAND = 0x111;
enum KeyModifier
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
WinKey = 8
}
public Form1()
{
InitializeComponent();
this.ShowInTaskbar = false;
int id_Ctrl = 0; // The id of the hotkey.
RegisterHotKey(this.Handle, id_Ctrl, (int)KeyModifier.Control, Keys.R.GetHashCode());
}
protected override void WndProc(ref Message m)
{
//const int WM_HOTKEY = 0x0312;
if (m.Msg == 0x0312)
{
if (m.WParam.ToInt32() == 0)
{
//do what you want here
SendKeyEvent();
}
}
base.WndProc(ref m);
}
private void SendKeyEvent()
{
SendKeys.SendWait("^c");
Thread.Sleep(500);
string test3 = Clipboard.GetText();
MessageBox.Show(test3);
}
}
}
Download and check out this code here:
http://www.codeproject.com/KB/cs/globalhook.aspx
Pre-tested, well-written and fully functional.
Best of luck!

Categories