I'm currently trying to set a single key as global hook. Howerver, I was perhaps wondering if it's possible to manipulate this code, so that a single button is set as a global hot key?
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[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 B = 0x42;
const int MOD_SHIFT = 0x0004;
const int WM_HOTKEY = 0x0312;
private void Form1_Load(object sender, EventArgs e)
{
RegisterHotKey(this.Handle, 1, B + MOD_SHIFT, (int)Keys.X);
RegisterHotKey(this.Handle, 2, B + MOD_SHIFT, (int)Keys.Y);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
UnregisterHotKey(this.Handle, 1);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_HOTKEY && (int)m.WParam == 1)
MessageBox.Show("Hotkey X pressed.");
if (m.Msg == WM_HOTKEY && (int)m.WParam == 2)
MessageBox.Show("Hotkey Y pressed.");
base.WndProc(ref m);
}
}
}
Related
This is the first code I've written in c#, and my first question to Stackoverflow...apologies up front if I'm doing everything wrong! :-/
I've tried to implement the Public Class RTFScrolledToBottom written by LarsTech that was posted as answered the question here:
Get current scroll position from rich text box control?
In the public Form1() code block, this line is generating a CS1061 error:
rtfScrolledBottom1.ScrolledToBottom += rtfScrolledBottom1_ScrolledToBottom;
object does not contain a definition for ScrolledToBottom and no accessible extension method ScrolledToBottom accepting a first argument of type object could be found (are you missing a using directive or an assembly reference?)
Thanks in advance for any assistance pointing me to what I'm screwing up!!
Cheers!
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private object rtfScrolledBottom1;
public Form1()
{
InitializeComponent();
int rtfScrolledBottom1_ScrolledToBottom = 0;
rtfScrolledBottom1.ScrolledToBottom += rtfScrolledBottom1_ScrolledToBottom;
}
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
}
}
public class RTFScrolledBottom : RichTextBox
{
public event EventHandler ScrolledToBottom;
private const int WM_VSCROLL = 0x115;
private const int WM_MOUSEWHEEL = 0x20A;
private const int WM_USER = 0x400;
private const int SB_VERT = 1;
private const int EM_SETSCROLLPOS = WM_USER + 222;
private const int EM_GETSCROLLPOS = WM_USER + 221;
[DllImport("user32.dll")]
private static extern bool GetScrollRange(IntPtr hWnd, int nBar, out int lpMinPos, out int lpMaxPos);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);
public bool IsAtMaxScroll()
{
int minScroll;
int maxScroll;
GetScrollRange(this.Handle, SB_VERT, out minScroll, out maxScroll);
Point rtfPoint = Point.Empty;
SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref rtfPoint);
return (rtfPoint.Y + this.ClientSize.Height >= maxScroll);
}
protected virtual void OnScrolledToBottom(EventArgs e)
{
if (ScrolledToBottom != null)
ScrolledToBottom(this, e);
}
protected override void OnKeyUp(KeyEventArgs e)
{
if (IsAtMaxScroll())
OnScrolledToBottom(EventArgs.Empty);
base.OnKeyUp(e);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_VSCROLL || m.Msg == WM_MOUSEWHEEL)
{
if (IsAtMaxScroll())
OnScrolledToBottom(EventArgs.Empty);
}
base.WndProc(ref m);
}
}
}
You have defined rtfScrolledBottom1 as object and object doesn't have any event. You need to define it as RTFScrolledBottom. You also can drop an instance of the RTFScrolledBottom control from toolbox and use it like any other control.
Alternative solution
As an alternative to the solution which you found in the linked post, here is another solution which Works with RichTextBox without creating a derived control, while you can put the logic in a derived control and make it more reusable, like what has done in the linked post.
You can handle VScroll event of the RichTextBox and get the scroll position by calling GetScrollInfo method. Then in the SCROLLINFO if nPage + nPos == nMax, it means the scroll is at bottom:
[StructLayout(LayoutKind.Sequential)]
struct SCROLLINFO {
public int cbSize;
public ScrollInfoMask fMask;
public int nMin;
public int nMax;
public uint nPage;
public int nPos;
public int nTrackPos;
}
public enum ScrollInfoMask : uint {
SIF_RANGE = 0x1,
SIF_PAGE = 0x2,
SIF_POS = 0x4,
SIF_DISABLENOSCROLL = 0x8,
SIF_TRACKPOS = 0x10,
SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS),
}
[DllImport("user32.dll")]
private static extern bool GetScrollInfo(IntPtr hwnd, SBOrientation fnBar,
ref SCROLLINFO lpsi);
public enum SBOrientation : int { SB_HORZ = 0x0, SB_VERT = 0x1 }
private void richTextBox1_VScroll(object sender, EventArgs e)
{
var info = new SCROLLINFO() {
cbSize = (Marshal.SizeOf<SCROLLINFO>()),
fMask = ScrollInfoMask.SIF_ALL
};
GetScrollInfo(richTextBox1.Handle, SBOrientation.SB_VERT, ref info);
if (info.nPage + info.nPos == info.nMax)
{
//VScroll is at bottom
}
}
I want to send message to other process already running. What wrong...? why I am not able to receive messages
My sender code is as below
public partial class RegisterWindowMessage : Form
{
[DllImport("User32.dll", EntryPoint = "SendMessage")]
//private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
private static extern int SendMessage(IntPtr hWnd, int Msg, string s, int i);
const int WM_SETTEXT = 0X000C;
public RegisterWindowMessage()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Process[] procs = Process.GetProcesses();
foreach (Process p in procs)
{
if (p.ProcessName.Equals("TaskScheduling"))
{
IntPtr hWnd = p.MainWindowHandle;
Thread.Sleep(1000);
SendMessage(hWnd, WM_SETTEXT, "This is the new Text!!!", 0);
MessageBox.Show("Inside");
}
}
}
private void button2_Click(object sender, EventArgs e)
{
}
}
My receiver code is
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
}
private void frmReceiver_KeyDown(object sender, KeyEventArgs e)
{
// this.lsvMsgList.Items.Add(e.KeyValue.ToString());
}
protected override void WndProc(ref Message m)
{
MessageBox.Show(m.Msg.ToString());
MessageBox.Show(m.LParam.ToString());
MessageBox.Show(m.WParam.ToString());
if (m.LParam.ToInt32() == 1)
{
}
else
{
base.WndProc(ref m);
}
}
}
I want to know why i am not able to receive message. Let me know where I am wrong
I'm working on a program, who need to detect when the user press the keyboard or use his mouse, even if the program is minimized or not focused.
I think I have to use the windows API, keybd_event (user32), but I don't know how to use the "listener" of this event. I have something like that:
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags,UIntPtr dwExtraInfo);
void PressKey(byte keyCode)
{
//My code here
}
I did some research, but it's the first time I have to use DllImport, so I don't know how to continue ...
Thanks
(Ps:Sorry about my bad English, this is not my native language :) )
(PPs: I've read all of your answers, but it takes a while to read every link, so I'll work on it tonight, but I think I will find the answer. Anyway, thanks for the links everybody ;) )
Edit: So I just finished my code and it's work :) It looks something like:
[DllImport("user32.dll")]
public static extern Boolean GetLastInputInfo(ref tagLASTINPUTINFO plii);
public struct tagLASTINPUTINFO
{
public uint cbSize;
public Int32 dwTime;
}
private void timerTemps_Inactif_Tick(object sender, EventArgs e)
{
tagLASTINPUTINFO LastInput = new tagLASTINPUTINFO();
Int32 IdleTime;
LastInput.cbSize = (uint)Marshal.SizeOf(LastInput);
LastInput.dwTime = 0;
if (GetLastInputInfo(ref LastInput))
{
IdleTime = System.Environment.TickCount - LastInput.dwTime;
if (IdleTime > 10000)
{
//My code here
}
}
}
Thanks for the help guys ;)
You will need to hook into Windows OS with SetWindowsHookEx function. You should read the article Keyloggers: How they work and how to detect them posted by SecureList to get a understanding ofthe process.
I have always got a good performance by using RegisterHotKey/UnregisterHotKey functions. Sample code:
[DllImport("User32")]
public static extern bool RegisterHotKey(
IntPtr hWnd,
int id,
int fsModifiers,
int vk
);
[DllImport("User32")]
public static extern bool UnregisterHotKey(
IntPtr hWnd,
int id
);
public const int MOD_SHIFT = 0x4;
public const int MOD_CONTROL = 0x2;
public const int MOD_ALT = 0x1;
public const int WM_HOTKEY = 0x312;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_HOTKEY && m.WParam == (IntPtr)0)
{
IntPtr lParamCTRLA = (IntPtr)4259842;
IntPtr lParamB = (IntPtr)4325376;
if (m.LParam == lParamCTRLA)
{
MessageBox.Show("CTRL+A was pressed");
}
else if (m.LParam == lParamB)
{
MessageBox.Show("B was pressed");
}
}
base.WndProc(ref m);
}
private void Form1_Load(object sender, EventArgs e)
{
this.FormClosing += new FormClosingEventHandler(Form1_FormClosing);
RegisterHotKey(this.Handle, 0, MOD_CONTROL, (int)Keys.A);
RegisterHotKey(this.Handle, 0, 0, (int)Keys.B);
}
private void Form1_FormClosing(Object sender, FormClosingEventArgs e)
{
UnregisterHotKey(this.Handle, 0);
}
You can "register" as many keys (or combination of keys) as you want by emulating the shown structure. All the registered keys will get inside the condition if (m.Msg == WM_HOTKEY && m.WParam == (IntPtr)0); if they are pressed at all (independently upon the program currently being selected). The easiest way to know the specific key/combination being pressed is relying on m.LParam (I got the two values I am including after a quick test with the given keys). You can do a quick research to find out a list of LParam or further constant modifiers (wheel of the mouse, for example).
The final code:
[DllImport("user32.dll")]
public static extern Boolean GetLastInputInfo(ref tagLASTINPUTINFO plii);
public struct tagLASTINPUTINFO
{
public uint cbSize;
public Int32 dwTime;
}
private void timerTemps_Inactif_Tick(object sender, EventArgs e)
{
tagLASTINPUTINFO LastInput = new tagLASTINPUTINFO();
Int32 IdleTime;
LastInput.cbSize = (uint)Marshal.SizeOf(LastInput);
LastInput.dwTime = 0;
if (GetLastInputInfo(ref LastInput))
{
IdleTime = System.Environment.TickCount - LastInput.dwTime;
if (IdleTime > 10000)
{
//My code here
}
}
}
I want to make in my application, than when this application is in background, when I will click F10, the function with loop will be start.
This is my code:
namespace test
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
public Form1() //(lub Form1_Load(object sender, System.EventArgs e))
{
RegisterHotKey(this.Handle,9000, 2, (int) Keys.F10);
InitializeComponent();
}
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
UnregisterHotKey(this.Handle,9000);
UnregisterHotKey(this.Handle,9001);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case 0x312:
switch (m.WParam.ToInt32())
{
case 9000:
//code
break;
case 9001:
//code
break;
}
break;
}
}
}
}
But don't work :(
Can you help me please?
when I will click F10
Wrong key, you have to type Ctrl+F10. You passed 2 as the 3rd argument to RegisterHotKey(), that's MOD_CONTROL. Using const or enum declarations instead of raw literals help you fall in the pit of success.
I am using the below code to disable the hotkeys like Alt + f4, ctrl + c which are working perfectly. But I could not register win + L using the below code.
namespace KioskMode
{
public partial class Test : Form
{
#region Dynamic Link Library Imports
[DllImport("user32.dll")]
private static extern int FindWindow(string cls, string wndwText);
[DllImport("user32.dll")]
private static extern int ShowWindow(int hwnd, int cmd);
[DllImport("user32.dll")]
private static extern long SHAppBarMessage(long dword, int cmd);
[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);
#endregion
#region Modifier Constants and Variables
// Constants for modifier keys
private const int USE_ALT = 1;
private const int USE_CTRL = 2;
private const int USE_SHIFT = 4;
private const int USE_WIN = 8;
// Hot key ID tracker
short mHotKeyId = 0;
#endregion
public Test()
{
InitializeComponent();
RegisterGlobalHotKey(Keys.F4, USE_ALT);
RegisterGlobalHotKey(Keys.L, USE_WIN);
}
private void RegisterGlobalHotKey(Keys hotkey, int modifiers)
{
try
{
mHotKeyId++;
if (mHotKeyId > 0)
{
// register the hot key combination
if (RegisterHotKey(this.Handle, mHotKeyId, modifiers, Convert.ToInt16(hotkey)) == 0)
{
MessageBox.Show("Error: " + mHotKeyId.ToString() + " - " +
Marshal.GetLastWin32Error().ToString(),
"Hot Key Registration");
}
}
}
catch
{
UnregisterGlobalHotKey();
}
}
private void UnregisterGlobalHotKey()
{
for (int i = 0; i < mHotKeyId; i++)
{
UnregisterHotKey(this.Handle, i);
}
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
const int WM_HOTKEY = 0x312;
if (m.Msg == WM_HOTKEY)
{
// Ignore the request or each
// disabled hotkey combination
}
}
}
}
You cannot register it since Windows already uses it as hotkey. If you really want to do it, you must register a low-level keyboard hook.
Reason why you can register Alt+F4, Ctrl+C... is that those keys are not hotkeys (they are just processed in wndproc).
Why not look into doing this through group policy or editing the registry instead?