Como obter a palavra sob o cursor no Windows?

Eu quero criar um aplicativo que obtém a palavra sob o cursor (não apenas para campos de texto), mas não consigo encontrar como fazer isso. Usar o OCR é bem difícil. A única coisa que vi trabalhando são os componentes do Deskperience. Eles apóiam um jeito ‘nativo’, mas eles custam muito. Agora estou tentando descobrir o que é esse modo ‘nativo’ (talvez de alguma forma de enganchar). Qualquer ajuda será apreciada.

EDIT: eu encontrei um caminho, mas fica apenas o texto todo do controle. Alguma idéia de como obter apenas a palavra sob o cursor de todo o texto?

Em versões recentes do Windows, a maneira recomendada de reunir informações de um aplicativo para outro (se você não tiver o aplicativo de destino, é claro) é usar a tecnologia de automação de interface do usuário . A Wikipedia é muito boa para obter mais informações sobre isso: Microsoft UI Automation

Basicamente, a automação da interface do usuário usará todos os meios necessários para reunir o que pode ser reunido

Aqui está um pequeno código de aplicativo de console que espiará a interface do usuário de outros aplicativos. Execute-o e mova o mouse para diferentes aplicativos. Cada aplicativo tem um suporte diferente para vários “padrões de automação da interface do usuário”. Por exemplo, há o padrão de valor e o padrão de texto, conforme demonstrado aqui.

static void Main(string[] args) { do { System.Drawing.Point mouse = System.Windows.Forms.Cursor.Position; // use Windows forms mouse code instead of WPF AutomationElement element = AutomationElement.FromPoint(new System.Windows.Point(mouse.X, mouse.Y)); if (element == null) { // no element under mouse return; } Console.WriteLine("Element at position " + mouse + " is '" + element.Current.Name + "'"); object pattern; // the "Value" pattern is supported by many application (including IE & FF) if (element.TryGetCurrentPattern(ValuePattern.Pattern, out pattern)) { ValuePattern valuePattern = (ValuePattern)pattern; Console.WriteLine(" Value=" + valuePattern.Current.Value); } // the "Text" pattern is supported by some applications (including Notepad)and returns the current selection for example if (element.TryGetCurrentPattern(TextPattern.Pattern, out pattern)) { TextPattern textPattern = (TextPattern)pattern; foreach(TextPatternRange range in textPattern.GetSelection()) { Console.WriteLine(" SelectionRange=" + range.GetText(-1)); } } Thread.Sleep(1000); Console.WriteLine(); Console.WriteLine(); } while (true); } 

A automação da interface do usuário é, na verdade, suportada pelo Internet Explorer e pelo Firefox, mas não pelo Chrome que eu saiba. Veja este link: Quando o Google Chrome será acessível?

Agora, este é apenas o começo do trabalho para você :-), porque:

  • Na maioria das vezes, tudo isso tem forte implicação de segurança. O uso dessa tecnologia (ou tecnologia direta do Windows, como WindowFromPoint) exigirá direitos suficientes para isso (por exemplo, ser um administrador). E não acho que o DExperience tenha alguma maneira de superar essas limitações, a menos que instalem um driver de kernel no computador.

  • Alguns aplicativos não expõem nada a ninguém, mesmo com direitos adequados. Por exemplo, se estou escrevendo um aplicativo bancário, não quero que você espie o que meu aplicativo exibirá :-). Outros aplicativos, como o Outlook com DRM, não expõem nada pelos mesmos motivos.

  • Somente o suporte ao padrão de texto da automação da interface do usuário pode fornecer mais informações (como a palavra) do que apenas o texto inteiro. Infelizmente, esse padrão específico não é suportado pelo IE nem pelo FF, mesmo que eles suportem a automação da interface do usuário globalmente.

Então, se tudo isso não funcionar para você, você terá que mergulhar mais fundo e usar técnicas de reconhecimento OCR ou Shape. Mesmo com isso, haverá alguns casos em que você não conseguirá fazê-lo (por causa dos direitos de segurança).

Isso não é trivial se o aplicativo que você deseja “espionar” estiver desenhando o texto. Uma solução possível é acionar o outro aplicativo para pintar uma parte de sua janela, invalidando a área diretamente sob o cursor.

Quando o outro aplicativo pintar, você terá que interceptar as chamadas de desenho de texto. Uma maneira de fazer isso é injetar código no outro aplicativo e interceptar chamadas em funções GDI que desenham texto. Quando você depura aplicativos nativos, isso é o que o visual studio faz para implementar pontos de interrupção. Para testar a ideia, você poderia usar uma biblioteca como desvios (mas isso não é livre para uso comercial).

Você também pode verificar se o aplicativo suporta uma das APIs de acessibilidade que estão no Windows para facilitar coisas como leitores de canvas para pessoas cegas.

Uma palavra de caucanvas: eu não fiz nada disso sozinho.

Se o aplicativo precisar lidar não apenas com aplicativos .Net, eu começaria importando funções ( P / Invoke ):

  • WindowFromPoint
  • ChildWindowFromPointEx

Posteriormente, você pode percorrer os controles e tentar obter o texto de dentro com base no tipo. Se eu vou encontrar algum tempo vou tentar publicar esse código.

Depois de algumas verificações, parece que a melhor maneira (infelizmente o difícil também) é conectar a renderização de texto GDI em alguma discussão.

Eu ecoaria o que Patricker disse, mas acho que não há maneira confiável de fazer o que você quer.

Você provavelmente obteve o texto da janela ou algo parecido. Mas e se o cursor estiver sobre uma janela que não use o texto da janela para armazenar seu conteúdo? O Windows não tem obrigação de armazenar seus dados de uma maneira específica.

Isso acaba apontando você para o reconhecimento de caracteres, onde você olha os pixels sob o cursor e tenta descobrir quais palavras estão lá. Mas não só isso é muito não-trivial, também não é infalível. E se parte da palavra não estiver visível porque se estende para fora da janela?

Isso definitivamente não é trivial. Existem algumas maneiras de abordá-lo. Mas não há uma maneira confiável que funcione com todas as janelas.

Existe um sdk para obter o texto usando o OCR. Não é grátis, mas é muito barato em comparação com outros produtos: http://www.screenocr.com/screen-ocr-library-sdk.htm Eles têm uma aplicação que fornece os mesmos resources para que você possa experimentar a demonstração também.

Para conseguir isso, você precisa de uma abordagem multifacetada.

O UIA funciona em muitos aplicativos, mas você precisa experimentar para ver onde o texto é retornado. Pode estar em Element, Value ou Range. Não há consistência mesmo em aplicativos de escritório.

Se o UIA falhar, enumere a tabela de objects em execução (ROT) e recupere os pointers COM para vários aplicativos registrados no ROT. Você pode, então, converter esses pointers para os tipos de escritório subjacentes:
por exemplo:

 enumerate ROT - then wb = (Excel._Workbook)enumerator.Value; string strText = wb.Application.ActiveCell.Text.ToString(); 

Se os dois methods acima falharem, faça uso do sistema OCR livre no MODI (Biblioteca de Tipos do Microsoft Office Document Imaging 12.0)