Get selected text from any application by means of another applicaiton - windows

I'm working on a concept that works like copy & paste but uses my own algorithm instead of using the clipboard.
We have users that use many different programs that contain part numbers. This is how my concept would work.
User highlights part number from any application (word, excel, pdf, JDE, etc)
Either by hotkey or clicking on another application the user launches my routine.
My routine grabs that text from the original application and processes it accordingly.
I know how to use the clipboard to get text.
What I'm not sure of is how to get currently selected text from the application that was active prior to running my code? Do I need to force my user to copy to clipboard first and then run my app or can I create my own copy/paste type windows add-in?
Preferred VB for this but can also use C++ or C# if easier.
As to the question why, because we want to the action to be seamless to the user. There will be several behind the scenes actions that take place and then the user will be presented a browser with pertinent information related to that part number. Ultimately, I don't want an in-between screen to pop up, but rather completely hidden from the user. If I require them to copy and then run my routine then I'm adding in one extra step to the user path that I'm hoping to avoid.
I looked into right click menu context a bit but found that each program can have their own override. I wasn't able to locate a way to globally override all right click context menus to include a new action.

From this article:
var element = AutomationElement.FocusedElement;
if (element != null)
{
object pattern;
if (element.TryGetCurrentPattern(TextPattern.Pattern, out pattern))
{
var tp = (TextPattern) pattern;
var sb = new StringBuilder();
foreach (var r in tp.GetSelection())
{
sb.AppendLine(r.GetText(-1));
}
var selectedText = sb.ToString();
}
}
It's in C# but it should be pretty trivial to translate.

Related

SwitchTo method for Coded UI

I am working on a, hand coded, Coded UI test for an application.
The application has a certain function that operates in 2 windows. When a button is clicked, a new window appears and then the user makes a selection upon which that window closes, and then the user continues taking actions on the main window.
With Selenium, I would handle that by iterating through all the window handles and switching by using passing it the URL of the page I wanted using the "driver.SwitchTo().Window(handle)" method. However, with Coded UI, I have not found a similar solution. Using the Process class I can do something similar that could work:
Process[] myList = Process.GetProcessesByName("iexplore");
foreach (Process item in myList)
if (item.MainWindowTitle.Contains("Window Title"))
{
item.Kill();
}
The problem is that the application that I am testing is poorly designed and all windows throughout the application have the same name, thus it will not work.
Is there a method which can be used to switch to a different window on Coded UI? Or what would be the best approach?
Take a look at this question, it might help: Interacting with multiple instances of an application in Coded UI
You don't do "switching" in CUIT, every window and control is accessed via a UITestControl object. If you want to do stuff on an other window you create a new object for it. If you can't differentiate the two windows with search properties you can use the Instance property or FindMatchingControls method.
To catch a window creation event you can use a winhook. It gives you the window handle of every window created. Using that you can find out if the window created is the window you are waiting for and then use the UITestControlFactory.FromWindowHandle to create a UITestControl for CUIT to interact with. If you have a generated class for that window you can create an instance of that class and call its CopyFrom method to pass to it the control you created from the window handle.
I am using:
public static HtmlDocument WaitForPopup(string popupName, string text)
{
BrowserWindow browser = new BrowserWindow();
browser.SearchProperties.Add(BrowserWindow.PropertyNames.Name, popupName,
PropertyExpressionOperator.Contains);
browser.WindowTitles.Add(popupName);
browser.WaitForControlExist();
browser.WaitForControlReady();
browser.SetFocus();
HtmlDocument html = new HtmlDocument(browser);
html.SearchProperties.Add(HtmlDocument.PropertyNames.InnerText, text,
PropertyExpressionOperator.Contains);
html.WaitForControlExist();
html.WaitForControlReady();
Playback.Wait(1000);
return html;
}
Just call WaitForPopup("your window name", "some constant text in window") and continue with tests there.
Note that this method will return html of the new window and you can use it further on.

Go to code location in VS extension

I've got a VS editor extension, and when the user performs a certain action, I'd like to send them to a specific location in the code- not unlike Go To Definition or what happens when you click on a stack frame in the debugger.
So far, I used dte.ItemOperations.OpenFile to open the actual file, and I have the relevant ITextDocument, but I don't know how to set the view to the relevant place in the file. It seems like ITextView and IVsTextView and friends have the methods that I need but I'm unsure how to get the instances I need from my ITextDocument.
How can I go to the file and location I want from a VS extension?
The easiest way to do this is to take the return of ItemOperations.OpenFile and navigate from it to the IWpfTextView
IWpfTextView GetWpfTextViewForDteWindow(
Window window,
System.IServiceProvider serviceProvider,
IVsEditorAdaptersFactoryService vsEditorAdaptersFactoryService)
{
var path = Path.Combine(window.Document.Path, window.Document.Name);
IVsUIHierarchy vsuiHierarchy;
uint itemID;
IVsWindowFrame vsWindowFrame;
if (VsShellUtilities.IsDocumentOpen(
serviceProvider,
path,
Guid.Empty,
out vsuiHierarchy,
out itemID,
out vsWindowFrame))
{
// Note this may have multiple IVsTextView instances associated with it in a split window but
// this will retrieve at least one
var vsTextView = VsShellUtilities.GetTextView(vsWindowFrame);
var wpfTextView = vsEditorAdaptersFactoryService.GetWpfTextView(vsTextView);
return wpfTextView;
}
return null;
}
Do note that there is not necessarily a 1-1 mapping between a DTE Window object and ITextView instance. The Window object essentially represents what is visually displayed as a tab and a given tab can contain many ITextView instances. The most common case is when there is a horizontal split in the window. Probably doesn't matter too much for this scenario but wanted to make sure that it got called out

UI Automating a VB6 application from .NET

For the last few days i have been trying to figure out the best way to get AutomationElement for a specific control in a vb6 application.
My initial way of doing so was by doing a search with the following condition:
new PropertyCondition(AutomationElement.NameProperty, controlName)
I was under the assumption that this was working correctly for about a week in a little test VB6 application.
but i few days ago i realized something... when i dragged a vb6 textbox into the form, the 'Name' property and 'Text' property were both set to 'Text1'
So when i searched with:
new PropertyCondition(AutomationElement.NameProperty, 'Text1')
it return the correct element, but if i then went and set the 'Text' property to '' the same search would bring nothing back.
Question: Has anyone found a way to get a AutomationElement based on a the VB6 control name
What i have tried:
getting the MSAA equivalent interface and looking at the 'Name' property - Result: ''
http://msdn.microsoft.com/en-us/library/windows/desktop/dd318490%28v=vs.85%29.aspx
getting the control based on other properties (AutomationId, RuntimeId) - Result: AutomationId - not all controls seem to have this property available - RuntimeId - changes each time the app runs
I have looked at alot of different sites the main one is listed below - while some say they have manage to get it working - i don't believe i can see how they do it.. or i just dont understand it :$
http://blogs.msdn.com/b/brianmcm/archive/2006/01/17/getting-the-winforms-id-of-a-control.aspx
While i have access to the demo app, i will not access to the production app as that has been created by a third party.
What i plan on doing from here is to get the Automation element based on their position on the form..
Thank you
Can't comment due to low rep. Do you absolutely HAVE to have an AutomationElement?
You may want to look at invoking [user32.dll] (http://pinvoke.net/default.aspx/user32.EnumChildWindows). Look at FindWindowEx, GetWindow, EnumWindows, EnumChildWindows, GetWindowText, etc.
You need the handle of the parent window, so you can use this loop to get it. From there you can use the other functions to get the information you need about the control.
IntPtr hWnd = IntPtr.Zero;
foreach(var process in System.Diagnostics.Process.GetProcesses())
if(condition)
hWnd = process.Handle;
Comment with the exact information you need out of the VB6 window, and I'll give you better code.
You can use the relational position of the AutomationElement in a specific Window (or any other container for that matter), in order to detect it. For example, if you have 5 TextBox AutomationElements in your main window, and you're certain that the order will not be changing, you could create a PropertyCondition on the TextBox class name, and then use the FindAll method to return a collection of AutomationElements and iterate through it, querying the BoundingRectangle property to find out which is the lowest one (or middle, or any other position, for that matter).
I would create a helper method that would return a Dictionary<int,AutomationElement> with the key being the visual position of the AutomationElement, and the value being the AutomationElement itself.
This way you can avoid using a specific Point on your screen (any window size change or element positioning will easily break your code) while not being bound to the AutomationId property.

How do I let the user copy arbitrary text?

I have an app, where I generate text (about 500 characters), and I would like the user to have some means of copying that text for use outside of the application.
I don't want to use any capabilities for this app (like web, or contacts).
Here's what I've tried (and why it's failed)
TextBox. IsReadOnly = true; SelectAll();
Can't SelectAll a read only text box
Turn off read only, hide the SIP
Can't hide the SIP on a (non-read-only) TextBox that the user is interacting with (I want to enable the user to copy, so needs to interact with the control)
allow edits, show sip, SelectAll()
The "copy" icon doesn't appear unless the user chose to select text
On selection changed (actually changed), SelectAll()
The "copy" icon doesn't appear unless the user selected the text? The copy icon appears erratically, nothing I would call an acceptable user experience.
So at this point, I'm quite far from what I want in a user experience, and I still don't have anything that works. Any suggestions?
Some other possible ways to answer my question include:
"How do I force the copy button to appear above text I programatically selected?"
"How do I change the selection behavior of a tap in a text box?"
Afaik there are some limitations to the Windows Phone 7 Clipboard:
Works only in TextBox and can only copy text upon users wish
Text is only kept until device gets locked. If your device gets locked, the clipboard will be wiped clean
Even if you try Clipboard.SetText Method, you will notice the SecurityException if you call this method without the users interaction. This is to keep the users data under control so that no rogue app can copy unrecognized Text.
But you could try Matt Laceys WP7Clipboard. It saves the clipboard content inside an image and can even copy bitmaps.
Try restyling the textbox as per http://mobileworld.appamundi.com/blogs/peterfoot/archive/2011/02/08/copyable-textblock-for-windows-phone.aspx
Here's what I eventually got mostly working
private void Export(StackPanel stacker)
{
var exportHeader = new TextBlock();
exportHeader.Text = "Export";
stacker.Children.Add(exportHeader);
var exportBox = new TextBox();
stacker.Children.Add(exportBox);
//exportBox.IsReadOnly = true; // hides SIP, but causes an exception with SelectAll() (pre-Mango, I haven't tried on Mango yet)
exportBox.FontSize = 1;
exportBox.Text = textToExport;
exportBox.GotFocus += new System.Windows.RoutedEventHandler((send, ev) =>
{
((TextBox)send).SelectAll();
});
exportBox.Focus();
}
Apparently, making the font size 1 makes the difference here, maybe because all of the text can appear on the screen at once? Who knows.
I accepted this answer, because no one else posted a better solution. I would appreciate a better solution. If you can get the SIP to go away, that would be awesome.

Firefox extension: How can I set the cursor position?

I have a page with possibly several content-editable iframes (editors).
Now I would like to use my custom Firefox extension to do the following:
Setting the cursor to the end (or last HTML element) of the editor the cursor actually is in.
I found many solutions to get the cursor's position, but I need one to set it.
Any suggestions?
XPCOM likely includes such functionality as part of the testing rig. Mochitest at least is capable of this (again, probably though XPCOM).
On the other hand, when a user is on the system this a generally a gross violation of user interaction practices. Be sure you have a good justification for doing it. It may seem convenient but what if they're doing something else whilst using your addon? I usually have various apps open at once, Fx extensions are only part of that. I don't want it taking control of my mouse, EVER.
Is there something wrong with setting the focus? At least that only forces the user's hand at a window level.
It also suspect it make it quite difficult to get past AMO review. You'd have to justify why it was necessary to invoke such low-level functionality. If you interact with a window, for example, the window might be able to affect the input of your functions which in turn control the mouse... and then a random web site has access to the user's window!
Found the solution to my problem myself. This code myself will set the Cursor position to the last Paragraph of my editor:
var frame = window.content.document.getElementsByTagName('iframe')[2];
var win = frame.contentWindow;
var editingSession = Components.classes["#mozilla.org/editor/editingsession;1"].createInstance(Components.interfaces.nsIEditingSession);
var editor = editingSession.getEditorForWindow(win);
selection = window.getSelection();
var body = frame.contentDocument.body;
text = frame.contentDocument.createTextNode(".");
body.lastChild.appendChild(text); // add textnode to be selected
var range = editor.document.createRange();
range.setStartBefore(text);
range.setEndAfter(text);
editor.selection.removeAllRanges();
editor.selection.addRange(range);
body.lastChild.removeChild(text); // remove Child

Resources