I have an application in which I can select options in a list which, when selected, give focus to another window and send a shortcut (e.g. focus Chrome, and send Ctrl + 3 to go to the third tab).
This works well, but I can also use a shortcut to quickly select an option in the list within my own app (e.g. Ctrl + 3).
The issue is that if the user uses a shortcut within my app, then Ctrl key is down globally, and sending shortcuts to other application will also have the Ctrl key down. (Note that I also send shortcuts to other applications using Alt and Win keys, so using the same control key in both my app and the target app is not an option)
Is there a way to tell Windows that Ctrl is not down when using SendKeys, so that the shortcut works in another application? Is there otherwise an alternative for achieving this?
Here is a simplified example of the code I'm using (C#):
private const int KEYEVENTF_EXTENDEDKEY = 1;
private const int KEYEVENTF_KEYUP = 2;
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
public void SendCtrl3()
{
keybd_event(0xA2, 0, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(0x33, 0, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(0x33, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
keybd_event(0xA2, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
It seems that if the key is physically down, there is no way to make it so other apps won't see that key as down.
The best alternative I found was to use UI Automation.
http://msdn.microsoft.com/en-us/library/ms747327(v=vs.110).aspx
Related
I need some applications running overnight on Citrix. I don't wish to stay awake all night for that. The Session will timeout and application will be closed. I would not convince the administrator to change the Citrix configuration for this application.
I am trying to create application which will periodically send mouse or keyboard events to the Citrix window. I already have a simple solution which is clicking the mouse.
I wish to have a better solution where everything will be done on background and events would be send just to the Citrix window. Any ideas how to achieve that?
I am using Windows and C# with .NET.
Thank you for any help.
Update #1
I am trying to use Citrix Live Monitoring API as it appears to be a best option. I end up with this:
WFICALib.ICAClient ico = new WFICALib.ICAClient();
int enumHandle = ico.EnumerateCCMSessions();
Console.WriteLine(ico.GetErrorMessage(ico.GetLastError()));
Unfortunately this returns an error message saying:
Live monitoring is disabled
According to documentation it requires following registry keys to be set to 1:
"HKLM\Software\Citrix\ICA Client\CCM\AllowLiveMonitoring(REG_DWORD)"
Problem is that I was unable to find Citrix key in "HKLM\Software\" and it also don't work if I created this keys and values. How do I enable Live Monitoring API?
I have played around with sending input to other windows in the past. I used something like the following:
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern bool SetCursorPos(int x, int y);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private static void LeftMouseClick(Point point)
{
int xpos = (int)point.X;
int ypos = (int)point.Y;
if (SetCursorPos(xpos, ypos))
{
mouse_event(MOUSEEVENTF_LEFTDOWN, xpos, ypos, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, xpos, ypos, 0, 0);
}
}
So to make this work you need to inject coordinates that fall within the Citrix Receiver window. I can't recall whether you get any focus/activation issues - I believe the click injection should bring the window into focus. I never did anything particularly serious with this code so no guarantees.
I'm using this code
const int WM_KEYDOWN = 256;
const int WM_KEYUP = 257;
const int WM_CHAR = 258;
public static void SendKeys(string message){
int foregroundWindowHandle = GetForegroundWindow();
uint remoteThreadId = GetWindowThreadProcessId(foregroundWindowHandle, 0);
uint currentThreadId = GetCurrentThreadId();
//AttachTrheadInput is needed so we can get the handle of a focused window in another app
AttachThreadInput(remoteThreadId, currentThreadId, true);
//Get the handle of a focused window
int focused = GetFocus();
//Now detach since we got the focused handle
AttachThreadInput(remoteThreadId, currentThreadId, false);
foreach (char c in message)
{
//SendMessage(focused, WM_CHAR, (int)c, null);
SendMessage(focused, WM_KEYDOWN, 65, null);
SendMessage(focused, WM_KEYUP, 66, null);
SendMessage(focused, WM_CHAR, 67, null);
}
}
And when I test it (with Notepad being active, for example), only the letter C prints, so only WM_CHAR is working - why?
First, understand that questions asking how to send keyboard messages are asked very often. I assume you have not invested much time looking for previous answers. Second, understand that beginners often mistakenly think that sending keyboard messages is the easiest and most effective solution. The truth is that it is usualy not the easiest and is not the most effective and not the most reliable.
If you are going to work with Windows messages like that, then learn to use Spy++. If you do not know what that is, then please invest a minute by familiarizing yourself with the tools available in the VS Tools menu.
A likely easier, more efective and reliable solution usually is to use the WM_GETTEXT and WM_SETTEXT messages. And anticipating future questions, to push a button in another application send a BN_CLICKED notification to the parent of the button. You can use Spy++ to get many more answers to questions of messages.
I'm trying to control the keystroke from kinect. For example, when my right hand move to right, it means I hold right arrow on the keyboard. I finished to write the code for the kinect, but I don't know how to make a custom keyboard device. I tried to use SendKey but it doesn't worked, because there is no hold key command. I also using loop, thread but it doesn't work too. I try to use kinect to control google earth via WPF application. Any move from kinect will be translated to the keyboard's press or hold, so that it can control google earth application. Any suggestion?
Best Regards,
C.Porawat
There is no hold key state or event. When holding down a key on a keyboard, multiple key events are generated. This win32 example simulates the left key held down forever:
while(true)
{
INPUT input =
{
INPUT_KEYBOARD
};
KEYBDINPUT tmp =
{
VK_LEFT,
0,
0,
0,
NULL
};
input.ki = tmp;
SendInput(1, &input, sizeof(INPUT));
::Sleep(100);
}
I got the answer. By using using System.Windows.Interop and System.Runtime.InteropServices. Then, using:
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, IntPtr dwExtraInfo);
Then, call the keyboard event when I want to used it by:
keybd_event(0x27, 0, KEYEVENTF_KEYDOWN, new System.IntPtr()); //press right arrow on the keyboard
How can I programmatically create an event that would simulate a key being pressed on the keyboard?
The question is tagged WPF but the answers so far are specific WinForms and Win32.
To do this in WPF, simply construct a KeyEventArgs and call RaiseEvent on the target. For example, to send an Insert key KeyDown event to the currently focused element:
var key = Key.Insert; // Key to send
var target = Keyboard.FocusedElement; // Target element
var routedEvent = Keyboard.KeyDownEvent; // Event to send
target.RaiseEvent(
new KeyEventArgs(
Keyboard.PrimaryDevice,
PresentationSource.FromVisual(target),
0,
key)
{ RoutedEvent=routedEvent }
);
This solution doesn't rely on native calls or Windows internals and should be much more reliable than the others. It also allows you to simulate a keypress on a specific element.
Note that this code is only applicable to PreviewKeyDown, KeyDown, PreviewKeyUp, and KeyUp events. If you want to send TextInput events you'll do this instead:
var text = "Hello";
var target = Keyboard.FocusedElement;
var routedEvent = TextCompositionManager.TextInputEvent;
target.RaiseEvent(
new TextCompositionEventArgs(
InputManager.Current.PrimaryKeyboardDevice,
new TextComposition(InputManager.Current, target, text))
{ RoutedEvent = routedEvent }
);
Also note that:
Controls expect to receive Preview
events, for example PreviewKeyDown
should precede KeyDown
Using target.RaiseEvent(...) sends the event directly to the target
without meta-processing such as
accelerators, text composition and
IME. This is normally what you want.
On the other hand, if you really do
what to simulate actual keyboard keys
for some reason, you would use
InputManager.ProcessInput() instead.
To produce key events without Windows Forms Context,
We can use the following method,
[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
sample code is given below:
const int VK_UP = 0x26; //up key
const int VK_DOWN = 0x28; //down key
const int VK_LEFT = 0x25;
const int VK_RIGHT = 0x27;
const uint KEYEVENTF_KEYUP = 0x0002;
const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
int press()
{
//Press the key
keybd_event((byte)VK_UP, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
return 0;
}
List of Virtual Keys are defined here.
To get the complete picture, please use the below link,
http://tksinghal.blogspot.in/2011/04/how-to-press-and-hold-keyboard-key.html
I've not used it, but SendKeys may do what you want.
Use SendKeys to send keystrokes and
keystroke combinations to the active
application. This class cannot be
instantiated. To send a keystroke to a
class and immediately continue with
the flow of your program, use Send. To
wait for any processes started by the
keystroke, use SendWait.
System.Windows.Forms.SendKeys.Send("A");
System.Windows.Forms.SendKeys.Send("{ENTER}");
Microsoft has some more usage examples here.
Easily!
(because someone else already did the work for us...)
After spending a lot of time trying to this with the suggested answers I came across this codeplex project Windows Input Simulator which made it simple as can be to simulate a key press:
Install the package, can be done or from the NuGet package manager or from the package manager console like:
Install-Package InputSimulator
Use this 2 lines of code:
inputSimulator = new InputSimulator()
inputSimulator.Keyboard.KeyDown(VirtualKeyCode.RETURN)
And that's it!
-------EDIT--------
The project page on codeplex is flagged for some reason, this is the link to the NuGet gallery.
Windows SendMessage API with send WM_KEYDOWN.
Basically I want to simulate in code a user clicking on the windows key. I know there is SendKeys which allows me to send key presses to windows if I get a handle to them, but what I can't figure out is what I need to get a handle on in order to send Windows key commands. E.g. Windows key + L. Having read into this a bit it appears that CTRL-ESC should pop up the Start Menu also but not sure how to tell it to send the keys to Windows (if this is even possible). Any help would be much appreciated.
Cheers!
I don't think you can do this using SendKeys, you will need to p/invoke to an API function instead, probably keybd_event to send either CTRL+ESC or the Windows key.
Here is an example of opening the start menu this way in VB and here is keybd_event with its C# signature on pinvoke.net.
Some of the things that a user would do via a WinKey shortcut can be done programmatically in other ways. To take your WinKey+L example, you could instead just use the following statement:
Process.Start("rundll32.exe", "user32.dll,LockWorkStation");
If you could elaborate on what exactly you're trying to accomplish, maybe there's a better way than keybd_event (as Dale has suggested).
I've used the class provided here by user703016 and worked fine!
for ref:
using System.Runtime.InteropServices;
using System.Windows.Forms;
static class KeyboardSend
{
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
private const int KEYEVENTF_EXTENDEDKEY = 1;
private const int KEYEVENTF_KEYUP = 2;
public static void KeyDown(Keys vKey)
{
keybd_event((byte)vKey, 0, KEYEVENTF_EXTENDEDKEY, 0);
}
public static void KeyUp(Keys vKey)
{
keybd_event((byte)vKey, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
}
used in this way:
KeyboardSend.KeyDown(Keys.LWin);
KeyboardSend.KeyDown(Keys.D4);
KeyboardSend.KeyUp(Keys.LWin);
KeyboardSend.KeyUp(Keys.D4);
You need to use a global keyboard hook to hook into keyboards outside your application. There's an article on how to do it here.