Textbox not clickable but editable - c#

I have a small form with 10 textboxes, I have them set in the right Tab Order currently the way I want them to Tab To. I was wondering if there is a way to set the textboxes up so they cannot be selected for editing unless they are Tabbed into. ie... I don't want the end user to be able to click on the textbox to edit them, I only want them editable through Tabbing.

This should do the trick
public partial class PoorTextBox : TextBox
{
protected override void WndProc(ref Message m)
{
if (m.Msg == (int) WM.LBUTTONDOWN)
{
return;//Eat mouse down events
}
base.WndProc(ref m);
}
}
Window messages enum can be found here.
How to do it without inheriting TextBox :
class EatMouseDown : NativeWindow
{
protected override void WndProc(ref Message m)
{
if (m.Msg == (int)WM.LBUTTONDOWN)
{
return;
}
base.WndProc(ref m);
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
new EatMouseDown().AssignHandle(textBox1.Handle);//Subclass a Handle
}
How to do it without any inheritance:
Clean up part omitted, which is also important. This may be buggy but that works. Recommended way is to use inheritance. Required methods pulled from .net fw src.
class EatMouseDown
{
public delegate IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
#region External methods...
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetWindowLong(HandleRef hWnd, int nIndex, WndProc wndproc);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetWindowLongPtr(HandleRef hWnd, int nIndex, WndProc wndproc);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetWindowLong(HandleRef hWnd, int nIndex);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetWindowLongPtr(HandleRef hWnd, int nIndex);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr DefWindowProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr CallWindowProc(IntPtr wndProc, IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
#endregion
private const int GWLP_WNDPROC = -4;
private IntPtr handle;
private IntPtr originalWndProc;
private IntPtr currentWndProc;
public static IntPtr SetWindowLongHelper(HandleRef hWnd, int nIndex, WndProc wndProc)
{
return IntPtr.Size == 4
? SetWindowLong(hWnd, nIndex, wndProc)
: SetWindowLongPtr(hWnd, nIndex, wndProc);
}
public static IntPtr GetWindowLongHelper(HandleRef hWnd, int nIndex)
{
return IntPtr.Size == 4
? GetWindowLong(hWnd, nIndex)
: GetWindowLongPtr(hWnd, nIndex);
}
internal void SubclassHandle(IntPtr handle)
{
this.handle = handle;
this.originalWndProc = GetWindowLongHelper(new HandleRef(this, handle), GWLP_WNDPROC);
SetWindowLongHelper(new HandleRef(this, handle), GWLP_WNDPROC, new WndProc(this.Callback));
this.currentWndProc = GetWindowLongHelper(new HandleRef(this, handle), GWLP_WNDPROC);
}
private IntPtr Callback(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam)
{
var m = Message.Create(hwnd, msg, wparam, lparam);
if (m.Msg == (int)WM.LBUTTONDOWN)
{
return IntPtr.Zero;
}
return CallWindowProc(originalWndProc, hwnd, msg, wparam, lparam);
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
new EatMouseDown().SubclassHandle(textBox1.Handle);//Subclass a Handle
}

Here's a similar approach to what Sriram Sakthivel had done, but using IMessageFilter instead:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
List<TextBox> TextBoxes = new List<TextBox>();
FindTextBoxes(this, TextBoxes);
Application.AddMessageFilter(new SuppressTextBoxClicks(TextBoxes));
}
private void FindTextBoxes(Control ctl, List<TextBox> TBs)
{
foreach(Control childCtl in ctl.Controls)
{
if (childCtl is TextBox)
{
TBs.Add((TextBox)childCtl);
}
else if(childCtl.HasChildren)
{
FindTextBoxes(childCtl, TBs);
}
}
}
}
public class SuppressTextBoxClicks : IMessageFilter
{
private List<TextBox> _TextBoxes = null;
private const int WM_LBUTTONDOWN = 0x201;
public SuppressTextBoxClicks(List<TextBox> TextBoxes)
{
_TextBoxes = TextBoxes;
}
public bool PreFilterMessage(ref Message m)
{
switch (m.Msg)
{
case WM_LBUTTONDOWN:
if (_TextBoxes != null)
{
foreach(TextBox TB in _TextBoxes)
{
if (TB.Handle.Equals(m.HWnd))
{
return true;
}
}
}
break;
default:
break;
}
return false;
}
}

Set all textboxes' Enabled property to false except the first one. On the TextChanged Event, check if it the Text is empty or not. if it was not empty, Enable the next TextBox and so on...

You can also try this one with the Enter event foreach TextBox
private void textBox2_Enter(object sender, EventArgs e)
{
if (textBox1.Text == "")
textBox1.Focus();
}
private void textBox3_Enter(object sender, EventArgs e)
{
if (textBox1.Text == "")
textBox1.Focus();
else
if (textBox2.Text == "")
textBox2.Focus();
}
private void textBox4_Enter(object sender, EventArgs e)
{
if (textBox1.Text == "")
textBox1.Focus();
else
if (textBox2.Text == "")
textBox2.Focus();
else
if (textBox3.Text == "")
textBox3.Focus();
}

Related

Same MouseMove event on multiple controls

I have a User Control that contains one Panel filling the entire UC. Within the panel there is a PctureBox and a Label. My issue is trying to make it so that no matter which control my cursor moves across, the backcolor on the panel will change as an indicator. I've made it possible in this way (see code below), but I'm sure this isn't the best way of doing it? Keep in mind I'm going to add maybe a hundred of these, so I'm aiming for it to be fairly optimized.
private void PMain_MouseMove(object sender, MouseEventArgs e)
{
Panel pan = sender as Panel;
pan.BackColor = Color.DimGray;
}
private void PMain_MouseLeave(object sender, EventArgs e)
{
Panel pan = sender as Panel;
pan.BackColor = originalBackColor;
}
private void PbIcon_MouseMove(object sender, MouseEventArgs e)
{
pMain.BackColor = Color.DimGray;
}
private void PbIcon_MouseLeave(object sender, EventArgs e)
{
pMain.BackColor = originalBackColor;
}
private void LTitle_MouseMove(object sender, MouseEventArgs e)
{
pMain.BackColor = Color.DimGray;
}
private void LTitle_MouseLeave(object sender, EventArgs e)
{
pMain.BackColor = originalBackColor;
}
If I'm getting you correctly you are trying to do something like the following
in order to do that without having to do it for every control that your user control has, you can insert a thread WH_GETMESSAGE hook to your main thread and check WM_MOUSEHOVER, WM_MOUSELEAVE, WM_MOUSEMOVE messages for your user control and its children
Below is the code sample for UserControl1 which has one Panel filling the entire UC, one PictureBox (koala in it) and one Label (written label1 on it)
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace WindowsFormsApp1
{
public partial class UserControl1 : UserControl
{
const int WH_GETMESSAGE = 0x03;
const int WM_MOUSEHOVER = 0x02A1;
const int WM_MOUSELEAVE = 0x02A3;
const int WM_MOUSEMOVE = 0x0200;
private delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "SetWindowsHookEx", SetLastError = true)]
static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hHook);
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId);
IntPtr _hook;
HookProc _hookProc;
public UserControl1()
{
InitializeComponent();
this.HandleCreated += (sender, e) =>
{
_hookProc = new HookProc(GetMsgHookProc);
_hook = SetWindowsHookEx(
WH_GETMESSAGE,
_hookProc,
GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
GetWindowThreadProcessId(this.Handle, IntPtr.Zero));
};
this.Disposed += (sender, e) =>
{
UnhookWindowsHookEx(_hook);
};
}
private bool IsOurChild(Control ctl)
{
if (ctl == null)
return false;
if (ctl.Handle == this.Handle || ctl.Parent?.Handle == this.Handle)
return true;
return IsOurChild(ctl.Parent);
}
private int GetMsgHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode < 0)
return CallNextHookEx(_hook, nCode, wParam, lParam);
Message m = Marshal.PtrToStructure<Message>(lParam);
Control ctl = Control.FromHandle(m.HWnd);
if (IsOurChild(ctl))
{
if (m.Msg == WM_MOUSEHOVER || m.Msg == WM_MOUSEMOVE)
this.BackColor = Color.Red;
if (m.Msg == WM_MOUSELEAVE)
this.BackColor = Color.Blue;
}
return CallNextHookEx(_hook, nCode, wParam, lParam);
}
}
}
Maybe you can do like this. Example:
Designer
//SomeButton
this.SomeButton.Click += delegate(object sender, EventArgs e)
{ SomeUserControl_Event(sender, e); };
//SomeLabel
this.SomeButton.Click += delegate(object sender, EventArgs e)
{ SomeUserControl_Event(sender, e); };
Cs
private void SomeUserControl_Event(object sender, EventArgs e)
{
pMain.BackColor = originalBackColor;
}
Its only a example

How to detect CTRL+keypress shortcut at any time in C#

In a C# Windows Form I would like transcode information:
when user press CTRL+I, the app detect the key press combination, it takes the code in the clipboard and transcode it.
I find out this code:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
switch (msg.Msg)
{
case 0x100:
case 0x104:
switch (keyData)
{
case Keys.Control | Keys.I:
MessageBox.Show("Ctrl + I pressed");
break;
}
break;
}
return base.ProcessCmdKey(ref msg, keyData);
}
This works fine when windows form has focus.
I would like detect the combination when the app is minimized as tray icon.
SOLUTION:
keyboardhook.cs:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace TrayIconForm
{
public static class Constants
{
public const int NOMOD = 0x0000;
public const int ALT = 0x0001;
public const int CTRL = 0x0002;
public const int SHIFT = 0x0004;
public const int WIN = 0x0008;
public const int WM_HOTKEY_MSG_ID = 0x0312;
}
public class KeyHandler
{
[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);
private int modifier;
private int key;
private IntPtr hWnd;
private int id;
public KeyHandler(int modifier, Keys key, Form form)
{
this.modifier = modifier;
this.key = (int)key;
this.hWnd = form.Handle;
id = this.GetHashCode();
}
public override int GetHashCode()
{
return modifier ^ key ^ hWnd.ToInt32();
}
public bool Register()
{
return RegisterHotKey(hWnd, id, modifier, key);
}
public bool Unregiser()
{
return UnregisterHotKey(hWnd, id);
}
}
}
Information.cs (Form):
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TrayIconForm
{
public partial class Information : Form
{
private KeyHandler ghk;
public Information()
{
InitializeComponent();
ghk = new KeyHandler(Constants.CTRL, Keys.I, this);
ghk.Register();
}
private void HandleHotkey()
{
string s = Get_Copy();
notifyIcon1.BalloonTipText = s;
notifyIcon1.BalloonTipTitle = "You have pressed CTRL+i";
notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
notifyIcon1.Visible = true;
notifyIcon1.ShowBalloonTip(500);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == Constants.WM_HOTKEY_MSG_ID)
HandleHotkey();
base.WndProc(ref m);
}
private string Get_Copy()
{
string r;
// Retrieves data from Clipboard
IDataObject iData = Clipboard.GetDataObject();
// Is Data Text?
if (iData.GetDataPresent(DataFormats.Text))
r = (String)iData.GetData(DataFormats.Text);
else
r = "nothing";
return r;
}
private void Information_Resize(object sender, EventArgs e)
{
if (FormWindowState.Minimized == this.WindowState)
{
notifyIcon1.BalloonTipText = "My application still working...";
notifyIcon1.BalloonTipTitle = "My Sample Application";
notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
notifyIcon1.Visible = true;
notifyIcon1.ShowBalloonTip(500);
this.Hide();
}
else if (FormWindowState.Normal == this.WindowState)
{
notifyIcon1.Visible = false;
}
}
}
}
This works just instantiate it, subscibe to the event and you are done. It s not my script. A while ago I searched long for this but I found it and it works great. There were you subscribed to the event you can look if the pressed key (stored in the event args) is your key and when it is you can look with Keyboard.iskeydown(key.lctrl) if control is pressed to and then you can do what the combination should do.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Input;
namespace <yournamespace>
{
public class LowLevelKeyboardListener
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_SYSKEYDOWN = 0x0104;
[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);
if (OnKeyPressed != null) { OnKeyPressed(this, new KeyPressedArgs(KeyInterop.KeyFromVirtualKey(vkCode))); }
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
}
public class KeyPressedArgs : EventArgs
{
public Key KeyPressed { get; private set; }
public KeyPressedArgs(Key key)
{
KeyPressed = key;
}
}
}
[DllImport("user32.dll")]
public static extern int GetAsyncKeyState(Keys vKeys);
then
var ctrl = GetAsyncKeyState(Keys.ControlKey) & 0x8000;
var key = GetAsyncKeyState(Keys.F10) & 0x8000; //F10 for example
if(ctrl != 0 && key != 0)
{
//do sth
}

Controls cannot be accessed inside my function

just a quick question, can you tell me why I can't access my controls like popup or textbox or the 'this' inside the function that has a comment, please check it out. I really need to know why asap. Thank you so much!
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
DispatcherTimer timer;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
public const int WH_KEYBOARD_LL = 13;
public const int WM_KEYDOWN = 0x0100;
public static LowLevelKeyboardProc _proc = HookCallback;
public static IntPtr _hookID = IntPtr.Zero;
public const uint VK_NUMLOCK = 0x90;
public const uint VK_CAPITAL = 0x14;
public MainWindow()
{
MouseDown += delegate { DragMove(); };
InitializeComponent();
_hookID = SetHook(_proc);
}
public void mainForm_Loaded(object sender, RoutedEventArgs e)
{
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(2000);
timer.Tick += timer_Tick;
}
public void timer_Tick(object sender, EventArgs e)
{
Popup1.IsOpen = false;
timer.Stop();
}
public 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);
}
}
public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
public static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
if (vkCode == VK_CAPITAL)
{
if (Console.CapsLock == true)
{
// I WANT TO ACCESS MY CONTROLS HERE (popup, textbox, etc... this);
}
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
protected override void OnClosed(EventArgs e)
{
UnhookWindowsHookEx(_hookID);
base.OnClosed(e);
}
}
It is a static method. "this" and the controls belong to the instance and can't be seen inside of a static method.
With the use of those .dlls, I can't provide a bulletproof method of accessing it. I would not advise resorting to hopes and dreams, but in the case where the MainWindow is the active window, you could do something like the following:
public static void StaticMainWindowMethod(string incomingMessage)
{
var activeWindow = Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
if (activeWindow != null)
{
var mainWindow = activeWindow as MainWindow;
if (mainWindow != null)
{
mainWindow.InstanceMainWindowMethod(incomingMessage);
}
}
}
protected void InstanceMainWindowMethod(string passedFromStaticMessage)
{
this.MainTextBox.Text = passedFromStaticMessage;
}
The idea is that you need to get the instance of the window in order to get at its properties/controls. Depending on how your application is designed, you may be able to get at it through application level properties. Its reliability is really up to the design of the application.
First, add a static event to your window:
public static event EventHandler CapsLockEnabled;
Next, add a handler for this event:
public MainWindow()
{
MouseDown += delegate { DragMove(); };
InitializeComponent();
_hookID = SetHook(_proc);
CapsLockEnabled += (sender, e) => { Console.WriteLine("caps lock enabled"); };
}
Your event handler, because it's defined on an instance, has full access to all of the window's controls.
Finally, raise the event from your HookCallback method:
public static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
if (vkCode == VK_CAPITAL)
{
if (Console.CapsLock == true)
{
var handler = CapsLockEnabled;
if (handler != null)
{
handler(typeof(MainWindow), EventArgs.Empty);
}
}
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}

Global hotkeys in WPF working from every window

I have to use hotkeys which will be working from every window and pulpit. In winforms I used:
RegisterHotKey(this.Handle, 9000, 0x0002, (int)Keys.F10);
and
UnregisterHotKey(this.Handle, 9000);
and
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case 0x312:
switch (m.WParam.ToInt32())
{
case 9000:
//function to do
break;
}
break;
}
}
In my WPF aplication I tried do:
AddHandler(Keyboard.KeyDownEvent, (KeyEventHandler)HandleKeyDownEvent);
and
private void HandleKeyDownEvent(object sender, KeyEventArgs e)
{
if (e.Key == Key.F11 && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
//function to do
}
}
But it works only when my application is active and on the top, but it doesn't work when the application is minimized (for example). Is any method to do it?
You can use the same approach as in WinForms with some adaptation:
use WindowInteropHelper to get HWND (instead of Handle property of a form)
use HwndSource to handle window messages (instead of overriding WndProc of a form)
don't use Key enumeration from WPF - it's values are not the ones you want
Complete code:
[DllImport("User32.dll")]
private static extern bool RegisterHotKey(
[In] IntPtr hWnd,
[In] int id,
[In] uint fsModifiers,
[In] uint vk);
[DllImport("User32.dll")]
private static extern bool UnregisterHotKey(
[In] IntPtr hWnd,
[In] int id);
private HwndSource _source;
private const int HOTKEY_ID = 9000;
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
var helper = new WindowInteropHelper(this);
_source = HwndSource.FromHwnd(helper.Handle);
_source.AddHook(HwndHook);
RegisterHotKey();
}
protected override void OnClosed(EventArgs e)
{
_source.RemoveHook(HwndHook);
_source = null;
UnregisterHotKey();
base.OnClosed(e);
}
private void RegisterHotKey()
{
var helper = new WindowInteropHelper(this);
const uint VK_F10 = 0x79;
const uint MOD_CTRL = 0x0002;
if(!RegisterHotKey(helper.Handle, HOTKEY_ID, MOD_CTRL, VK_F10))
{
// handle error
}
}
private void UnregisterHotKey()
{
var helper = new WindowInteropHelper(this);
UnregisterHotKey(helper.Handle, HOTKEY_ID);
}
private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
const int WM_HOTKEY = 0x0312;
switch(msg)
{
case WM_HOTKEY:
switch(wParam.ToInt32())
{
case HOTKEY_ID:
OnHotKeyPressed();
handled = true;
break;
}
break;
}
return IntPtr.Zero;
}
private void OnHotKeyPressed()
{
// do stuff
}

Detect & Differentiate Clipboard Events (Cut,Copy and Paste)

is it possible for it to detect and differentiate cut,copy, or paste of files? I only can detect a change in the clipboard to far.
public partial class Form1 : Form
{
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWnd);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
private IntPtr _ClipboardViewerNext;
private const int WM_DRAWCLIPBOARD = 0x0308;
// private const int WM_CUT = 0x0301;
public Form1()
{
InitializeComponent();
}
private void StartClipboardViewer()
{
_ClipboardViewerNext = SetClipboardViewer(this.Handle);
}
private void StopClipboardViewer()
{
ChangeClipboardChain(this.Handle, _ClipboardViewerNext);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_DRAWCLIPBOARD)
{
MessageBox.Show("Copied");
SendMessage(_ClipboardViewerNext, m.Msg, m.WParam, m.LParam);
}
else
{
base.WndProc(ref m);
}
}
private void Form1_Load(object sender, EventArgs e)
{
StartClipboardViewer();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
StopClipboardViewer();
}
}
No, but you could write a wrapper for the Clipboard (as it's a sealed class you can't derive from it) to keep track of the get/set operations.
The clipboard does not differentiate between cut and copy. It's a semantic difference in the way that the source application treats the data (or files).

Categories