Windows get selected text

How to get selected text from ANY window (using UI Automation) — 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:

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?

3 Answers 3

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):

  1. UIA.TextPattern
  2. Internet Explorer-specific (this had different implementations for IE 6,7,8,9)
  3. Adobe Reader-specific
  4. 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.

Windows get selected text

I encountered this problem recently and despite many findings on the internet about the issue I couldn’t find any comprehensive solution, especially not for a WPF program. So I decided to summarize how I got it to work in my project.

AutomationElement

First we look at the AutomationElement . There is a very short simple code snippet which if it would work this would be a very short blog post. It works on some program (e g Word and Outlook) but not all (like Internet Explorer). The big advantage about AutomationElement over the copy solution which we will use when AutomationElement doesn’t work, is that we don’t tamper with the Clipboard . In the code below we start by getting an element. I have it easy because I reach my code before my program gets focus so I can just call:

If your program has focus you have to get your element elsewise. After you have your element you try to get a TextPattern and if that succeeds you’re done, just call GetSelection like the example below:

Читайте также:  Готовые аккаунты windows live

If TryGetCurrentPattern returns false you can´t use AutomationElement (not in any way I have found).

Copy command

The other way is to simulate the copy command and check the Clipboard for the text like so:

This does however not work even if it is a nice small piece of code. The problem is that even if we call the copy command with SendWait very often the actual command has not been executed before we check the Clipboard for its content. Perhaps one could try to fix this by using timers/delay of some kind but there is a more exact way. Set up your program to listen to the copy event. In this way we just send the copy command and will always catch it when it executes. Be careful though because your program will now catch every copy command sent, you probably just want to catch the one your code sent. My solution to this is to set a flag when I call copy and test for it when a copy command is executed.

To set up our program as a copy command listener we use the Win32 command SetClipboardViewer . An example how this can be done is given below:

Why we also listen to WM_CHANGECBCHAIN is described here. As you can see I call Clipboard.Clear() after Clipboard.GetText() , this because I don’t want the text to be left in the Clipboard . One could try to retrieve the content before the copy command and set it back afterwards but I haven’t found any good solution to this. What will you for example do if there is a large file in the Clipboard ? Anyway I believe that if the user copies something to the Clipboard and doesn’t use it right away the user has forgotten about it anyway, and if the Clipboard is empty the user just has to fill it again. But I will still prefer to use the AutomationElement if it is possible just to avoid this problem.

Summary

To sum it up use AutomationElement where it works and otherwise use the copy command with the program set up as a Clipboard listener.

How to retrieve the selected text from the active window

I am trying to create a simple open source utility for windows using Python that can perform user-defined actions on the selected text of the currently active window. The utility should be activated using a pre-defined keyboard shortcut.

Usage is partially outlined in the following example:

  1. The user selects some text using the mouse or the keyboard (in any application window)
  2. The user presses a pre-defined keyboard shortcut
  3. The selected text is retrieved by our utility or copied to clipboard (both approaches should be fine)
  4. The keyboard shortcut-dependent action is performed on the selected text

What puzzles me is step 3. How the selected text is retrieved from the active window. This should work with all applications.

I use the pywin32 module.

Читайте также:  Huawei e3372h 153 linux

Thanks in advance for your answers and tips.

Update #1:

Turns out that there are two approaches to accomplish the task:

  1. Find the active window, then send a message/keystroke (Ctrl-C) to it in order to copy the selected text to the clipboard. Then the utility can work on the text by accessing it using the clipboard-related functions.
  2. Find the active Window, then retrieve the selected text directly (without copying it to clipboard). This seems more difficult than the 1st approach.

As starting points:

Get the active window ID as Anurag Uniyal has pointed out in his reply.

Or get the window object with the following code:

How to get selected text of currently focused window?

So, I’m trying to make an application that does the following:

  1. Listens for a keyboard shortcut (using this library)
  2. When the shortcut is hit, retrieves the contents of the currently selected text, and
  3. Processes the text

I’ve used the method shared by the latest edit of this answer (this method) to attach my application to the focused control, but the GetText function in that method doesn’t do what I need.

I’ve seen this answer as well, but that only gives detailed steps as to how to get the focused window on double click, which is not what I need. It did link to this question which led me to try the WM_KEYDOWN method (shown below), but that didn’t work either.

So far I’ve tried these GetText methods (all within the context of that MSDN post):

(I don’t care about preserving the clipboard yet.)

How can I consistently get the selected text of the currently focused application? Bonus points for not tampering with the clipboard, but using it is OK too.

1 Answer 1

Ever since Vista, apps should refrain from using p-invoke or WM_GETTEXT to snoop on other apps due to potential blocks from Windows Elevated Processes. Instead consider using Microsoft UI Automation. Though arguably a testing framework, it is also useful as a means to remotely interact with another GUI application.

Microsoft UI Automation is the new accessibility framework for Microsoft Windows. It addresses the needs of assistive technology products and automated test frameworks by providing programmatic access to information about the user interface (UI). In addition, UI Automation enables control and application developers to make their products accessible.

The following code will look for the running process Notepad and grab any text selection. Ensure you run notepad beforehand, enter in some text and select a word or two.

EDIT:

How can I consistently get the selected text of the currently focused application?

Now in your case to work from focused window, instead of:

How do I get the selected text from the focused window using native Win32 API?

My app. will be running on the system try monitoring for a hotkey; when the user selects some text in any window and presses a hotkey, how do I obtain the selected text, when I get the WM_HOTKEY message?

Читайте также:  Linux check the shell

To capture the text on to the clipboard, I tried sending Ctrl + C using keybd_event() and SendInput() to the active window ( GetActiveWindow() ) and forground window ( GetForegroundWindow() ); tried combinations amongst these; all in vain. Can I get the selected text of the focused window in Windows with plain Win32 system APIs?

3 Answers 3

TL;DR: Yes, there is a way to do this using plain win32 system APIs, but it’s difficult to implement correctly.

WM_COPY and WM_GETTEXT may work, but not in all cases. They depend on the receiving window handling the request correctly — and in many cases it will not. Let me run through one possible way of doing this. It may not be as simple as you were hoping, but what is in the adventure filled world of win32 programming? Ready? Ok. Let’s go.

First we need to get the HWND id of the target window. There are many ways of doing this. One such approach is the one you mentioned above: get the foreground window and then the window with focus, etc. However, there is one huge gotcha that many people forget. After you get the foreground window you must AttachThreadInput to get the window with focus. Otherwise GetFocus() will simply return NULL .

There is a much easier way. Simply (miss)use the GUITREADINFO functions. It’s much safer, as it avoids all the hidden dangers associated with attaching your input thread with another program.

Sending the keystrokes to copy the text is a bit more involved.

We’re going to use SendInput instead of keybd_event because it’s faster, and, most importantly, cannot be messed up by concurrent user input, or other programs simulating keystrokes.

This does mean that the program will be required to run on Windows XP or later, though, so, sorry if your running 98!

There. That wasn’t so bad, was it?

Now we just have to take a peek at what’s in the clipboard. This isn’t as simple as you would first think. The «clipboard» can actually hold multiple representations of the same thing. The application that is active when you copy to the clipboard has control over what exactly to place in the clipboard.

When you copy text from Microsoft Office, for example, it places RTF data into the clipboard, alongside a plain-text representation of the same text. That way you can paste it into wordpad and notepad. Wordpad would use the rich-text format, while notepad would use the plain-text format.

For this simple example, though, let’s assume we’re only interested in plaintext.

And there you have it! Just make sure you copy lpstr to some variable you want to use, don’t use lpstr directly, since we have to cede control of the contents of the clipboard before we close it.

Win32 programming can be quite daunting at first, but after a while. it’s still daunting.

Оцените статью