Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have this C# code and I want to change the Text of a label named label1. When I am using these functions to detect what key is pressed and change the label1.Text from within the function, the text is unchanged. How can I change the label1.Text from within this function?
private void Form1_Load(object sender, EventArgs e)
{
_hookID = SetHook(_proc);
label1.Font = new Font("Arial", 24, FontStyle.Bold);
}
private static const int WH_KEYBOARD_LL = 13;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private static 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 delegate IntPtr LowLevelKeyboardProc(
int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYUP)
{
int vkCode = Marshal.ReadInt32(lParam);
Form1 f = new Form1();
f.label1.Text = "Changed Label"; //<-------------------- change label here
}
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)]
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);
You have several mistakes:
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private static IntPtr HookCallback(
You're trying to assign something that won't exist until runtime inside a static class method. That is not going to work; you need to do something like:
private LowLevelKeyboardProc _proc;
private IntPtr _hookID;
private IntPtr HookCallback(...
private void Form1_Load(object sender, EventArgs e)
{
_proc = new LowLevelKeyboardProc(HookCallback);
_hookID = SetHook(_proc);
Learn what static means and do not use it unless you absolutely have to. It doesn't do what you seem to think it does.
Next:
Form1 f = new Form1();
f.label1.Text = "Changed Label";
You are creating a completely new copy of your form, f, changing a label inside the copy, then throwing away the copy without displaying or doing anything at all with it. You want this:
label1.Text = "Changed Label";
Related
I am creating a bot program that opens an external application and does a series of keyboard commands. Unfortunately, the user can press a keyboard button while it is botting and get it out of sequence. Is there a way to disable the keyboard for that application only? The only thing I have found is BlockInput which does not work:
[DllImport("user32.dll", EntryPoint = "BlockInput")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool BlockInput([MarshalAs(UnmanagedType.Bool)] bool fBlockIt);
private void button_Click(object sender, EventArgs e)
{
BlockInput(true);
//Open application and do macro
BlockInput(false);
}
EDIT:
So I found a solution that worked better than what I asked for. I'm not answer my own question though because I didn't block JUST the external application; I was able to block all mouse and keyboard commands to the computer.
What I did was right-clicked on the Namespace under the Solution in Solution Explorer and selected Add > New Item. Add an Application Manifest File. Click on the newly created app.manifest file. Read the green that says to replace the requestedExecutionLevel and replace the current one with "requireAdministrator". Add the following code to the program:
[DllImport("user32.dll", SetLastError = true)]
static extern bool BlockInput(bool fBlockIt);
private void button_Click(object sender, EventArgs e)
{
BlockInput(true);
//Blocked code
BlockInput(false);
}
I find a good topic on that subject test if it fit you : How to intercept all the keyboard events and prevent losing focus in a WinForms application? (test the return -1 on the call back).
The code of the link :
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
class InterceptKeys
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
Application.Run();
UnhookWindowsHookEx(_hookID);
}
private static 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 delegate IntPtr LowLevelKeyboardProc(
int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine((Keys)vkCode);
}
return -1;
}
[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);
}
I am attempting to create a program to globally detect key presses and mouse clicks. I have googled around and found solutions for both and got them working in the same program. But I would like to combine the two separate classes into one class that does both. I have fiddled around with it for a bit and can't figure out how to do it. Does anyone know how to solve this? Thanks in advance!
Mouse clicks class:
public static class MouseHook
{
public static event EventHandler imputAction = delegate { };
public static void Start()
{
_hookID = SetHook(_proc);
}
public static void stop()
{
UnhookWindowsHookEx(_hookID);
}
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
MyGlobals.clickType = 1;
imputAction(null, new EventArgs());
}
if (nCode >= 0 && MouseMessages.WM_RBUTTONDOWN == (MouseMessages)wParam)
{
MyGlobals.clickType = 2;
imputAction(null, new EventArgs());
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private const int WH_MOUSE_LL = 14;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_RBUTTONDOWN = 0x0204,
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc 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);
}
Keyboard class:
class InterceptKeys
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static event EventHandler imputAction = delegate { };
public static void Start()
{
_hookID = SetHook(_proc);
}
public static void stop()
{
UnhookWindowsHookEx(_hookID);
}
private static 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 delegate IntPtr LowLevelKeyboardProc(
int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
MyGlobals.characters = Convert.ToString((Keys)vkCode);
MyGlobals.clickType = 3;
imputAction(null, new EventArgs());
}
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);
}
I am starting these like this:
MouseHook.Start();
MouseHook.MouseAction += new EventHandler(Event);
InterceptKeys.Start();
InterceptKeys.MouseAction += new EventHandler(Event)
The function receiving both events:
private void Event(object sender, EventArgs e)
{
//do stuff
}
I am also trying to do scrolling, I got it to detect scrolling by adding these lines. But I can't figure out how to read the scroll direction or value and assign it to a variable.
WM_MOUSEWHEEL = 0x020A,
if (nCode >= 0 && MouseMessages.WM_MOUSEWHEEL == (MouseMessages)wParam)
{
MyGlobals.imputType = 4;
// Here is where I need to set a variable to the direction or
// value of scrolling but I cant figure out how
imputAction(null, new EventArgs());
}
I found a way to capture the Print Screen button in C#. When pressing Alt + Print Screen a simple messagebox pops up saying the keys have been pressed. But it's unresponsive for a couple of seconds right after. I have no idea why this is happening.
Here's the code I use:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
_hookID = SetHook(_proc);
Application.Run(new Form1());
UnhookWindowsHookEx(_hookID);
}
/****************************************/
private const int WH_KEYBOARD_LL = 13;
//private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int VK_F1 = 0x70;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private static 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 delegate IntPtr LowLevelKeyboardProc(
int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
Keys number = (Keys)Marshal.ReadInt32(lParam);
if (number == Keys.PrintScreen)
{
if ((wParam == (IntPtr)260 && Keys.Alt == Control.ModifierKeys && number == Keys.PrintScreen))
{
MessageBox.Show("You pressed alt+ print screen");
}
}
}
return CallNextHookEx(IntPtr.Zero, 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);
}
Does anyone have a clue why it's hanging after the messagebox?
Windows cannot dispatch the next keyboard message until the hook callback finished executing. Clearly you do not want to use MessageBox.Show(), that blocks the callback. Windows puts up with that for several seconds before it declares your code broken and disables the hook.
Use Debug.Print() instead.
How can I "catch" the KeyPress event from a Word 2010 Addin developed in C#?
Note: I'm not looking for "complex" solutions like hooking stuff, but for the nice and tidy
.NET even from the object model.
The application object I have "in my hands" is:
Microsoft.Office.Interop.Word.Application
Best Regards
Unfortunately there is nothing built-in in the Word API or VSTO which can pick up key strokes, more info on this can be found here
I've been searching for a feasible solution for some time but the best I could come up with was handling it through Windows API using hooks, it's likely you will reach the same conclusion so here's an example:
You'll need to add a using directive to the following assemblies:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
And here's the hook:
public partial class ThisAddIn
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static IntPtr hookId = IntPtr.Zero;
private delegate IntPtr HookProcedure(int nCode, IntPtr wParam, IntPtr lParam);
private static HookProcedure procedure = HookCallback;
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, HookProcedure lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
hookId = SetHook(procedure);
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
UnhookWindowsHookEx(hookId);
}
private static IntPtr SetHook(HookProcedure procedure)
{
using (Process process = Process.GetCurrentProcess())
using (ProcessModule module = process.MainModule)
return SetWindowsHookEx(WH_KEYBOARD_LL, procedure, GetModuleHandle(module.ModuleName), 0);
}
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int pointerCode = Marshal.ReadInt32(lParam);
string pressedKey = ((Keys)pointerCode).ToString();
//Do some sort of processing on key press
var thread = new Thread(() => { MessageBox.Show(pressedKey); });
thread.Start();
}
return CallNextHookEx(hookId, nCode, wParam, lParam);
}
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
}
You might try to use the Excel WebBrowser Control instead of the System.Windows.Forms WebBrowser; it handles special key forwarding as TAB, DEL, CTRL+V, etc.
For that change the WebBrowser contructor from
new System.Windows.Forms.WebBrowser();
to
new Microsoft.Office.Tools.Excel.Controls.WebBrowser();
You would need to add references to your project: Project/Add Reference/Extensions select Microsoft.Tools.Outlook & Microsoft.Tools.Outlook.v4.0.Utilities
I've got a simple window form application that turns on capslock when I press space and turns it off if I press a letter.
Problem is that I have to focus on the window for it to work (top-most doesn't work either, top-most doesn't focus it just displaying the window above all other unfocused).
Anyone has any idea how can I make it work even if im writing in a notepad?
Key logging can be used for naughty stuff, and manipulating Caps Lock like that seems rather strange, but since the info is already publicly available, and you know your user stories better than me, I've posted a solution.
Here's an example based on the code snippet posted from keylogger code in C# in the MSDN forum.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
class Program
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private static bool lastKeyWasLetter = false;
[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);
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
_hookID = SetHook(_proc);
Application.Run();
UnhookWindowsHookEx(_hookID);
}
private static 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 static void ToggleCapsLock()
{
const int KEYEVENTF_EXTENDEDKEY = 0x1;
const int KEYEVENTF_KEYUP = 0x2;
UnhookWindowsHookEx(_hookID);
keybd_event(0x14, 0x45, KEYEVENTF_EXTENDEDKEY, (UIntPtr)0);
keybd_event(0x14, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, (UIntPtr)0);
_hookID = SetHook(_proc);
}
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
if (lastKeyWasLetter)
{
if (Control.IsKeyLocked(System.Windows.Forms.Keys.CapsLock))
{
ToggleCapsLock();
}
lastKeyWasLetter = false;
}
Keys key = (Keys)Marshal.ReadInt32(lParam);
if (key == Keys.Space)
{
if (!Control.IsKeyLocked(System.Windows.Forms.Keys.CapsLock))
{
ToggleCapsLock();
}
}
else if (key >= Keys.A && key <= Keys.Z)
{
lastKeyWasLetter = true;
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
}
Paste that into a new Windows application's Program.cs in Visual Studio to try it out.
If you intercept a key down event to turn Caps Lock on and off, then the event is intercepted before the application handles it. This means that turning Caps Lock off when a letter key is pressed will result in the application you are typing in receiving a lower case letter, even directly after a space.
I've assumed you are trying to force the capitalization of the first letter in each word (and if so, you may need to handle other keys such as Return too), so my snippet will only turn Caps Lock off on the next key down event following a letter being pressed. Note that you can't just try and capture the key up, as when typing fast you may hold the initial key down until after you've pressed the following key.