I'm creating an UserControl that should react if the mouse is over the control and MouseWheel gets rotated.
Currently i'm doing this as shown here:
public MyUserControl()
{
this.MouseWheel += new MouseEventHandler(MouseWheelHandler);
}
private void MouseWheelHandler(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Delta > 0)
incIndex();
if (e.Delta < 0)
decIndex();
}
protected override void OnMouseEnter(EventArgs e)
{
this.Focus();
base.OnMouseEnter(e);
}
In fact this works fine, but the problem is the part with the "this.Focus();" as it destroys my forms / applications behaviour.
Is there a better way to achive this?
having the same problem, I finally implemented a mix of both solution by #Paul_Westcott and #nr1. This is a local solution like solution of #Paul_Westcott (only applies to the winforms control that subscribes to). It is multiple monitor safe and MDI safe (overlapping by other windows within the application)
public static class MouseWheelHandlerForWinformsControl
{
private class MouseWheelMessageFilter : IMessageFilter
{
[DllImport("user32.dll")]
private static extern IntPtr WindowFromPoint(Point pt);
private readonly Control mCtrl;
private readonly Action<MouseEventArgs> mOnMouseWheel;
public MouseWheelMessageFilter(Control ctrl, Action<MouseEventArgs> onMouseWheel)
{
mCtrl = ctrl;
mOnMouseWheel = onMouseWheel;
}
public bool PreFilterMessage(ref Message m)
{
// handle only mouse wheel messages
if (m.Msg != 0x20a)
return false;
Point mouseAbsolutePosition = new Point(m.LParam.ToInt32());
Point mouseRelativePosition = mCtrl.PointToClient(mouseAbsolutePosition);
IntPtr hControlUnderMouse = WindowFromPoint(mouseAbsolutePosition);
Control controlUnderMouse = Control.FromHandle(hControlUnderMouse);
if (controlUnderMouse != mCtrl)
return false;
MouseButtons buttons = GetMouseButtons(m.WParam.ToInt32());
int delta = m.WParam.ToInt32() >> 16;
var e = new MouseEventArgs(buttons, 0, mouseRelativePosition.X, mouseRelativePosition.Y, delta);
mOnMouseWheel(e);
return true;
}
private static MouseButtons GetMouseButtons(int wParam)
{
MouseButtons buttons = MouseButtons.None;
if(HasFlag(wParam, 0x0001)) buttons |= MouseButtons.Left;
if(HasFlag(wParam, 0x0010)) buttons |= MouseButtons.Middle;
if(HasFlag(wParam, 0x0002)) buttons |= MouseButtons.Right;
if(HasFlag(wParam, 0x0020)) buttons |= MouseButtons.XButton1;
if(HasFlag(wParam, 0x0040)) buttons |= MouseButtons.XButton2;
return buttons;
}
private static bool HasFlag(int input, int flag)
{
return (input & flag) == flag;
}
}
public static void MemorySafeAdd(Control ctrl, Action<MouseEventArgs> onMouseWheel)
{
if (ctrl == null || onMouseWheel == null)
throw new ArgumentNullException();
var filter = new MouseWheelMessageFilter(ctrl, onMouseWheel);
Application.AddMessageFilter(filter);
ctrl.Disposed += (s, e) => Application.RemoveMessageFilter(filter);
}
}
Once you have added this helper class into your solution, you subscribe a control myControl to the mouse-wheel, in one line, as following:
public void Init() {
MouseWheelHandlerForWinformsControl.MemorySafeAdd(myControl, OnMouseWheelEvent);
}
void OnMouseWheelEvent(MouseEventArgs args) {
// do what you need here
}
Copy pasted from http://social.msdn.microsoft.com/forums/en-US/winforms/thread/eb922ed2-1036-41ca-bd15-49daed7b637c/
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsApplication1 {
public partial class Form1 : Form, IMessageFilter {
public Form1() {
InitializeComponent();
Application.AddMessageFilter(this);
}
public bool PreFilterMessage(ref Message m) {
if (m.Msg == 0x20a) {
// WM_MOUSEWHEEL, find the control at screen position m.LParam
Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
IntPtr hWnd = WindowFromPoint(pos);
if (hWnd != IntPtr.Zero && hWnd != m.HWnd && Control.FromHandle(hWnd) != null) {
SendMessage(hWnd, m.Msg, m.WParam, m.LParam);
return true;
}
}
return false;
}
// P/Invoke declarations
[DllImport("user32.dll")]
private static extern IntPtr WindowFromPoint(Point pt);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
}
}
this works great, thx Hans Passant
Just a slight variation on the solution that has already been published, in order to not have to use P/Invoke.
public static class MouseWheelHandler
{
public static void Add(Control ctrl, Action<MouseEventArgs> onMouseWheel)
{
if (ctrl == null || onMouseWheel == null)
throw new ArgumentNullException();
var filter = new MouseWheelMessageFilter(ctrl, onMouseWheel);
Application.AddMessageFilter(filter);
ctrl.Disposed += (s, e) => Application.RemoveMessageFilter(filter);
}
class MouseWheelMessageFilter
: IMessageFilter
{
private readonly Control _ctrl;
private readonly Action<MouseEventArgs> _onMouseWheel;
public MouseWheelMessageFilter(Control ctrl, Action<MouseEventArgs> onMouseWheel)
{
_ctrl = ctrl;
_onMouseWheel = onMouseWheel;
}
public bool PreFilterMessage(ref Message m)
{
var parent = _ctrl.Parent;
if (parent != null && m.Msg == 0x20a) // WM_MOUSEWHEEL, find the control at screen position m.LParam
{
var pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
var clientPos = _ctrl.PointToClient(pos);
if (_ctrl.ClientRectangle.Contains(clientPos)
&& ReferenceEquals(_ctrl, parent.GetChildAtPoint(parent.PointToClient(pos))))
{
var wParam = m.WParam.ToInt32();
Func<int, MouseButtons, MouseButtons> getButton =
(flag, button) => ((wParam & flag) == flag) ? button : MouseButtons.None;
var buttons = getButton(wParam & 0x0001, MouseButtons.Left)
| getButton(wParam & 0x0010, MouseButtons.Middle)
| getButton(wParam & 0x0002, MouseButtons.Right)
| getButton(wParam & 0x0020, MouseButtons.XButton1)
| getButton(wParam & 0x0040, MouseButtons.XButton2)
; // Not matching for these /*MK_SHIFT=0x0004;MK_CONTROL=0x0008*/
var delta = wParam >> 16;
var e = new MouseEventArgs(buttons, 0, clientPos.X, clientPos.Y, delta);
_onMouseWheel(e);
return true;
}
}
return false;
}
}
}
And then this can used from individual controls like
class MyControl
: Control
{
public MyControl()
{
...
MouseWheelHandler.Add(this, MyOnMouseWheel);
}
void MyOnMouseWheel(MouseEventArgs e)
{
...
}
}
Paul Westcott's answer works great when using a FlowLayoutPanel. My implementation of MyOnMouseWheel event is:
void MyOnMouseWheel(MouseEventArgs e)
{
int ChangeIncrement = (this.panel1.VerticalScroll.SmallChange * 4); //Change the 4 to any positive number to scroll more or less one each scroll event.
if (e.Delta < 0)
{
int NewValue = this.panel1.VerticalScroll.Value + ChangeIncrement;
if (NewValue > this.panel1.VerticalScroll.Maximum)
{
this.panel1.VerticalScroll.Value = this.panel1.VerticalScroll.Maximum;
}
else
{
this.panel1.VerticalScroll.Value = NewValue;
}
}
else if (e.Delta > 0)
{
int NewValue = this.panel1.VerticalScroll.Value - ChangeIncrement;
if (NewValue < this.panel1.VerticalScroll.Minimum)
{
this.panel1.VerticalScroll.Value = this.panel1.VerticalScroll.Minimum;
}
else
{
this.panel1.VerticalScroll.Value = NewValue;
}
}
this.panel1.PerformLayout();
}
Related
When dragging a borderless form to the top of the screen; if the Y coordinate is negative, it sets it back to 0. What I'm looking to do is be able to drag the form above the top, where the Y coordinate would be negative, the same way you can with every other side of the screen.
Here is what I have tried:
public partial class BorderlessForm : Form
{
public BorderlessForm()
{
InitializeComponent();
}
private bool _isNegative;
private Point _negative;
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("user32.dll")]
public static extern bool ReleaseCapture();
protected override void OnMouseDown(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left) {
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
protected override void OnResizeEnd(EventArgs e)
{
if (_isNegative) {
Location = _negative;
}
//base.OnResizeEnd(e);
}
protected override void OnMove(EventArgs e)
{
if (Location.Y < 0) {
_isNegative = true;
_negative = Location;
}
else {
_isNegative = false;
}
//base.OnMove(e);
}
}
This was the best I could come up with after thinking on it for a while. The problem is that when the mouse is released and the form is finished moving, OnMove is called before OnResizeEnd, and _isNegative is then set back to false. At least, that is what I assume is happening.
Do I have the right idea, or is there some better way to go about this?
So, I thought more about what isaeid said, and was able to come up with a solution. Still not sure if this is the best way to go about it, but here it is:
public partial class ImageForm : PerPixelAlphaForm
{
public ImageForm()
{
InitializeComponent();
}
private bool _isNegative;
private Point _negative;
private bool _flag;
protected override void OnMouseDown(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left) {
NativeMethods.ReleaseCapture();
NativeMethods.SendMessage(Handle, NativeMethods.WM_NCLBUTTONDOWN, NativeMethods.HT_CAPTION, 0);
}
}
protected override void OnResizeEnd(EventArgs e)
{
if (_isNegative) {
Location = _negative;
_isNegative = false;
}
}
protected override void OnMove(EventArgs e)
{
if (Location.Y < 0) {
_isNegative = true;
_flag = true;
_negative = Location;
}
else {
if (_flag) {
_flag = false;
return;
}
_isNegative = false;
}
}
}
You can change some events like this:
protected override void OnResizeEnd(EventArgs e)
{
if (_isNegative)
{
Location = _negative;
}
oldRight = this.Right;
oldBottom = this.Bottom;
//base.OnResizeEnd(e);
}
protected override void OnMove(EventArgs e)
{
if ( this.Right == oldRight || this.Bottom == oldBottom)
return;
if (Location.Y < 0)
{
_isNegative = true;
_negative = Location;
}
else
{
_isNegative = false;
}
//base.OnMove(e);
}
When top or left of window is changed, dotnet determines location of window is changed and calls onmove event, i consider if right or bottom of the window is not changed so window's location is not changed.
Add this codes too:
int oldBottom, oldRight;
private void BorderlessForm_Load(object sender, EventArgs e)
{
oldRight = this.Right;
oldBottom = this.Bottom;
}
I want to know how to use it....I want to say that if I Click Up and Right Arrow (Form1_KeyDown Event) then timer1.Start();
and When I release the Up and Right Arrow (Form1_KeyUp Event) then timer1.Stop();
I have already Imported the "User32.dll"
using System.Runtime.InteropServices;
[DllImport("User32.dll")]
public static extern short GetAsyncKeyState(Keys ArrowKeys);
so How to use it...I see a lot of website but can't get it
Implement IMessageFilter for you Form and track when the Up/Right Arrows are toggled:
public partial class form1 : Form, IMessageFilter
{
public form1()
{
InitializeComponent();
Application.AddMessageFilter(this);
}
private bool UpDepressed = false;
private bool RightDepressed = false;
private const int WM_KEYDOWN = 0x100;
private const int WM_KEYUP = 0x101;
public bool PreFilterMessage(ref Message m)
{
switch (m.Msg)
{
case WM_KEYDOWN:
if ((Keys)m.WParam == Keys.Up)
{
UpDepressed = true;
}
else if ((Keys)m.WParam == Keys.Right)
{
RightDepressed = true;
}
break;
case WM_KEYUP:
if ((Keys)m.WParam == Keys.Up)
{
UpDepressed = false;
}
else if ((Keys)m.WParam == Keys.Right)
{
RightDepressed = false;
}
break;
}
timer1.Enabled = (UpDepressed && RightDepressed);
label1.Text = timer1.Enabled.ToString();
return false;
}
private void timer1_Tick(object sender, EventArgs e)
{
label2.Text = DateTime.Now.ToString("ffff");
}
}
Here is how you can use it
int keystroke;
byte[] result = BitConverter.GetBytes(GetAsyncKeyState(keystroke));
if (result[0] == 1)
Console.Writeline("the key was pressed after the previous call to GetAsyncKeyState.")
if (result[1] == 0x80)
Console.Writeline("The key is down");
change
[DllImport("User32.dll")]
public static extern short GetAsyncKeyState(Keys ArrowKeys);
to
[DllImport("User32.dll")]
public static extern bool GetAsyncKeyState(Keys ArrowKeys);
async key state should be a bool not a short
TreeView leaks resource (2 DC handles and 2 Bitmap handles) when TreeView CheckBoxes=true because of a bug, and I dealt with it:
public class TreeViewCustom : TreeView
{
public new bool CheckBoxes
{
get
{
return base.CheckBoxes;
}
set
{
if (base.CheckBoxes == false)
{
base.CheckBoxes = true;
IntPtr handle = SendMessage(this.Handle, TVM_GETIMAGELIST, new IntPtr(TVSIL_STATE), IntPtr.Zero);
if (handle != IntPtr.Zero)
_checkboxImageList = handle;
}
}
}
/// <summary>
/// The handle to the state ImageList
/// </summary>
private IntPtr _checkboxImageList = IntPtr.Zero;
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x203) // double click
m.Result = IntPtr.Zero;
else
base.WndProc(ref m);
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Right)
{
Focus();
SelectedNode = GetNodeAt(e.X, e.Y);
}
}
[DllImport("comctl32.dll", CharSet = CharSet.Auto)]
public static extern bool ImageList_Destroy(IntPtr hImageList);
[DllImport("comctl32.dll", CharSet = CharSet.Auto)]
public static extern bool ImageList_RemoveAll(IntPtr hImageList);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern System.IntPtr SendMessage(IntPtr hWnd, uint Msg,
IntPtr wParam, IntPtr lParam);
const uint TV_FIRST = 0x1100;
const uint TVM_GETIMAGELIST = TV_FIRST + 8;
const int TVSIL_NORMAL = 0;
const int TVSIL_STATE = 2;
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_checkboxImageList != IntPtr.Zero)
{
ImageList_Destroy(_checkboxImageList);
}
base.Dispose(disposing);
this.DestroyHandle();
}
else base.Dispose(disposing);
}
}
And everything is OK, except when treeview.ShowNodeToolTips is set to true, then the resources still leak, even with the fix. I think the tooltip is a problem (ToolTips also leak handles if you don't dispose of them properly)
EDIT:
(Why the leak happens when CheckBoxes = true)
When CheckBoxes is set to true, the style is set to the TreeView, and it can be done only once. This causes an CheckBoxImageList to be created. The list contains 2 bitmaps: the checked and unchecked box, every object in the list has a DC handle and a BITMAP handle (that's why 4 handles are leaked for each instance). When the TreeView is disposed, the list of images isn't destroyed, hence the leak.
(Why the leak happens when ShowNodeToolTips=true - my suspicions, http://reflector.webtropy.com/default.aspx/DotNET/DotNET/8#0/untmp/whidbey/REDBITS/ndp/fx/src/WinForms/Managed/System/WinForms/TreeView#cs/2/TreeView#cs)
The TootTip holds the reference to the control, if the ToolTip is not disposed, the control stays in the memory too. When ShowNodeToolTips = true, the ToolTip is created and associated with the TreeView, and it isn't disposed when TreeView is disposed.
The code I use for testing:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form_Tv form = new Form_Tv();
form.StartPosition = FormStartPosition.CenterParent; ;
form.ShowDialog();
form.Dispose();
GC.Collect();
}
}
public partial class Form_Tv : Form
{
public Form_Tv()
{
InitializeComponent();
for (int i = 0; i < 100; i++)
{
TreeViewCustom tv = new TreeViewCustom();
tv.CheckBoxes = true;
tv.ShowNodeToolTips = true;
this.Controls.Add(tv);
}
this.FormClosed += new FormClosedEventHandler(Form_Tv_FormClosed);
this.ControlRemoved += new ControlEventHandler(Form_Tv_ControlRemoved);
}
void Form_Tv_ControlRemoved(object sender, ControlEventArgs e)
{
e.Control.Dispose();
}
void Form_Tv_FormClosed(object sender, FormClosedEventArgs e)
{
this.Controls.Clear();
}
}
Test results (Windows 7):
Form1 is the main form of the application. After it's shown:
DC: 7 Bitmap: 3
After Form_Tv is shown:
DC: 409 Bitmap: 405
After Form_Tv is closed:
DC: 209 Bitmap: 205
My question:
How can I get a hold of the ToolTip that is set for the TreeView when ShowNodeToolTips is set to true, and how can I properly dispose of it?
How do I check user is inactive?
I have this:
class UserActivity : IMessageFilter
{
private double afk_time = 0.1;//minutes
private DateTime last_activity = DateTime.Now;
public static bool inactive = false;
private int WM_LBUTTONDOWN = 0x0201;
private int WM_MBUTTONDOWN = 0x0207;
private int WM_RBUTTONDOWN = 0x0204;
private int WM_MOUSEWHEEL = 0x020A;
private int WM_MOUSEMOVE = 0x0200;
private int WM_KEYDOWN = 0x0100;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_LBUTTONDOWN || m.Msg == WM_MBUTTONDOWN || m.Msg == WM_RBUTTONDOWN || m.Msg == WM_MOUSEWHEEL || m.Msg == WM_MOUSEMOVE || m.Msg == WM_KEYDOWN)
{
this.last_activity = DateTime.Now;
inactive = false;
}
if (DateTime.Now.AddMinutes(-afk_time) > last_activity)
inactive = true;
return false;
}
}
But I must run it in Program.cs
Application.AddMessageFilter(new UserActivity());
How can I do that I can run the checking of user inactivity by my self. I'll check some checkbox and it will start checking.
And I want check global user activity - in all system not only in app.
I don't want use of cpu unnecessary. Or should I use another solution?
I found this and it works perfect !
So if another one have problem with it here is solution:
[StructLayout(LayoutKind.Sequential)]
public struct LASTINPUTINFO
{
public uint cbSize;
public uint dwTime;
}
[DllImport("user32.dll")]
static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
public static TimeSpan? GetInactiveTime()
{
LASTINPUTINFO info = new LASTINPUTINFO();
info.cbSize = (uint)Marshal.SizeOf(info);
if (GetLastInputInfo(ref info))
return TimeSpan.FromMilliseconds(Environment.TickCount - info.dwTime);
else
return null;
}
I have tried to build a class base on previous answer, I have test it and it work properly.
It is async but i have not use async key. If someone finds some problem or amelioration so welcome.
public class User
{
[StructLayout(LayoutKind.Sequential)]
public struct LASTINPUTINFO
{
public uint cbSize;
public uint dwTime;
}
[DllImport("user32.dll")]
static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
public static TimeSpan? GetInactiveTime()
{
LASTINPUTINFO info = new LASTINPUTINFO();
info.cbSize = (uint)Marshal.SizeOf(info);
if (GetLastInputInfo(ref info))
return TimeSpan.FromMilliseconds(Environment.TickCount - info.dwTime);
else
return null;
}
private TimeSpan? LastTime;
private DispatcherTimer timer = new DispatcherTimer();
public void RequestUserActivity()
{
LastTime = GetInactiveTime();
timer.Interval = TimeSpan.FromMilliseconds(500);
timer.Tick += timer_Tick;
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
TimeSpan? tmpTime = GetInactiveTime();
if (LastTime.HasValue && tmpTime.HasValue && tmpTime < LastTime)
{
timer.Stop();
UserAtivited(this, new EventArgs());
}
else if (!LastTime.HasValue || !tmpTime.HasValue)
{
timer.Stop();
throw new Exception();
}
}
public event EventHandler UserAtivited;
}
Now In your window create a new instance of User, register to UserActivated event and laugth RequestUserActivity(). I expert it will be helpfull.
Please, do not have regards on my poor english. I'm french speaker.
How can I create an application that performs an action with keyboard shortcut (App must be unvisible). For example Shows MessageBox when user press Ctrl + Alt + W.
One solution would be to use interop and use the Win32 RegisterHotKey API. Here is a quick and dirty example I just put together so it is not well tested and I am not sure that there are no unexepcted side effects, but it should work.
First here is a simple HotKeyManager this takes care of the basic interop, provides a hidden window to handle the native Windows messages (WM_HOTKEY) which is translated into a .NET event HotKeyPressed
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public class HotKeyManager
{
public static event EventHandler<HotKeyEventArgs> HotKeyPressed;
public static int RegisterHotKey(Keys key, KeyModifiers modifiers)
{
int id = System.Threading.Interlocked.Increment(ref _id);
RegisterHotKey(_wnd.Handle, id, (uint)modifiers, (uint)key);
return id;
}
public static bool UnregisterHotKey(int id)
{
return UnregisterHotKey(_wnd.Handle, id);
}
protected static void OnHotKeyPressed(HotKeyEventArgs e)
{
if (HotKeyManager.HotKeyPressed != null)
{
HotKeyManager.HotKeyPressed(null, e);
}
}
private static MessageWindow _wnd = new MessageWindow();
private class MessageWindow : Form
{
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_HOTKEY)
{
HotKeyEventArgs e = new HotKeyEventArgs(m.LParam);
HotKeyManager.OnHotKeyPressed(e);
}
base.WndProc(ref m);
}
private const int WM_HOTKEY = 0x312;
}
[DllImport("user32")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[DllImport("user32")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
private static int _id = 0;
}
public class HotKeyEventArgs : EventArgs
{
public readonly Keys Key;
public readonly KeyModifiers Modifiers;
public HotKeyEventArgs(Keys key, KeyModifiers modifiers)
{
this.Key = key;
this.Modifiers = modifiers;
}
public HotKeyEventArgs(IntPtr hotKeyParam)
{
uint param = (uint)hotKeyParam.ToInt64();
Key = (Keys)((param & 0xffff0000) >> 16);
Modifiers = (KeyModifiers)(param & 0x0000ffff);
}
}
[Flags]
public enum KeyModifiers
{
Alt = 1,
Control = 2,
Shift = 4,
Windows = 8,
NoRepeat = 0x4000
}
The following shows a simple windows forms application which will keep the main form hidden and respond to the hot key events. I did not handle the closing of the application and the unregistering of the hot key, you can handle that.
using System;
using System.Windows.Forms;
namespace HotKeyManager
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
HotKeyManager.RegisterHotKey(Keys.A, KeyModifiers.Alt);
HotKeyManager.HotKeyPressed += new EventHandler<HotKeyEventArgs>(HotKeyManager_HotKeyPressed);
}
void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e)
{
MessageBox.Show("Hello");
}
protected override void SetVisibleCore(bool value)
{
// Quick and dirty to keep the main window invisible
base.SetVisibleCore(false);
}
}
}
Add this to KeyPress event of your form:
if(e.KeyCode == (char)Keys.W && e.Modifiers == Keys.Control && e.Modifiers = Keys.Alt)
{
MessageBox.Show("I think this is a homework and that you should study instead of asking for an already cooked up answer on programming websites","Cheater");
}