Можно ли написать приложение для Windows, которое получает уведомление при выделении текста в другом приложении Windows? - PullRequest
4 голосов
/ 07 марта 2012

Мне любопытно, можно ли написать программу, которая контролирует мой выбор текста. Одним из возможных применений было бы написание независимого от редактора / IDE средства форматирования кода:

  1. Приложение / Сервис, P, запускается и каким-то образом подключается к окнам, так что оно получает уведомление, когда текст выделяется в любом окне.
  2. Запущено какое-то другое приложение А.
  3. Пользователь выбирает текст в A.
  4. P уведомляется с выделенным текстом.

-> Я был бы счастлив пройти так далеко ...

Ответы [ 3 ]

6 голосов
/ 07 марта 2012

Это невозможно без специальных знаний о каждом элементе управления / приложении, которое будет использоваться, поскольку все они могут обрабатывать / обрабатывать его по-разному.

3 голосов
/ 07 марта 2012

Этот код поможет вам получить сфокусированный управляющий текст в сфокусированном окне, надеюсь, это поможет:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace TextFocusedns 
{
    public partial class TextFocusedFrm : Form
    {
        #region APIs

        [DllImport("user32.dll")]
        public static extern bool GetCursorPos(out Point pt);

        [DllImport("user32.dll", EntryPoint = "WindowFromPoint", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern IntPtr WindowFromPoint(Point pt);

        [DllImport("user32.dll", EntryPoint = "SendMessageW")]
        public static extern int SendMessageW([InAttribute] System.IntPtr hWnd, int Msg, int wParam, IntPtr lParam);
        public const int WM_GETTEXT = 13;

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        internal static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        internal static extern IntPtr GetFocus();

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern int GetWindowThreadProcessId(int handle, out int processId);

        [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        internal static extern int AttachThreadInput(int idAttach, int idAttachTo, bool fAttach);
        [DllImport("kernel32.dll")]
        internal static extern int GetCurrentThreadId();

        [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern int GetWindowText(IntPtr hWnd, [Out, MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpString, int nMaxCount);

        #endregion

        private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer() { Interval = 100, Enabled = true };

        public TextFocusedFrm()
        {
            InitializeComponent();
        }

        private void TextFocusedFrm_Load(object sender, EventArgs e)
        {
            timer.Tick += new EventHandler(timer_Tick);
            timer.Start();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            try
            {
                MultiLineTextBox.Text = GetTextFromFocusedControl();
            }
            catch (Exception exp)
            {
                MultiLineTextBox.Text += exp.Message;
            }
        }

        //Get the text of the focused control
        private string GetTextFromFocusedControl()
        {
            try
            {
                int activeWinPtr = GetForegroundWindow().ToInt32();
                int activeThreadId = 0, processId;
                activeThreadId = GetWindowThreadProcessId(activeWinPtr, out processId);
                int currentThreadId = GetCurrentThreadId();
                if (activeThreadId != currentThreadId)
                    AttachThreadInput(activeThreadId, currentThreadId, true);
                IntPtr activeCtrlId = GetFocus();

                return GetText(activeCtrlId);
            }
            catch (Exception exp)
            {
                return exp.Message;
            }
        }

        //Get the text of the control at the mouse position
        private string GetTextFromControlAtMousePosition()
        {
            try
            {
                Point p;
                if (GetCursorPos(out p))
                {
                    IntPtr ptr = WindowFromPoint(p);
                    if (ptr != IntPtr.Zero)
                    {
                        return GetText(ptr);
                    }
                }
                return "";
            }
            catch (Exception exp)
            {
                return exp.Message;
            }
        }

        //Get the text of a control with its handle
        private string GetText(IntPtr handle)
        {
            int maxLength = 512;
            IntPtr buffer = Marshal.AllocHGlobal((maxLength + 1) * 2);
            SendMessageW(handle, WM_GETTEXT, maxLength, buffer);
            string w = Marshal.PtrToStringUni(buffer);
            Marshal.FreeHGlobal(buffer);
            return w;
        }
    }
}
3 голосов
/ 07 марта 2012

Я не думаю, что вы можете зарегистрировать любой вид хука. Я думаю, вам нужно постоянно опрашивать «сфокусированное» или выбранное окно.

Вероятно, вы можете использовать Windows Automation API для этого, насколько я знаю, он превзошел старый API доступа: http://msdn.microsoft.com/en-us/library/ms747327.aspx

Я использовал этот API для автоматизации тестов GUI. Я немного заржавел, поэтому не знаю наверняка, но я достаточно уверен, что вы можете использовать это для того, что вы пытаетесь сделать. По сути, API позволяет обходить дерево объектов автоматизации с корнем на рабочем столе. Каждый элемент автоматизации, как правило, является своего рода элементом управления Windows, а различные элементы управления реализуют разные шаблоны. Вы также можете получить доступ к элементам под курсором мыши и, возможно, вы можете сразу перейти к выбранному / сфокусированному элементу.

После этого я заметил, что класс TextPattern, например, имеет метод GetSelection (), который задокументирован как «Извлекает коллекцию непересекающихся диапазонов текста, связанных с текущим выделением или выделениями текста». Бьюсь об заклад, объект автоматизации для текстовых полей реализуют TextPattern. http://msdn.microsoft.com/en-us/library/system.windows.automation.textpattern.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...