I've written a simple auto clicker using MouseKeyHook.
The reason I use MouseKeyHook is to detect global left clicks throughout Windows OS.
Although, when I run the .exe, the software lags on the click and after a while I can't seem to hit the 'X' button anymore and the application crashed my windows or slows down everything.
I am making this software to test our game, but this is not really helping :P
The code for the software can be found below:
using Gma.System.MouseKeyHook;
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.Tasks;
using System.Windows.Forms;
namespace Rapid_Fire
{
public partial class Form1 : Form
{
#region structs
/// <summary>
/// Structure for SendInput function holding relevant mouse coordinates and information
/// </summary>
public struct INPUT
{
public uint type;
public MOUSEINPUT mi;
};
/// <summary>
/// Structure for SendInput function holding coordinates of the click and other information
/// </summary>
public struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
};
#endregion
// Constants for use in SendInput and mouse_event
public const int INPUT_MOUSE = 0x0000;
public const int MOUSEEVENTF_LEFTDOWN = 0x0002;
public const int MOUSEEVENTF_LEFTUP = 0x0004;
private const int INTERVAL = 10;
private bool m_fire = false;
private bool m_close = false;
private int m_counter = INTERVAL;
private INPUT m_input = new INPUT();
private IKeyboardMouseEvents m_GlobalHook;
public Form1()
{
InitializeComponent();
Subscribe();
InitAutoClick();
this.FormClosed += new FormClosedEventHandler(formClosed);
}
private void Subscribe()
{
m_GlobalHook = Hook.GlobalEvents();
m_GlobalHook.KeyPress += GlobalHookKeyPress;
m_GlobalHook.MouseDownExt += GlobalHookMouseDownExt;
}
private void GlobalHookKeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 'q') m_fire = false;
}
private void GlobalHookMouseDownExt(object sender, MouseEventExtArgs e)
{
m_fire = true;
RapidFire();
}
private void InitAutoClick()
{
m_input.type = INPUT_MOUSE;
m_input.mi.dx = 0;
m_input.mi.dy = 0;
m_input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
m_input.mi.dwExtraInfo = IntPtr.Zero;
m_input.mi.mouseData = 0;
m_input.mi.time = 0;
}
private void RapidFire()
{
while (m_fire && !m_close)
{
if (m_counter <= 0)
{
// ClickLeftMouseButtonSendInput();
m_counter = INTERVAL;
}
m_counter--;
}
}
private void ClickLeftMouseButtonSendInput()
{
// Send a left click down followed by a left click up to simulate a full left click
SendInput(1, ref m_input, Marshal.SizeOf(m_input));
m_input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(1, ref m_input, Marshal.SizeOf(m_input));
}
private void formClosed(object sender, FormClosedEventArgs e)
{
m_fire = false;
m_close = true;
Unsubscribe();
}
public void Unsubscribe()
{
m_GlobalHook.MouseDownExt -= GlobalHookMouseDownExt;
m_GlobalHook.KeyPress -= GlobalHookKeyPress;
m_GlobalHook.Dispose();
}
}
}
Fixed the script by doing it another way. Turns out I had to attach it to a left mouse button down event :D
Here the script is:
using Gma.System.MouseKeyHook;
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 Rapid_Fire
{
public partial class Form1 : Form
{
[DllImport("user32.dll", SetLastError = true)]
public static extern int SendInput(int nInputs, ref INPUT pInputs, int cbSize);
#region structs
/// <summary>
/// Structure for SendInput function holding relevant mouse coordinates and information
/// </summary>
public struct INPUT
{
public uint type;
public MOUSEINPUT mi;
};
/// <summary>
/// Structure for SendInput function holding coordinates of the click and other information
/// </summary>
public struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
};
#endregion
public const int INPUT_MOUSE = 0x0000;
public const int MOUSEEVENTF_LEFTDOWN = 0x0002;
public const int MOUSEEVENTF_LEFTUP = 0x0004;
private const int TIMES_CLICK_FIRE = 25;
private bool m_fire = false;
private INPUT m_input = new INPUT();
private IKeyboardMouseEvents m_Events;
public Form1()
{
InitializeComponent();
SubscribeGlobal();
InitAutoClick();
this.FormClosed += new FormClosedEventHandler(formClosed);
}
private void SubscribeGlobal()
{
Unsubscribe();
Subscribe(Hook.GlobalEvents());
}
private void Subscribe(IKeyboardMouseEvents events)
{
m_Events = events;
m_Events.MouseUp += OnMouseUp;
m_Events.MouseDown += OnMouseDown;
}
private void InitAutoClick()
{
m_input.type = INPUT_MOUSE;
m_input.mi.dx = 0;
m_input.mi.dy = 0;
m_input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
m_input.mi.dwExtraInfo = IntPtr.Zero;
m_input.mi.mouseData = 0;
m_input.mi.time = 0;
}
private void Log(string text)
{
if (IsDisposed) return;
Console.WriteLine(text);
}
private void OnMouseDown(object sender, MouseEventArgs e)
{
m_fire = true;
Thread thread = new Thread(RapidFire);
thread.Start();
}
private void RapidFire()
{
while (m_fire)
{
for (; ; )
{
ClickLeftMouseButtonSendInput();
}
}
}
private void OnMouseUp(object sender, MouseEventArgs e)
{
m_fire = false;
}
private void ClickLeftMouseButtonSendInput()
{
SendInput(1, ref m_input, Marshal.SizeOf(m_input));
m_input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(1, ref m_input, Marshal.SizeOf(m_input));
}
private void formClosed(object sender, FormClosedEventArgs e)
{
Unsubscribe();
}
private void Unsubscribe()
{
if (m_Events == null) return;
m_Events.MouseUp -= OnMouseUp;
m_Events.MouseDown -= OnMouseDown;
m_Events.Dispose();
m_Events = null;
}
}
}
Related
I am programming a little tool for myself just for fun. It is for a game where you can play a guitar and I want to make a programm, that automates the guitar to play some nice little songs. The problem is: I can move the cursor without any problem at my Desktop. The cursor can move in the settings menu in the game too. But when I try it, when im in the game (controlling the player/camera) the cursor has no effect. The Playermodel is not even moving the head. (It is Windows Forms)
I have tried activateing the programm in the Menu (to make sure it works) and it worked and switched to the Player/camera and it just wont move.
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 WindowsFormsApp2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
ghk = new KeyHandler(Keys.Multiply, this);
ghk.Register();
KeyPositioner();
}
bool guitarPlay = false;
private void HandleHotkey()
{
if(checkBox1.Checked)
{
guitarPlay = true;
}
if(guitarPlay = true)
{
for(int i = Cursor.Position.Y; i < 1000; i++)
{
Cursor.Position = new Point(i);
System.Threading.Thread.Sleep(100);
}
//Cursor.Position = new Point(Cursor.Position.X - 0, Cursor.Position.Y + 30);
//System.Threading.Thread.Sleep(100);
//Cursor.Position = new Point(Cursor.Position.X - 0, Cursor.Position.Y - 80);
//System.Threading.Thread.Sleep(100);
//Cursor.Position = new Point(Cursor.Position.X - 0, Cursor.Position.Y - 90);
//System.Threading.Thread.Sleep(100);
//Cursor.Position = new Point(Cursor.Position.X - 0, Cursor.Position.Y + 10);
//System.Threading.Thread.Sleep(100);
//Cursor.Position = new Point(Cursor.Position.X - 0, Cursor.Position.Y - 70);
}
KeyPositioner();
// Do stuff...
//this.Cursor = new Cursor(Cursor.Current.Handle);
Cursor.Position = new Point(Cursor.Position.X - 0, Cursor.Position.Y + 10);
KeyPositioner();
}
private void KeyPositioner()
{
int posx = Cursor.Position.X;
int posy = Cursor.Position.Y;
string posxx;
string posyy;
posxx = Convert.ToString(posx);
posyy = Convert.ToString(posy);
label1.Text = posxx;
label4.Text = posyy;
}
protected override void WndProc(ref Message m)
{
if (m.Msg == Constants.WM_HOTKEY_MSG_ID)
HandleHotkey();
base.WndProc(ref m);
}
private void Form1_Load(object sender, EventArgs e)
{
}
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 key;
private IntPtr hWnd;
private int id;
public KeyHandler(Keys key, Form form)
{
this.key = (int)key;
this.hWnd = form.Handle;
id = this.GetHashCode();
}
public override int GetHashCode()
{
return key ^ hWnd.ToInt32();
}
public bool Register()
{
return RegisterHotKey(hWnd, id, 0, key);
}
public bool Unregiser()
{
return UnregisterHotKey(hWnd, id);
}
}
private KeyHandler ghk;
public static class Constants
{
//windows message id for hotkey
public const int WM_HOTKEY_MSG_ID = 0x0312;
}
private void label1_Click(object sender, EventArgs e)
{
}
private void label4_Click(object sender, EventArgs e)
{
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
}
}
}
I expect that the code can move teh camera view of the player model to.
I am trying to use SetInputToAudioStream method for speech engine.
But it does not work.
I've also searched few articles and tried every possible way. but it still does not work.
https://stackoverflow.com/a/6203533/1336662
https://stackoverflow.com/a/6203533/1336662
I had to use the SpeechStreamer class described in Sean's response in order for the SpeechRecognitionEngine to work.
Here is my code, please if anyone can help me, that will be great.
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Speech.Recognition;
using System.Speech.AudioFormat;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;
namespace WpfAppNAudio
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
console.AppendText("Click to start recording");
}
public WaveIn waveSource = null;
public WaveFileWriter waveFile = null;
private SpeechRecognitionEngine _recognizer = null;
//Stream a = null;
SpeechStreamer stream = null;
private bool _recognizing;
void RecognizeSpeechAndWriteToConsole()
{
_recognizer = new SpeechRecognitionEngine();
try
{
//_recognizer.
// Create and load a grammar.
Grammar dictation = new DictationGrammar();
dictation.Name = "Dictation Grammar";
_recognizer.LoadGrammar(dictation);
_recognizer.SpeechRecognized += _recognizer_SpeechRecognized; // if speech is recognized, call the specified method
_recognizer.SpeechRecognitionRejected += _recognizer_SpeechRecognitionRejected; // if recognized speech is rejected, call the specified method
_recognizer.SpeechDetected += _recognizer_SpeechDetected;
_recognizer.RecognizeCompleted += _recognizer_RecognizeCompleted;
}
catch (Exception)
{
}
}
private void _recognizer_RecognizeCompleted(object sender, RecognizeCompletedEventArgs e)
{
}
private void _recognizer_SpeechDetected(object sender, SpeechDetectedEventArgs e)
{
}
private void _recognizer_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
{
console.AppendText("speech rejected");
}
private void _recognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
console.AppendText("speech recognized" + e.Result.Text);
}
private void StartBtn_Click()
{
waveSource = new WaveIn();
waveSource.WaveFormat = new WaveFormat(22050, 8, 1);
waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable);
waveSource.RecordingStopped += new EventHandler<StoppedEventArgs>(waveSource_RecordingStopped);
waveFile = new WaveFileWriter(#"C:\Temp\Test0001.wav", waveSource.WaveFormat);
console.AppendText("Starting recording");
RecognizeSpeechAndWriteToConsole();
waveSource.StartRecording();
}
void StopBtn_Click(object sender, EventArgs e)
{
waveSource.StopRecording();
}
void waveSource_DataAvailable(object sender, WaveInEventArgs e)
{
if (waveFile != null)
{
stream = new SpeechStreamer(e.Buffer.Length);
stream.Write(e.Buffer, 0, e.BytesRecorded);
waveFile.Write(e.Buffer, 0, e.BytesRecorded);
waveFile.Flush();
if (!_recognizing)
{
_recognizing = true;
_recognizer.SetInputToAudioStream(stream, new System.Speech.AudioFormat.SpeechAudioFormatInfo(22050, System.Speech.AudioFormat.AudioBitsPerSample.Eight, System.Speech.AudioFormat.AudioChannel.Mono));
var s = _recognizer.RecognizerInfo.SupportedAudioFormats;
_recognizer.RecognizeAsync(RecognizeMode.Multiple);
}
}
}
void waveSource_RecordingStopped(object sender, StoppedEventArgs e)
{
if (waveSource != null)
{
waveSource.Dispose();
waveSource = null;
}
if (waveFile != null)
{
waveFile.Dispose();
waveFile = null;
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
StartBtn_Click();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
waveSource.StopRecording();
}
}
class SpeechStreamer : Stream
{
private AutoResetEvent _writeEvent;
private List<byte> _buffer;
private int _buffersize;
private int _readposition;
private int _writeposition;
private bool _reset;
public SpeechStreamer(int bufferSize)
{
_writeEvent = new AutoResetEvent(false);
_buffersize = bufferSize;
_buffer = new List<byte>(_buffersize);
for (int i = 0; i < _buffersize; i++)
_buffer.Add(new byte());
_readposition = 0;
_writeposition = 0;
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return true; }
}
public override long Length
{
get { return -1L; }
}
public override long Position
{
get { return 0L; }
set { }
}
public override long Seek(long offset, SeekOrigin origin)
{
return 0L;
}
public override void SetLength(long value)
{
}
public override int Read(byte[] buffer, int offset, int count)
{
int i = 0;
while (i < count && _writeEvent != null)
{
if (!_reset && _readposition >= _writeposition)
{
_writeEvent.WaitOne(100, true);
continue;
}
buffer[i] = _buffer[_readposition + offset];
_readposition++;
if (_readposition == _buffersize)
{
_readposition = 0;
_reset = false;
}
i++;
}
return count;
}
public override void Write(byte[] buffer, int offset, int count)
{
for (int i = offset; i < offset + count; i++)
{
_buffer[_writeposition] = buffer[i];
_writeposition++;
if (_writeposition == _buffersize)
{
_writeposition = 0;
_reset = true;
}
}
_writeEvent.Set();
}
public override void Close()
{
_writeEvent.Close();
_writeEvent = null;
base.Close();
}
public override void Flush()
{
}
}
}
stream = new SpeechStreamer(e.Buffer.Length);
stream.Write(e.Buffer, 0, e.BytesRecorded);
Is this really the only place that is writing to the stream, no where else in the application? If it only writes some bytes when it initializes it will not continue to get audio coming in to the recognizer.
I have a Arduino communicating the state of a button through serial port. On the PC I have a Windows Service application that is polling the serial port to get the state of the button. Whenever I receive a message in the serial port about the button state, I write the received message to a file, and also want to log the current mouse position. Following this I would like to raise a left click event at the current mouse position.
For some reason, when I read the current mouse position using GetCursorPos, I always get 0, 0 as the mouse position. I am using user32.dll to do this.
The following is my C# code.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Threading;
using System.IO;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;
namespace MouseInterface
{
public class MyMouseClass
{
[DllImport("user32.dll")]
static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo);
[Flags]
public enum MouseEventFlags
{
LEFTDOWN = 0x00000002,
LEFTUP = 0x00000004
}
[DllImport("user32.dll")]
static extern bool SetCursorPos(int x, int y);
[DllImport("user32.dll")]
public static extern bool GetCursorPos(ref Point pt);
public static void LeftDown(int x, int y)
{
SetCursorPos(x, y);
mouse_event((int)(MouseEventFlags.LEFTDOWN), x, y, 0, 0);
}
public static void LeftUp(int x, int y)
{
SetCursorPos(x, y);
mouse_event((int)(MouseEventFlags.LEFTUP), x, y, 0, 0);
}
}
public partial class Service1 : ServiceBase
{
private HCIDevice hcidev;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
hcidev = new HCIDevice();
hcidev.init();
}
protected override void OnStop()
{
hcidev.terminate();
}
private void onElapsedTimer(object source, ElapsedEventArgs e)
{
}
}
public class HCIDevice
{
private SerialPort _sPort;
private Thread _reader;
private bool _connected;
private bool _stop;
private System.Timers.Timer _contimer = new System.Timers.Timer();
public HCIDevice()
{
// create a new serial port
_sPort = new SerialPort();
// update settings
updateSerialPortSettings();
// set reader and writer threads.
_reader = new Thread(this._readerthread);
// reset flags.
_connected = false;
_stop = false;
// start the thread.
//init();
}
public void connect()
{
if (this._sPort.IsOpen == false)
{
try
{
this._sPort.Open();
_connected = true;
AddToFile("Device connected!\n");
}
catch
{
}
}
}
public void disconnect()
{
if (this._sPort.IsOpen)
{
this._sPort.Close();
}
_connected = false;
AddToFile("Device disconnected!\n");
}
public void init()
{
try
{
this._stop = false;
// start thread.
this._reader.Start();
}
catch
{
//AddToFile("Service could not be started!\n");
}
}
public void terminate()
{
// first stop.
this._stop = true;
this._reader.Join();
//AddToFile("Device stopped!");
}
public bool isRunning()
{
return (this._stop == false);
}
public bool isConnected()
{
return this._sPort.IsOpen;
}
private void updateSerialPortSettings()
{
// Allow the user to set the appropriate properties.
this._sPort.PortName = System.Configuration.ConfigurationManager.AppSettings["devCOM"];
this._sPort.BaudRate = int.Parse(System.Configuration.ConfigurationManager.AppSettings["devbaudrate"]);
this._sPort.Parity = Parity.None;
this._sPort.DataBits = 8;
this._sPort.StopBits = StopBits.One;
this._sPort.Handshake = Handshake.None;
// Set the read/write timeouts
this._sPort.ReadTimeout = 500;
this._sPort.WriteTimeout = 500;
}
private void _readerthread()
{
byte[] _rxdata = new byte[1024];
//int n;
double nanosecPerTick = 1.0 / Stopwatch.Frequency;
Stopwatch stp_watch = new Stopwatch();
stp_watch.Start();
AddToFile("Service started!\n");
while (_stop == false)
{
// make sure the device is still connected.
if (isConnected())
{
// Do nothing if in pause
// Not paused read data and parse
try
{
handle_message();
}
catch (System.TimeoutException) { }
}
else
{
// Just got disconnected?
if (_connected)
{
disconnect();
// Reset timer.
stp_watch.Reset();
stp_watch.Start();
}
else
{
// try to connect every one second.
if (stp_watch.ElapsedMilliseconds >= 1000)
{
connect();
// Reset timer.
stp_watch.Reset();
if (_connected == false)
{
stp_watch.Start();
}
}
}
}
}
disconnect();
AddToFile("Service stopped!\n");
}
private void AddToFile(string line)
{
using (FileStream fs = File.Open(System.Configuration.ConfigurationManager.AppSettings["logloc"], FileMode.Append, FileAccess.Write, FileShare.None))
{
Byte[] info = new UTF8Encoding(true).GetBytes(string.Format("{0} {1}", DateTime.Now.ToString("dd-MMM-yyyy HH:mm:ss"), line));
// Add some information to the file.
fs.Write(info, 0, info.Length);
}
}
private void handle_message()
{
// read line.
string msg = _sPort.ReadLine();
AddToFile(msg);
Point pt = new Point();
MyMouseClass.GetCursorPos(ref pt);
AddToFile(string.Format("{0}, {1}", pt.X, pt.Y));
}
}
}
What am I doing wrong? I googled for a couple of hours to find the solution, but could not find anything about this.
I try to use code from How to use C# BackgroundWorker to report progress in native C++ code? for change progressBar in WinForms.
But the function which is called from c++ dll does not started (CSharpReportProgressStatus()), if I create a form. Without creation of the form it works fine.
CppLayer.h:
#define DLLAPI __declspec(dllexport)
extern "C"
{
typedef void (__stdcall *ReportProgressCallback)(int, char *);
typedef bool (__stdcall *CancellationPendingCallback)();
struct DLLAPI WorkProgressInteropNegotiator
{
ReportProgressCallback progressCallback;
CancellationPendingCallback cancellationPending;
bool cancel;
};
DLLAPI void __stdcall CppLongFunction(WorkProgressInteropNegotiator& negotiator);
}
CppLayer.cpp:
#include "CppLayer.h"
#include <iostream>
#include <windows.h> //Для sleep
typedef void (__stdcall * pfnCallback)(int progress, int* cancel);
extern "C"
{
DLLAPI void __stdcall CppLongFunction(WorkProgressInteropNegotiator& negotiator)
{
const int STEP_COUNT = 12;
char * messages[3] = {"ONE", "TWO", "THREE"};
for (int i = 0; i < STEP_COUNT; i++)
{
Sleep(100);
if (negotiator.cancellationPending()) {
negotiator.cancel = true;
break;
}
std::cout << "Calculate " << i << std::endl;
negotiator.progressCallback((i + 1) * 100 / STEP_COUNT, messages[i % 3]);
}
}
};
Program.cs:
using System;
using System.Windows.Forms;
namespace CallBackFromCpp
{
static class Program
{
[STAThread]
public static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Presenter p = new Presenter();
Application.Run(p.Init());
}
}
}
Form1.cs:
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace CallBackFromCpp
{
public partial class Form1 : Form
{
public event EventHandler StartEvent;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (StartEvent != null)
StartEvent(this, e);
}
}
}
Presenter.cs:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace CallBackFromCpp
{
public class Presenter
{
Form1 _view;
public ApplicationContext Init()
{
_view = new Form1();
_view.StartEvent += _view_StartEvent;
return new ApplicationContext(_view);
}
public delegate void ReportProgressCallback(int percentage, string message);
public delegate bool CancellationPendingCallback();
[StructLayout(LayoutKind.Sequential)]
public class WorkProgressInteropNegotiator
{
public ReportProgressCallback reportProgress;
public CancellationPendingCallback cancellationPending;
#pragma warning disable 0649
// C# does not see this member is set up in native code, we disable warning to avoid it.
public bool cancel;
#pragma warning restore 0649
}
[DllImport("CppLayer.dll")]
public static extern void CppLongFunction([In, Out] WorkProgressInteropNegotiator negotiator);
static EventWaitHandle resetEvent = null;
void _view_StartEvent(object sender, EventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.ProgressChanged += CSharpReportProgressStatus;
bw.DoWork += CSharpLongFunctionWrapper;
bw.RunWorkerCompleted += CSharpReportComplete;
resetEvent = new AutoResetEvent(false);
bw.RunWorkerAsync();
resetEvent.WaitOne();
}
void CSharpLongFunctionWrapper(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
WorkProgressInteropNegotiator negotiator = new WorkProgressInteropNegotiator();
negotiator.reportProgress = new ReportProgressCallback(bw.ReportProgress);
negotiator.cancellationPending = new CancellationPendingCallback(() => bw.CancellationPending);
GCHandle gch = GCHandle.Alloc(negotiator);
CppLongFunction(negotiator);
gch.Free();
e.Cancel = negotiator.cancel;
}
void CSharpReportProgressStatus(object sender, ProgressChangedEventArgs e)
{
string message = e.UserState as string;
_view.richTextBox1.Text += String.Format("Report {0:00}% with message '{1}'", e.ProgressPercentage, message);
_view.progressBar1.PerformStep();
BackgroundWorker bw = sender as BackgroundWorker;
if (e.ProgressPercentage > 50)
bw.CancelAsync();
}
void CSharpReportComplete(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
_view.richTextBox1.Text = "Long operation canceled!";
}
else if (e.Error != null)
{
_view.richTextBox1.Text = String.Format("Long operation error: {0}", e.Error.Message);
}
else
{
_view.richTextBox1.Text += "Long operation complete!";
}
resetEvent.Set();
}
}
}
The problem was solved transfer dll call in a separate thread and GUI update via invoke from this thread.
Form1.cs:
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace CallBackFromCpp
{
public partial class Form1 : Form
{
public event EventHandler StartEvent;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (StartEvent != null)
StartEvent(this, e);
}
private void button2_Click(object sender, EventArgs e)
{
if (StopEvent != null)
StopEvent(this, e);
}
}
}
Presenter.cs:
using System;
using System.Threading;
using System.Windows.Forms;
namespace CallBackFromCpp
{
public class Presenter
{
Form1 _view;
WorkerClass _wc;
public ApplicationContext Init()
{
_view = new Form1();
_view.StartEvent += _view_StartEvent;
_view.StopEvent += _view_StopEvent;
return new ApplicationContext(_view);
}
void _view_StopEvent(object sender, EventArgs e)
{
if (_wc != null)
_wc.Stop = true;
}
delegate void ShowProgressDelegate(int progressPercentage, string message);
private void ShowProgress(int progressPercentage, string message)
{
_view.richTextBox1.Text += String.Format("Report {0:00}% with message '{1}'\n", progressPercentage, message);
_view.progressBar1.PerformStep();
}
void _view_StartEvent(object sender, EventArgs e)
{
ShowProgressDelegate showProgress = new ShowProgressDelegate(ShowProgress);
_wc = new WorkerClass(_view, showProgress);
Thread t = new Thread(new ThreadStart(_wc.RunProcess));
t.IsBackground = true; //make them a daemon - prevent thread callback issues
t.Start();
}
}
}
WorkerClass.cs:
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace CallBackFromCpp
{
public class WorkerClass
{
/// <summary>
/// Usually a form or a winform control that implements "Invoke/BeginInvode"
/// </summary>
ContainerControl _sender = null;
/// <summary>
/// The delegate method (callback) on the sender to call
/// </summary>
Delegate _senderDelegate = null;
public delegate void ReportProgressCallback(int percentage, string message);
public delegate bool CancellationPendingCallback();
[StructLayout(LayoutKind.Sequential)]
public class WorkProgressInteropNegotiator
{
public ReportProgressCallback reportProgress;
public CancellationPendingCallback cancellationPending;
#pragma warning disable 0649
// C# does not see this member is set up in native code, we disable warning to avoid it.
public bool cancel;
#pragma warning restore 0649
}
[DllImport("CppLayer.dll")]
public static extern void CppLongFunction([In, Out] WorkProgressInteropNegotiator negotiator);
/// <summary>
/// Constructor called by calle using ThreadPool OR ThreadStart
/// </summary>
public WorkerClass(ContainerControl sender, Delegate senderDelegate)
{
_sender = sender;
_senderDelegate = senderDelegate;
}
/// <summary>
/// Method for ThreadStart delegate
/// </summary>
public void RunProcess()
{
Thread.CurrentThread.IsBackground = true; //make them a daemon
WorkProgressInteropNegotiator negotiator = new WorkProgressInteropNegotiator();
negotiator.reportProgress = new ReportProgressCallback(ReportProgress);
negotiator.cancellationPending = new CancellationPendingCallback(() => { return Stop; });
// Refer for details to
// "How to: Marshal Callbacks and Delegates Using C++ Interop"
// http://msdn.microsoft.com/en-us/library/367eeye0%28v=vs.100%29.aspx
GCHandle gch = GCHandle.Alloc(negotiator);
CppLongFunction(negotiator);
gch.Free();
}
private void ReportProgress(int progressPercentage, string message)
{
_sender.BeginInvoke(_senderDelegate, new object[] { progressPercentage, message });
}
volatile bool _stop = false;
public bool Stop
{
set
{
_stop = value;
}
get
{
return _stop;
}
}
}
}
I my program I need to capture when the Print Screen key is pressed down but it is not working (however it works with other keys).
I guess this has something to do with windows hijacking my authority and since im still new at this I'd love to know how I can get around this issue.
Here's my current code:
namespace Boom_Screenshot_
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
//SETTINGS
Key TRIGGER_KEY = Key.PrintScreen;
public Window1()
{
InitializeComponent();
}
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == TRIGGER_KEY)
{
MessageBox.Show("'PrintScreen' was pressed.");
}
}
}
}
I have an answer for you that I found here (I don't speak Chinese so don't ask me what it says :). You have to set a hook. He provides a wrapper class. I repeat some code here without the Chinese characters. RegisterHotKey.cs ...
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace TestKeydown
{
public class RegisterHotKeyClass
{
private IntPtr m_WindowHandle = IntPtr.Zero;
private MODKEY m_ModKey = MODKEY.MOD_CONTROL;
private Keys m_Keys = Keys.A;
private int m_WParam = 10000;
private bool Star = false;
private HotKeyWndProc m_HotKeyWnd = new HotKeyWndProc();
public IntPtr WindowHandle
{
get { return m_WindowHandle; }
set { if (Star)return; m_WindowHandle = value; }
}
public MODKEY ModKey
{
get { return m_ModKey; }
set { if (Star)return; m_ModKey = value; }
}
public Keys Keys
{
get { return m_Keys; }
set { if (Star)return; m_Keys = value; }
}
public int WParam
{
get { return m_WParam; }
set { if (Star)return; m_WParam = value; }
}
public void StarHotKey()
{
if (m_WindowHandle != IntPtr.Zero)
{
if (!RegisterHotKey(m_WindowHandle, m_WParam, m_ModKey, m_Keys))
{
throw new Exception("");
}
try
{
m_HotKeyWnd.m_HotKeyPass = new HotKeyPass(KeyPass);
m_HotKeyWnd.m_WParam = m_WParam;
m_HotKeyWnd.AssignHandle(m_WindowHandle);
Star = true;
}
catch
{
StopHotKey();
}
}
}
private void KeyPass()
{
if (HotKey != null) HotKey();
}
public void StopHotKey()
{
if (Star)
{
if (!UnregisterHotKey(m_WindowHandle, m_WParam))
{
throw new Exception("");
}
Star = false;
m_HotKeyWnd.ReleaseHandle();
}
}
public delegate void HotKeyPass();
public event HotKeyPass HotKey;
private class HotKeyWndProc : NativeWindow
{
public int m_WParam = 10000;
public HotKeyPass m_HotKeyPass;
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312 && m.WParam.ToInt32() == m_WParam)
{
if (m_HotKeyPass != null) m_HotKeyPass.Invoke();
}
base.WndProc(ref m);
}
}
public enum MODKEY
{
MOD_ALT = 0x0001,
MOD_CONTROL = 0x0002,
MOD_SHIFT = 0x0004,
MOD_WIN = 0x0008,
}
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr wnd, int id, MODKEY mode, Keys vk);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr wnd, int id);
}
}
Calling code in a Form ...
private RegisterHotKeyClass _RegisKey = new RegisterHotKeyClass();
void _Regis_HotKey()
{
MessageBox.Show("ok");
}
private void Form1_Load(object sender, EventArgs e)
{
_RegisKey.Keys = Keys.PrintScreen;
_RegisKey.ModKey = 0;
_RegisKey.WindowHandle = this.Handle;
_RegisKey.HotKey += new RegisterHotKeyClass.HotKeyPass(_Regis_HotKey);
_RegisKey.StarHotKey();
}
Below is my pure WPF solution.
We can achieve this in xaml by using NavigationCommands (Namespace: System.Window.Input) class which provides a standard set of navigation commands (e.g. NextPage, PreviousPage, Refresh, Search etc.)
Implementation Approach:
So we can call any custom code to execute on application refresh using NavigationCommands.Refresh as
<UserControl.CommandBindings>
<CommandBinding Command='NavigationCommands.Refresh'
Executed="ApplicationRefresh_Executed">
</CommandBinding>
</UserControl.CommandBindings>
Now in code behind class of UserControl we can define method as
private void ApplicationRefresh_Executed(object sender, ExecutedRoutedEventArgs e)
{
// Implementation goes here.
}