c # - Er det muligt at skrive et Windows-program, der får en besked, når tekst er valgt i et andet Windows-program?

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg er nysgerrig, om det er muligt at skrive et program, der overvåger mit tekstvalg. En mulig anvendelse ville være at skrive en editor/IDE agnostisk kodeformatter:



  1. Program/Service, P, startes og på en eller anden måde hænger ind i Windows, så det bliver meddelt, når tekst er markeret i et hvilket som helst vindue.

  2. Nogle andre applikationer, A, bliver lanceret.

  3. Bruger vælger tekst i A.

  4. P får besked med den valgte tekst.



-> Jeg er glad for at få det her langt ...

Bedste reference


Dette er ikke muligt uden særlig viden om hver kontrol/applikation, som vil blive brugt, da de alle kan håndtere/behandle det anderledes.

Andre referencer 1


Jeg tror ikke, du kan registrere nogen form for krog. Jeg tror, ​​du bliver nødt til konstant at afstemme det 'fokuserede' eller valgte vindue.


Du kan sandsynligvis bruge Windows Automation API til at gøre dette, hvilket er så vidt jeg ved, at den overordnede adgangs API er overtaget:
http://msdn.microsoft.com/en-us/library/ms747327.aspx[2]


Jeg har brugt denne API til at automatisere GUI-test. Jeg er lidt rustet med det, så jeg ved det ikke sikkert, men jeg er rimelig sikker på, at du kan bruge den til det, du forsøger at gøre. I grunden tillader API'en dig at krydse træet af automatiseringsobjekter med roten ved skrivebord. Hvert automatiseringselement har tendens til at være en Windows-kontrol af en eller anden art, og forskellige kontroller implementerer forskellige mønstre. Du kan også komme til elementer under musemarkøren, og muligvis kan du komme direkte til det aktuelt valgte/fokuserede element.


Efter det bemærker jeg, at TextPattern-klassen f.eks. Har en GetSelection () -metode, der er dokumenteret som 'Henter en samling af uensartede tekstintervaller i forbindelse med det aktuelle tekstvalg eller valg.'. Jeg vedder på, at automatiseringsobjektet for tekstbokse implementerer TextPattern.
http://msdn.microsoft.com/en-us/library/system.windows.automation.textpattern.aspx[3]

Andre referencer 2


Denne kode hjælper dig med at få fokuseret kontroltekst i fokuseret vindue, jeg håber det hjælper:


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;
        }
    }
}