How to get selected text from ANY window (using UI Automation) - C# - c#

I have a small tray application which registers a system-wide hotkey. When the user selects a text anywhere in any application and presses this hotkey I want to be able to capture the selected text. I'm currently doing this using AutomationElements:
//Using FocusedElement (since the focused element should be the control with the selected text?)
AutomationElement ae = AutomationElement.FocusedElement;
AutomationElement txtElement = ae.FindFirst(TreeScope.Subtree,Condition.TrueCondition);
if(txtElement == null)
return;
TextPattern tp;
try
{
tp = txtElement.GetCurrentPattern(TextPattern.Pattern) as TextPattern;
}
catch(Exception ex)
{
return;
}
TextPatternRange[] trs;
if (tp.SupportedTextSelection == SupportedTextSelection.None)
{
return;
}
else
{
trs = tp.GetSelection();
string selectedText = trs[0].GetText(-1);
MessageBox.Show(selectedText );
}
This works for some apps (such as notepad, visual studios edit boxes and such) but not for all (such as Word, FireFox, Chrome, and so on.)
Anyone here with any ideas of how to be able to retreive the selected text in ANY application?

Unfortunately, there's no way to get the selected text from any arbitrary application. UI Automation works if the application supports UIA TextPattern; unfortunately, most do not. I wrote an application that tried to do this, and had a bunch of fallbacks.
I tried (pretty much in order):
UIA.TextPattern
Internet Explorer-specific (this had different implementations for IE 6,7,8,9)
Adobe Reader-specific
Clipboard
This covered 80-90% of the applications out there, but there were quite a few that still failed.
Note that restoring the clipboard has problems of its own; some applications (Office, etc.) put vendor-specific information into the clipboard that can have pointers into internal data; when you put your own info on the clipboard, the internal data gets released, and when you put the old data back, the clipboard now points to freed data, resulting in crashes. You could work around this somewhat by only saving/restoring known clipboard formats, but again, that results in odd behavior in that apps behave "wrong" instead of crashing.

UIA technology does not supported by all applications, you can try to use MSAA in some cases (like FF, Chrome, etc.) but you still will get many problems.
The best way is to save current clipboard text, send "CTRL + C" keypress message via SendMessage WinAPI function, get clipboard text, and restore initial clipboard text as Rick said.

Is it possible to look at the clipboard and make your hotkey: CTRL+C ?
You won't be able to read selected text from any application. For example some PDF files have protected content that disallows copies.

Related

How to get currently active tab index on Chrome via Selenium?

I'm creating app which is half-automated (user is opening tabs (attention) and if he wants to dump one of them he just clicks hot-key).
But when user opens to much tabs, I need to know to which one I should switch.
How can i get currenttab index. Or switch to current tab on Selenium C#?
string windowHandle = Browser.WindowHandles.Last();
string windowHandle = Browser.WindowHandles.First();
string windowHandle = Browser.WindowHandles[1];
...
is not working for me.
The currenttab index may get changed everytime you invoke Browser.WindowHandles().
Though the general perception is WindowHandles would be sorted like the oldest windows first and the newest windows last. But this is not the case: It is totaly random !
In a discussion, Simon clearly mentioned:
While the datatype used for storing the list of handles may be ordered by insertion, the order in which the WebDriver implementation iterates over the window handles to insert them has no requirement to be stable. The ordering is arbitrary.
This comment is pretty much inline with the Get Window Handles section where it mentioned:
In order to determine whether or not a particular interaction with the browser opens a new window, one can obtain the set of window handles before the interaction is performed and compare it with the set after the action is performed.
You can find a relevant detailed discussion in Best way to keep track and iterate through tabs and windows using WindowHandles using Selenium
Update
As per your comment user switch tab (in window) but driver is still focused on another tab you need to induce WebDriverWait for numberOfWindowsToBe(n) and you can find a detailed discussion in getWindowHandles() not working in firefox 58.The focus remains on parent tab and does not transfer to next tab

Odd behaviour when opening a WPF Window from WinForms

When displaying a WPF window from an Excel addin, I'm encountering odd behaviour whenever I show it with myWindow.Show() rather than myWindow.ShowDialog(). Thus far everything has worked fine when using the latter. However, it would be nice to be able to display a window such that the user can interact with Excel at the same time - i.e. the behaviour I'd expect from Show().
The problem is that controls in my form start acting very oddly quite quickly. ComboBox dropdowns collapse immediately, and textbox input ends up in whatever cell is selected in the Excel worksheet that's active.
I've noticed that with ShowDialog, Snoop is able to attach to my window as well, whereas with Show, I get an error amounting to "Could not find a PresentationSource to attach to". I'm not, however, completely sure if that's related.
Obviously one solution would be to stop directly showing a WPF window from WinForms; I expect the problem to largely go away if I change my window into a UserControl and chuck it into an ElementHost. However, I'd rather avoid that if I can.
Current code (roughly)
public void DoOpenWindow(Office.IRibbonControl button)
{
var myWindow = new myWindow();
// This hasn't addressed the issue, though may be sensible to include:
//ElementHost.EnableModelessKeyboardInterop(myWindow);
// This *also* didn't work, and essentially set my window to
// be always on top of Excel
//var hwSrc = HwndSource.FromVisual(myWindow );
//var ownerHelper = new WindowInteropHelper(myWindow );
//ownerHelper.Owner = (IntPtr)Globals.ThisAddIn.Application.Hwnd;
// with ShowDialog() this works fine...
myWindow .Show();
}
Current thoughts are:
I'm getting window messages from Excel forwarded to myWindow, some of which it isn't expecting.
Excel is intercepting messages meant for my window (keyboard and mouse), which is probably what ElementHost.EnableModelessKeyboardInterop(myWindow) is intended to solve (but either I'm using it wrong, or it's not the whole solution).

XNA show xbox onscreen keyboard in PC

I need to show, and input some text in xbox-like onscreen keyboard. Sadly, when I call Guide.BeginShowKeyboardInput, there is only some funny textbox shown, and i must fill it via keyboard. I know, that on PC iv very normal to use keyboard, but in my case i MUST enter text via gamepad, using xbox on screen keyboard.
Is there any way to achieve this? To call xbox onscreen keyboard on PC?
If you need one for like a touchscreen monitor you could do
using System.Diagnostics;
using System.IO;
then use this function
Process.Start(Environment.GetFolderPath(Environment.SpecialFolder.System) + Path.DirectorySeparatorChar + "osk.exe");
but if you need it to work with like an xbox controller you will probably need to build your own
No. It was a design decision (documented here) to give the end user control of the keyboard being invoked. Therefore, the end user has to touch a text box (or the like) to invoke the virtual on-screen keyboard.
Check this text form this link
Blockquote User-driven invocation
The invocation model of the touch keyboard is designed to put the user in control of the keyboard. Users indicate to the system that they want to input text by tapping on an input control instead of having an application make that decision on their behalf. This reduces to zero the scenarios where the keyboard is invoked unexpectedly, which can be a painful source of UI churn because the keyboard can consume up to 50% of the screen and mar the application's user experience. To enable user-driven invocation, we track the coordinates of the last touch event and compare them to the location of the bounding rectangle of the element that currently has focus. If the point is contained within the bounding rectangle, the touch keyboard is invoked.
Blockquote This means that applications cannot programmatically invoke the touch keyboard via manipulation of focus. Big culprits here in the past have been webpages—many of them set focus by default into an input field but have many other experiences available on their page for the user to enjoy. A good example of this is msn.com. The website has a lot of content for consumption, but happens to have a Bing search bar on the top of its page that takes focus by default. If the keyboard were automatically invoked, all of the articles located below that search bar would be occluded by default, thus ruining the website's experience on tablets. There are certain scenarios where it doesn't feel great to have to tap to get the keyboard, such as when a user has started a new email message or has opened the Search pane. However, we feel that requiring the user to tap the input field is an acceptable compromise.
Check out: http://classes.soe.ucsc.edu/cmps020/Winter08/lectures/controller-keyboard-input.pdf
You might find your answer in here, It has all information about the input of a gamepad and such.
There is a good guide on how to do this here:
static public string GetKeyboardInput()
{
if (HandleInput.currentState.IsButtonDown(Buttons.B))
{
useKeyboardResult = false;
}
if (KeyboardResult == null && !Guide.IsVisible)
{
string title = "Name";
string description = "Pick a name for this game";
string defaultText = "Your name here";
pauseType = PauseType.pauseAll;
KeyboardResult = Guide.BeginShowKeyboardInput(HandleInput.playerIndex, title,
description, defaultText, null, null);
useKeyboardResult = true;
pauseType = PauseType.pauseAll;
}
else if (KeyboardResult != null && KeyboardResult.IsCompleted)
{
pauseType = PauseType.none;
KeyboardInputRquested = false;
string input = Guide.EndShowKeyboardInput(KeyboardResult);
KeyboardResult = null;
if (useKeyboardResult)
{
return input;
}
}
return null;
}
And your Update method should contain something like this:
if (KeyboardInputRequested)
{
string result = GetKeyboardInput();
}
if (result != null)
{
//use result here
}
It is unlikely that the on-screen keyboard was packaged in the XNA DLLs for PC, but if you really want to find out, you could research a free .NET decompiling program (such as ILSpy) and look through it.
Also, you can't use the chatpad either. I would recommend either making your own on-screen keyboard that is usable by a controller, or maybe, if you can, using the MonoGame framework (an open-source version of XNA), and modifying it to have an on-screen keyboard on Windows.
You could also make a separate program that acts as a virtual keyboard controlled by the controller.

Sending text into whatever window that is currently in focus

I'm trying to write a program with C# that sends text into other windows.
How do I write a command in C# that sends a text into the window that is currently under the users focus?
For example:
If the user clicks an open notepad window, or an open outlook letter, or an open excel sheet, and then clicks the button on my program, a text will be "pasted" directly into the last notepad window/outlook letter/excel cell that the user clicked on last.
I hope my question is clear enough. I'm not so experienced and am missing a lot of terminology.
Take your application out of focus by minimizing or hiding the main window, and then send your text with
SendKeys.SendWait("Hello World!");
Finally, restore your main window.
If the code is executed in the main form, you could do this
this.Visible = false;
SendKeys.SendWait("Hello World!");
this.Visible = true;
Olivier's response actually seems more accurate (and taught me something :)) than my original "does not seem achievable". If you need an example, then take a look at this:
http://www.codeproject.com/Articles/18366/Sending-Keystrokes-to-another-Application-in-C
However, on a more complex level, without an API to call into, there is not much more that you can do beyond this solution.

How do I read MessageBox text using WinAPI

How do I read a message of standard Win message box (Info)?
Using
SendMessage(this.HandleControl, WM_GETTEXT, builder.Capacity, builder);
I can only read the header of the message box or the text of the button, but not the message itself.
thanks.
Notes (from Q&A):
this.HandleControl is a handler to the message box window
Spy++ shows no child controls bar the button. That's what it made me thinking that Message Boxes have their own way of keeping text w/out using labels
It's a legacy app written with delphi, the button's class is TButton as per Spy++, but still there's no controls except of button inside the dialog window.
After checking a notepad window, both Image & Text are 'selectable', I guess my app doesn't use a std MessageBox. still, how do I go about extracting the text out of the thing? I can see that no labels in my delphi app can be selected by Spy++ Finder tool.
The message text is in a label control on the modal MessageBox dialog window. You have to get the window handle to the MessageBox dialog (win32 API FindWindow) then retrieve the window handle to the control (win32 API GetDlgItem) and then retrieve the text from that window win32 API GetWindowText).
EDIT --
TCHAR text[51] = {0};
HWND msgBox = ::FindWindow(NULL, TEXT("MessageBoxCaption"));
HWND label = ::GetDlgItem(msgBox, 0xFFFF);
::GetWindowText(label, text, sizeof(text)-1);
Try simulating a copy operation (Ctrl-C), then fetch the text from the clipboard: messageboxes allow copying the whole content that way (if they're properly done).
The OP commented that: that worked, thanks. I might end up with doing it that way. Ideally we wanted to keep our implementation focus independant, but choosing between a dedicated PC and OCR I'd probably go the first route.
Personally I've tested this in Delphi 6 and it comes out looking like this:
---------------------------
Confirm
---------------------------
You are about to close the program
WARNING: Are you sure?
---------------------------
Yes No
---------------------------
Note: This is based on an answer that was proposed by "Stefan" in the comments to the original Question

Categories