Here is my code that I use to simulate a tab-keypress in a certain process:
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
public Form1()
{
PostMessage(MemoryHandler.GetMainWindowHandle(),
(int)KeyCodes.WMessages.WM_KEYDOWN,
(int)KeyCodes.VKeys.VK_TAB, 0);
InitializeComponent();
}
Is there any way to extend it so that it presses the key for (example) 1 second, instead of just tapping it?
Please note that I'm not interested in a Thread.Sleep() solution that blocks the UI thread.
The repeating of a keystroke when you hold it down is a feature that's built into the keyboard controller. A microprocessor that's built into the keyboard itself. The 8042 microcontroller was the traditional choice, the keyboard device driver still carries its name.
So, no, this is not done by Windows and PostMessage() is not going to do it for you. Not exactly a problem, you can simply emulate it with a Timer.
If you want to simulate what Windows does with messages, you likely want to find out how fast the key repeat rate is. That can be found at HKEY_CURRENT_USER\Control Panel\Keyboard\KeyboardSpeed. there's also the KeyboardDelay value.
What Windows does is send a WM_KEYDOWN and a WM_CHAR when a key is initially pressed. Then, if the key is still pressed after KeyboardDelay time span, the WM_KEYDOWN and WM_CHAR pair are repeated every KeyboardSpeed until the key is depressed--at which point WM_KEYUP is sent.
I would suggest using a Timer to send the messages at a specific frequencies.
Update:
for example:
int keyboardDelay, keyboardSpeed;
using (var key = Registry.CurrentUser.OpenSubKey(#"Control Panel\Keyboard"))
{
Debug.Assert(key != null);
keyboardDelay = 1;
int.TryParse((String)key.GetValue("KeyboardDelay", "1"), out keyboardDelay);
keyboardSpeed = 31;
int.TryParse((String)key.GetValue("KeyboardSpeed", "31"), out keyboardSpeed);
}
maxRepeatedCharacters = 30; // repeat char 30 times
var startTimer = new System.Windows.Forms.Timer {Interval = keyboardSpeed};
startTimer.Tick += startTimer_Tick;
startTimer.Start();
var repeatTimer = new System.Windows.Forms.Timer();
repeatTimer.Interval += keyboardDelay;
repeatTimer.Tick += repeatTimer_Tick;
//...
private static void repeatTimer_Tick(object sender, EventArgs e)
{
PostMessage(MemoryHandler.GetMainWindowHandle(),
(int)KeyCodes.WMessages.WM_KEYDOWN,
(int)KeyCodes.VKeys.VK_TAB, 0);
PostMessage(MemoryHandler.GetMainWindowHandle(),
(int)KeyCodes.WMessages.WM_CHAR,
(int)KeyCodes.VKeys.VK_TAB, 0);
counter++;
if (counter > maxRepeatedCharacters)
{
Timer timer = sender as Timer;
timer.Stop();
}
}
private static void startTimer_Tick(object sender, EventArgs eventArgs)
{
Timer timer = sender as Timer;
timer.Stop();
PostMessage(MemoryHandler.GetMainWindowHandle(),
(int)KeyCodes.WMessages.WM_KEYDOWN,
(int)KeyCodes.VKeys.VK_TAB, 0);
PostMessage(MemoryHandler.GetMainWindowHandle(),
(int)KeyCodes.WMessages.WM_CHAR,
(int)KeyCodes.VKeys.VK_TAB, 0);
}
When holding a key down on a physical keyboard, repeated keystrokes are passed to the active window. This is not built into the keyboard, but is a Windows feature.
You can simulate this by doing the following steps in order:
Send a keydown message.
Run a timer at 30 ms intervals (the default in Windows, changeable through Ease of Access settings), sending a keypress message to the window at each tick.
Send a keyup message.
I would do it in a thread, for sleeping and not-blocking the UI thread.
Look at this:
System.Threading.Thread KeyThread = new System.Threading.Thread(() => {
//foreach process
// press key now
PostMessage(MemoryHandler.GetMainWindowHandle(),
(int)KeyCodes.WMessages.WM_KEYDOWN,
(int)KeyCodes.VKeys.VK_TAB, 0);
System.Threading.Thread.Sleep(1000); // wait 1 second
//foreach process
// release keys again
PostMessage(MemoryHandler.GetMainWindowHandle(),
(int)KeyCodes.WMessages.WM_KEYUP,
(int)KeyCodes.VKeys.VK_TAB, 0);
});
Ofcourse, you have to start it.
I'm not sure exactly what you're trying to achieve, but below is the function I use to simulate text input using SendInput.
If you alter this slightly to make the final call to SendInput from a new thread, and then separate out the down and up events with a timer, does that achieve what you need?
[DllImport("user32.dll", SetLastError = true)]
static extern UInt32 SendInput(UInt32 numberOfInputs, INPUT[] inputs, Int32 sizeOfInputStructure);
public enum InputType : uint
{
MOUSE = 0,
KEYBOARD = 1,
HARDWARE = 2,
}
struct INPUT
{
public UInt32 Type;
public MOUSEKEYBDHARDWAREINPUT Data;
}
struct KEYBDINPUT
{
public UInt16 Vk;
public UInt16 Scan;
public UInt32 Flags;
public UInt32 Time;
public IntPtr ExtraInfo;
}
public enum KeyboardFlag : uint // UInt32
{
EXTENDEDKEY = 0x0001,
KEYUP = 0x0002,
UNICODE = 0x0004,
SCANCODE = 0x0008,
}
public static void SimulateTextEntry(string text)
{
if (text.Length > UInt32.MaxValue / 2) throw new ArgumentException(string.Format("The text parameter is too long. It must be less than {0} characters.", UInt32.MaxValue / 2), "text");
var chars = UTF8Encoding.ASCII.GetBytes(text);
var len = chars.Length;
INPUT[] inputList = new INPUT[len * 2];
for (int x = 0; x < len; x++)
{
UInt16 scanCode = chars[x];
var down = new INPUT();
down.Type = (UInt32)InputType.KEYBOARD;
down.Data.Keyboard = new KEYBDINPUT();
down.Data.Keyboard.Vk = 0;
down.Data.Keyboard.Scan = scanCode;
down.Data.Keyboard.Flags = (UInt32)KeyboardFlag.UNICODE;
down.Data.Keyboard.Time = 0;
down.Data.Keyboard.ExtraInfo = IntPtr.Zero;
var up = new INPUT();
up.Type = (UInt32)InputType.KEYBOARD;
up.Data.Keyboard = new KEYBDINPUT();
up.Data.Keyboard.Vk = 0;
up.Data.Keyboard.Scan = scanCode;
up.Data.Keyboard.Flags = (UInt32)(KeyboardFlag.KEYUP | KeyboardFlag.UNICODE);
up.Data.Keyboard.Time = 0;
up.Data.Keyboard.ExtraInfo = IntPtr.Zero;
// Handle extended keys:
// If the scan code is preceded by a prefix byte that has the value 0xE0 (224),
// we need to include the KEYEVENTF_EXTENDEDKEY flag in the Flags property.
if ((scanCode & 0xFF00) == 0xE000)
{
down.Data.Keyboard.Flags |= (UInt32)KeyboardFlag.EXTENDEDKEY;
up.Data.Keyboard.Flags |= (UInt32)KeyboardFlag.EXTENDEDKEY;
}
inputList[2*x] = down;
inputList[2*x + 1] = up;
}
var numberOfSuccessfulSimulatedInputs = SendInput((UInt32)len*2, inputList, Marshal.SizeOf(typeof(INPUT)));
}
Not sure what you're doing with the PostMessage but modifying some code from here:
SendKey.Send() Not working
[DllImport("user32.dll", SetLastError = true)]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
public static void PressKey(Keys key, bool up)
{
const int KEYEVENTF_EXTENDEDKEY = 0x1;
const int KEYEVENTF_KEYUP = 0x2;
if (up)
{
keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, (UIntPtr)0);
}
else
{
keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY, (UIntPtr)0);
}
}
void TestProc()
{
PressKey(Keys.Tab, false);
Thread.Sleep(1000);
PressKey(Keys.Tab, true);
}
Maybe this could work for you. Its just a key down and then a key up with a sleep in between. You could even add to this further and pass a time value for how long you want the key to stay down.
Related
I made a code that synchronize a scroll of two RichTextBox.
Hope this works without a matter of line numbers.
but when the line of RichTextBox gets large (around 2000+), System.OverflowException occurs at SendMessage method.
Covering SendMessage with try/catch does not make it work.
Is there any way to handle IntPtr with a number which is greater than Int.MaxValue?
This is my code.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
for (int a = 0; a < 4000; a++)
{
RTB1.Text += a + "\n";
RTB2.Text += a + "\n";
}
}
[DllImport("User32.dll")]
public extern static int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("User32.dll")]
public extern static int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
private void RTB1_VScroll(object sender, EventArgs e)
{
int nPos = GetScrollPos(RTB1.Handle, (int)ScrollBarType.SbVert);
nPos <<= 16;
uint wParam = (uint)ScrollBarCommands.SB_THUMBPOSITION | (uint)nPos;
SendMessage(RTB2.Handle, (int)Message.WM_VSCROLL, new IntPtr(wParam), new IntPtr(0)); //Error occurs here.
}
public enum ScrollBarType : uint
{
SbHorz = 0,
SbVert = 1,
SbCtl = 2,
SbBoth = 3
}
public enum Message : uint
{
WM_VSCROLL = 0x0115
}
public enum ScrollBarCommands : uint
{
SB_THUMBPOSITION = 4
}
}
Looks like your application is running as 32 bit and you're getting an Overflow because UInt can have a value which can't be fit in 32 bit signed int.
For instance, running your application as 64 bit should just work fine.
That said, you don't need that. You can simply avoid using uint and just use int which will work just fine.
int wParam = (int)ScrollBarCommands.SB_THUMBPOSITION | (int)nPos;
In my windows.forms c# application, I have a multi-line textbox with WordWrap = true. After I set Text property to a long string, I need to get all lines produced by wrapping. It is not the same as Lines[] property, because my text does not include new line characters.
I have found solutions using graphics MeasureString function but it seems a little bit extra work considering that the textbox control already did the wrapping - why should I do the same work again?
Is there any way to get the lines into which the textbox wraps the text?
Thank you
Can you check the below solution,
public Form1()
{
InitializeComponent();
textBox1.Text = "This is my text where I want to check how I can get wrapped content as seperate lines automatically !! This is my text which I want to check how I can get wrapped content as seperate lines automatically !!";
}
private void button1_Click(object sender, EventArgs e)
{
bool continueProcess = true;
int i = 1; //Zero Based So Start from 1
int j = 0;
List<string> lines = new List<string>();
while (continueProcess)
{
var index = textBox1.GetFirstCharIndexFromLine(i);
if (index != -1)
{
lines.Add(textBox1.Text.Substring(j, index - j));
j = index;
i++;
}
else
{
lines.Add(textBox1.Text.Substring(j, textBox1.Text.Length - j));
continueProcess = false;
}
}
foreach(var item in lines)
{
MessageBox.Show(item);
}
}
GetFirstCharIndexFromLine Reference
Line numbering in the text box starts at zero. If the lineNumber
parameter is greater than the last line in the text box,
GetFirstCharIndexFromLine returns -1.
GetFirstCharIndexFromLine returns the first character index of a
physical line. The physical line is the displayed line, not the
assigned line. The number of displayed lines can be greater than the
number of assigned lines due to word wrap. For example, if you assign
two long lines to a RichTextBox control and set Multiline and WordWrap
to true, the two long assigned lines result in four physical (or
displayed lines).
A little pinvoking would work:
private const UInt32 EM_GETLINECOUNT = 0xba;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
private void button1_Click(object sender, EventArgs e) {
int numLines = SendMessage(textBox1.Handle,
EM_GETLINECOUNT, IntPtr.Zero, IntPtr.Zero).ToInt32()
MessageBox.Show(numLines.ToString());
}
REVISED ANSWER
I checked the Win32 APIs again and realized it could be done easily. I wrote an extension method so you can do it even easier:
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
static class TextBoxExtensions
{
private const uint EM_FMTLINES = 0x00C8;
private const uint WM_GETTEXT = 0x000D;
private const uint WM_GETTEXTLENGTH = 0x000E;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);
public static string[] GetWrappedLines(this TextBox textBox)
{
var handle = textBox.Handle;
SendMessage(handle, EM_FMTLINES, 1, IntPtr.Zero);
var size = SendMessage(handle, WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero).ToInt32();
if (size > 0)
{
var builder = new StringBuilder(size + 1);
SendMessage(handle, WM_GETTEXT, builder.Capacity, builder);
return builder.ToString().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
}
return new string[0];
}
}
}
usage:
var lines = textBox1.GetWrappedLines();
ORIGINAL ANSWER
WinForm TextBox is actually a wrapper of Windows GDI edit control, which handles text wrapping natively. That being said, even if the TextBox keeps an array of wrapped lines, it is not exposed by public API, not even brought to managed environment (which, if it did, can however be retrieved with reflection). So your best bet is still MeasureString.
To check if particular line is wrapped or not, here is the GDI Function you need to use:
1. [DllImport("user32.dll")]
static extern int DrawText(IntPtr hdc, string lpStr, int nCount, ref Dimension lpRect, int wFormat);
Here are what you need to get things done:
public enum DrawTextFlags
{
CalculateArea = 0x00000400,
WordBreak = 0x00000010,
TextBoxControl = 0x00002000,
Top = 0x00000000,
Left = 0x00000000,
HorizontalCenter = 0x00000001,
Right = 0x00000002,
VerticalCenter = 0x00000004,
Bottom = 0x00000008,
SingleLine = 0x00000020,
ExpandTabs = 0x00000040,
TabStop = 0x00000080,
NoClipping = 0x00000100,
ExternalLeading = 0x00000200,
NoPrefix = 0x00000800,
Internal = 0x00001000,
PathEllipsis = 0x00004000,
EndEllipsis = 0x00008000,
WordEllipsis = 0x00040000,
ModifyString = 0x00010000,
RightToLeft = 0x00020000,
NoFullWidthCharacterBreak = 0x00080000,
HidePrefix = 0x00100000,
PrefixOnly = 0x00200000,
NoPadding = 0x10000000,
}
[StructLayout(LayoutKind.Sequential)]
public struct Dimension
{
public int Left, Top, Right, Bottom;
public Dimension(int left, int top, int right, int bottom)
{
this.Left = left;
this.Right = right;
this.Top = top;
this.Bottom = bottom;
}
public Dimension(Rectangle r)
{
this.Left = r.Left;
this.Top = r.Top;
this.Bottom = r.Bottom;
this.Right = r.Right;
}
public static implicit operator Rectangle(Dimension rc)
{
return Rectangle.FromLTRB(rc.Left, rc.Top, rc.Right, rc.Bottom);
}
public static implicit operator Dimension(Rectangle rc)
{
return new Dimension(rc);
}
public static Dimension Default
{
get { return new Dimension(0, 0, 1, 1); }
}
}
So to know whether a particular line is wrapped or not, you would call the function like this:
Dimension rc = new Dimension(0,0,2,2);
var flag = DrawTextFlags.CalculateArea | DrawTextFlags.TextBoxControl | DrawTextFlags.WordBreak;
DrawText(hdc, line, line.length, ref rc, (int)flag);
Now if height of rc you get after executing this function is greater then your font height or tmHeight if you use TextMetric (that is what minimum required for a line to fit vertically) you can safely assume your line is wrapped.
Apart from this,
You can use the following function as an alternative approach:
static extern bool GetTextExtentExPoint(IntPtr hDc, string str, int nLength,
int nMaxExtent, int[] lpnFit, int[] alpDx, ref Size size);
Please refer to the screenshot below:
The datetime control is a Compact Framework DateTimePicker, the numbered buttons are stndard Button controls.
Clicking on the arrow of the DateTimePicker displays a calendar control allowing the suer to select a date. However if the user clicks on any part of the selected Text date it is highlighted and can be amended using either the hard keys or the on-screen keyboard. I'm trying to emulate this functionality with my standard buttons.
I've have tried the following but currently this is only causing the DateTimePicker to lose focus.
const int KEYEVENTF_KEYUP = 0x2;
const int KEYEVENTF_KEYDOWN = 0x0;
const int VK_NUMPAD1 = 0x61;
private void digitButton_Clicked(object sender, EventArgs e)
{
keybd_event(VK_NUMPAD1, 0, KEYEVENTF_KEYDOWN, 0);
keybd_event(VK_NUMPAD1, 0, KEYEVENTF_KEYUP, 0);
}
[DllImport("coredll.dll", EntryPoint = "keybd_event", SetLastError = true)]
public static extern void keybd_event
(
byte bVk,
byte bScan,
int dwFlags,
int dwExtraInfo
);
I think you pointed out your problem, "...but currently this is only causing the DateTimePicker to lose focus". I suspect your buttons are gaining focus and as a result are consuming the keystrokes. You might try setting focus to the DateTimePicker before generating the keystrokes. If that fails, as a last resort you can hard code to the control using SendMessage() to the window handle for the DateTimePicker, with WM_KEYDOWN, WM_KEYUP.
Try the following - while I haven't tested it for your exact scenario, it does work in our .NET CF applications:
const int KEYEVENTF_EXTENDED_KEY = 0x1;
const int KEYEVENTF_KEYUP = 0x2;
const int KEYEVENTF_KEYDOWN = 0x0;
const int VK_NUMPAD1 = 0x61;
private void digitButton_Clicked(object sender, EventArgs e)
{
keybd_event(VK_NUMPAD1, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_NUMPAD1, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
[DllImport("coredll.dll", EntryPoint = "keybd_event", SetLastError = true)]
public static extern void keybd_event
(
byte bVk,
byte bScan,
int dwFlags,
int dwExtraInfo
);
keybd_event works fine, BUT you have to focus the datePicker first:
(on a form with one datePicker and 12 buttons (button1 to button12)):
public Form1()
{
InitializeComponent();
foreach (Control c in this.Controls)
{
if (c is Button)
{
int n = getButtonNumber((Button)c);
if (n <= 10)
c.Text = n.ToString();
c.Click += new EventHandler(c_Click);
}
}
button11.Text = "<-"; button12.Text = "OK";
}
void c_Click(object sender, EventArgs e)
{
if (sender is Button)
{
Button b = (Button)sender;
int n = Convert.ToInt16( b.Text);
digitButtonClick(n);
}
}
private void digitButtonClick(int n)
{
byte vkInt = (byte)(0x30 + n);
dateTimePicker1.Focus();
keybd_event(vkInt, 0, KEYEVENTF_KEYDOWN, 0);
keybd_event(vkInt, 0, KEYEVENTF_KEYUP, 0);
}
regards
Josef
Goal: write a C# app that runs in the background, listens for the key combination Win-V, and when that occurs, pastes the clipboard contents into the current active window (some arbitrary app). Essentially I'm trying to mimic PureText, but I'm not bothering to convert the text to plain text first.
Problem: pasting into the currently active windows is not working.
Details: To listen in the background for key presses I'm using the globalKeyboardHook class from A Simple C# Global Low Level Keyboard Hook. I'm able to catch Win-V events, but I'm not able to send the paste command properly. I can send the paste by using the functions SendKeys.Send or keybd_event. However, they send another "V" press down the pipeline which gets caught by the gkh_KeyDown event and causes multiple paste events to fire.
I'm expecting that I need to use SendMessage or PostMessage, but all my attempts to do that have failed so far. Below is the full code with the last function, SendCtrlV, being the one of interest. The comments explain everything I've tried so far. Can you see what I'm missing?
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Utilities;
namespace KeyHookTest
{
public partial class Form1 : Form
{
private bool LWin_down;
private bool V_down;
globalKeyboardHook gkh = new globalKeyboardHook();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static public extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hwnd, int msg, int wParam, int lParam);
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
gkh.HookedKeys.Add(Keys.V);
gkh.HookedKeys.Add(Keys.LWin);
gkh.KeyDown += new KeyEventHandler(gkh_KeyDown);
gkh.KeyUp += new KeyEventHandler(gkh_KeyUp);
}
void gkh_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.LWin)
LWin_down = false;
else
V_down = false;
}
void gkh_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.LWin)
LWin_down = true;
else
V_down = true;
if (LWin_down && V_down)
{
LogDebug("Enter Win+V");
try
{
SendCtrlV();
}
catch { }
}
}
private void SendCtrlV()
{
uint KEYEVENTF_KEYUP = 2;
int KEYDOWN = 0x0100;
int KEYUP = 0x0101;
byte KEY_LCONTROL1 = 0x11;
IntPtr KEY_LCONTROL2 = new IntPtr(0x11);
byte KEY_V1 = 0x56;
IntPtr KEY_V2 = new IntPtr(0x56);
int WM_PASTE1 = 0x302;
uint WM_PASTE2 = 0x302;
IntPtr hWnd = GetForegroundWindow();
// Works, but causes multiple gkh_KeyDown to fire so it's slow and buggy
/*keybd_event(KEY_LCONTROL1, 0, 0, 0);
keybd_event(KEY_V1, 0, 0, 0);
keybd_event(KEY_V1, 0, KEYEVENTF_KEYUP, 0);
keybd_event(KEY_LCONTROL1, 0, KEYEVENTF_KEYUP, 0);*/
// Works, but causes multiple gkh_KeyDown to fire so it's slow and buggy
//SendKeys.Send("^v");
// Doesn't work, causes UAC prompt
//SendKeys.Send("{^}v");
// Doesn't work, nothing gets pasted to the foregroundwindow
//SendMessage(hWnd, WM_PASTE1, 0, 0);
// Doesn't work, nothing gets pasted to the foregroundwindow
//PostMessage(hWnd, WM_PASTE2, IntPtr.Zero, IntPtr.Zero);
// Doesn't work, nothing gets pasted to the foregroundwindow
/*SendMessage(hWnd, KEYDOWN, KEY_LCONTROL1, 0);
SendMessage(hWnd, KEYDOWN, KEY_V1, 0);
SendMessage(hWnd, KEYUP, KEY_V1, 0);
SendMessage(hWnd, KEYUP, KEY_LCONTROL1, 0);*/
// Doesn't work, nothing gets pasted to the foregroundwindow
/*PostMessage(hWnd, 0x0100, KEY_LCONTROL2, IntPtr.Zero);
PostMessage(hWnd, 0x0100, KEY_V2, IntPtr.Zero);
PostMessage(hWnd, 0x0101, KEY_V2, IntPtr.Zero);
PostMessage(hWnd, 0x0101, KEY_LCONTROL2, IntPtr.Zero);*/
}
private void LogDebug(string msg)
{
string logpath = Environment.GetEnvironmentVariable("USERPROFILE") + #"\Desktop\KeyHookTest.txt";
File.AppendAllText(logpath, DateTime.Now.ToString("HH:mm:ss:fff") + ": " + msg + "\r\n");
}
}
}
These additional links helped lead me to the answer:
How to get active child window
How can I find the active child window?
Here's what's working for me:
private void SendCtrlV()
{
IntPtr hWnd = GetFocusedHandle();
PostMessage(hWnd, WM_PASTE, IntPtr.Zero, IntPtr.Zero);
}
static IntPtr GetFocusedHandle()
{
var info = new GuiThreadInfo();
info.cbSize = Marshal.SizeOf(info);
if (!GetGUIThreadInfo(0, ref info))
throw new Win32Exception();
return info.hwndFocus;
}
It works, but you must use the TextBox's native window handle if you want it to be effective
When I do this;
Point startpoint = Cursor.Position;
startpoint.Y -= 1;
DoMouse(MOUSEEVENTF.MOVE | MOUSEEVENTF.ABSOLUTE, startpoint);
The mouse doesn't just move up.. it moves a bit to the left as well. But if I do it in a loop, it only moves to the left at the first iteration.
Here is a fully working console program presenting the problem. You have to Add Reference -> .NET -> System.Drawing and System.Windows.Forms to get it to compile.
When starting the program type start to move the mouse up 5 pixels once or type start X (X being a number) to move the mouse up 5 pixels X times. You will see that each new loop the mouse will move a bit to the left; it shouldn't be doing that at all.
using System;
using System.Text.RegularExpressions;
using System.Threading;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace mousemove_temp
{
class Program
{
//Capture user input
static void Main(string[] args)
{
while (true)
{
string s = Console.ReadLine();
switch (s)
{
case("start"):
moveMouseTest(1);
break;
default:
//Get # of times to run function
Match match = Regex.Match(s, #"start (.+)", RegexOptions.IgnoreCase);
if (!match.Success || match.Groups.Count != 2) break;
//Copy # to int
int amnt = -1;
try
{
amnt = Int32.Parse(match.Groups[1].Value);
}
catch (Exception) { break; } //fail
if (amnt <= -1) break; //fail
moveMouseTest(amnt); //aaaawww yeah
break;
}
Thread.Sleep(10);
}
}
//Move the mouse
static void moveMouseTest(int repeat)
{
int countrepeat = 0;
//Loop entire function X times
while (countrepeat < repeat)
{
Point startpoint = Cursor.Position;
int amount = 5; //Move 5 pixels
int counter = 0;
//Move 1 pixel up each loop
while (counter < amount)
{
startpoint.Y -= 1;
DoMouse(MOUSEEVENTF.MOVE | MOUSEEVENTF.ABSOLUTE, startpoint);
counter++;
Thread.Sleep(100); //Slow down so you can see it only jumps left the first time
}
countrepeat++;
Console.WriteLine(String.Format("{0}/{1}", countrepeat, repeat));
Thread.Sleep(1000); //Wait a second before next loop
}
}
/*
* Function stuff
*/
//Control the Mouse
private static object mouselock = new object(); //For use with multithreading
public static void DoMouse(MOUSEEVENTF flags, Point newPoint)
{
lock (mouselock)
{
INPUT input = new INPUT();
MOUSEINPUT mi = new MOUSEINPUT();
input.dwType = InputType.Mouse;
input.mi = mi;
input.mi.dwExtraInfo = IntPtr.Zero;
// mouse co-ords: top left is (0,0), bottom right is (65535, 65535)
// convert screen co-ord to mouse co-ords...
input.mi.dx = newPoint.X * (65535 / Screen.PrimaryScreen.Bounds.Width);
input.mi.dy = newPoint.Y * (65535 / Screen.PrimaryScreen.Bounds.Height);
input.mi.time = 0;
input.mi.mouseData = 0;
// can be used for WHEEL event see msdn
input.mi.dwFlags = flags;
int cbSize = Marshal.SizeOf(typeof(INPUT));
int result = SendInput(1, ref input, cbSize);
if (result == 0)
Console.WriteLine("DoMouse Error:" + Marshal.GetLastWin32Error());
}
}
/*
* Native Methods
*/
[DllImport("user32.dll", SetLastError = true)]
static internal extern Int32 SendInput(Int32 cInputs, ref INPUT pInputs, Int32 cbSize);
[DllImport("user32.dll")]
public static extern bool GetAsyncKeyState(Int32 vKey);
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 28)]
internal struct INPUT
{
[FieldOffset(0)]
public InputType dwType;
[FieldOffset(4)]
public MOUSEINPUT mi;
[FieldOffset(4)]
public KEYBDINPUT ki;
[FieldOffset(4)]
public HARDWAREINPUT hi;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct MOUSEINPUT
{
public Int32 dx;
public Int32 dy;
public Int32 mouseData;
public MOUSEEVENTF dwFlags;
public Int32 time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct KEYBDINPUT
{
public Int16 wVk;
public Int16 wScan;
public KEYEVENTF dwFlags;
public Int32 time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct HARDWAREINPUT
{
public Int32 uMsg;
public Int16 wParamL;
public Int16 wParamH;
}
internal enum InputType : int
{
Mouse = 0,
Keyboard = 1,
Hardware = 2
}
[Flags()]
internal enum MOUSEEVENTF : int
{
MOVE = 0x1,
LEFTDOWN = 0x2,
LEFTUP = 0x4,
RIGHTDOWN = 0x8,
RIGHTUP = 0x10,
MIDDLEDOWN = 0x20,
MIDDLEUP = 0x40,
XDOWN = 0x80,
XUP = 0x100,
VIRTUALDESK = 0x400,
WHEEL = 0x800,
ABSOLUTE = 0x8000
}
[Flags()]
internal enum KEYEVENTF : int
{
EXTENDEDKEY = 1,
KEYUP = 2,
UNICODE = 4,
SCANCODE = 8
}
}
}
Can anybody tell what's going wrong?
You're doing the math wrong and as a result are getting rounding errors.
For example, 65535 / 1920 = 34.1328125. But truncation (because you are dividing an int by an int) is resulting in 34. So if on a 1920x1080 screen you had the mouse all the way at the right, you would get 1920 * (65535 / 1920) = 1920 * 34 = 65280.
This will get you better results:
input.mi.dx = (int)((65535.0f * (newPoint.X / (float)Screen.PrimaryScreen.Bounds.Width)) + 0.5f);
input.mi.dy = (int)((65535.0f * (newPoint.Y / (float)Screen.PrimaryScreen.Bounds.Height)) + 0.5f);
Though if you're determined to use P/Invoke rather than just say
Cursor.Position = new Point(newPoint.X, newPoint.Y);
then you really should use SetCursorPos - http://msdn.microsoft.com/en-us/library/windows/desktop/ms648394(v=vs.85).aspx - since that (along with GetCursorPos) is the API that .NET is using to get and set the cursor position via Cursor.Position.
Simplest way for your project is useful open-source library Windows Input Simulator (C# SendInput Wrapper - Simulate Keyboard and Mouse) on codeplex. Use it!