I would like to know the word under the mouse cursor in Powerpoint so that it can be used for a screen reader. Accessibility solutions are acceptable if it can distinguish between different words (vs a block).
-
Do you mean in editing mode when the user has placed the cursor over text and clicked, in editing mode when the user has moved the cursor over some text, in slide show mode or ??? In any case, it's likely to be quite complicated. – Steve Rindsberg Sep 06 '15 at 02:34
-
Not in slide show mode necessarily, but during editing mode when the user has placed the cursor over the text (but not clicked to enter the ext mode edit). – tofutim Sep 08 '15 at 14:04
-
1The only way I can imagine this working is to get the cursor position then iterate through all the text on the slide, look at the bounding box properties for each character to determine whether the cursor position is within the bounding box. Is there some reason why you can't ask the user to select the text first? That would simplify things tremendously. – Steve Rindsberg Sep 08 '15 at 14:50
-
1Screen readers are generally used by people with a visual impairment. Are you sure you want them to move a mouse cursor over a word? More practical is to start reading when they select something. – Hans Passant Sep 08 '15 at 15:08
-
Are you planning to develop a [powerpoint add-in](https://msdn.microsoft.com/en-us/library/bb960904(v=office.12).aspx) or writing an application which tries to access it externally? – Binkan Salaryman Sep 08 '15 at 15:32
-
Application that access the text externally - think popup dictionary – tofutim Sep 10 '15 at 01:12
-
@SteveRindsberg I tried what you suggested, but the PowerPoint bounding box is always the parent bounding box even when iterating through the text character by character on the slide - http://stackoverflow.com/questions/32540442/when-i-try-to-use-ui-automation-for-powerpoint-2013-i-can-only-get-the-first-ch – tofutim Sep 12 '15 at 15:43
2 Answers
This is actually really hard, if you do not know what you are doing. There is a easy way and a hard way to do this. Easy way would be to use Microsoft UI automation framework (that includes Powerpoint automation). Alternative frameworks can also be used.
Hard way wold be to directly use win api.
For example: To get window title currently under the mouse.
public static class dllRef
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetCursorPos(out Point lpPoint);
[DllImport("user32.dll")]
private static extern IntPtr WindowFromPoint(Point point);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int RegisterWindowMessage(string lpString);
[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
public static extern bool SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SendMessage(int hWnd, int Msg, int wparam, int lparam);
public const int WM_USER = 0x400;
public const int WM_COPYDATA = 0x4A;
public const int WM_GETTEXT = 0x000D;
public const int WM_GETTEXTLENGTH = 0x000E;
public static void RegisterControlforMessages()
{
RegisterWindowMessage("WM_GETTEXT");
}
public static string GetText()
{
StringBuilder title = new StringBuilder();
Point p = dllRef.getMousePosition();
var lhwnd = dllRef.WindowFromPoint(p);
var lTextlen = dllRef.SendMessage((int)lhwnd, dllRef.WM_GETTEXTLENGTH, 0, 0).ToInt32();
if (lTextlen > 0)
{
title = new StringBuilder(lTextlen + 1);
SendMessage(lhwnd, WM_GETTEXT, title.Capacity, title);
}
return title.ToString();
}
public static Point getMousePosition()
{
Point p = new Point();
GetCursorPos(out p);
return p;
}
}
and
private void Form1_Load(object sender, EventArgs e)
{
Timer t = new Timer();
t.Interval = 25;
t.Tick += new EventHandler(Timer_Tick);
t.Start();
}
public void Timer_Tick(object sender, EventArgs eArgs)
{
this.label1.Text = dllRef.GetText();
}
In addition you can use Microsoft Spy++
to find if information you are looking for is exposed. Other then that I can really recommend you use automation framework that is layer built on top of this. Google has more then enough examples on this (as well as how to build sophisticated keyloggers).

- 19,694
- 14
- 55
- 103
-
And yes, I know it is really hard - hence +500 - need to do it on Powerpoint 2015. (I have previous versions working...) – tofutim Sep 10 '15 at 01:14
-
1There is no PowerPoint 2015. If Windows, you can have 2016 (preview release), 2013, 2010, 2007 and so on, back into the mists of time. If Mac, 2016, 2011, etc. So if you have it working in some versions, what version does it not work in, and what exactly doesn't work? – Steve Rindsberg Sep 11 '15 at 01:05
The same solutions as Margus came to mind. Either UI Automation or PowerPoint interop. Luckily UI Automation works.
The below works in my test putting the mouse over a PowerPoint 2013 text box. Let me know if you think something is missing.
using System.Windows.Automation;
using UIAutomationClient;
String TextUnderCursor()
{
System.Windows.Point point = new System.Windows.Point(Cursor.Position.X, Cursor.Position.Y);
AutomationElement element = AutomationElement.FromPoint(point);
object patternObj;
if (element.TryGetCurrentPattern(TextPattern.Pattern, out patternObj))
{
var textPattern = (TextPattern)patternObj;
return textPattern.DocumentRange.GetText(-1).TrimEnd('\r'); // often there is an extra '\r' hanging off the end.)
} else
{
return "no text found";
}
}
Update Sample http://download.veodin.com/misc/PowerPoint_Screen_Reader.zip
Focus Visual Studio, put the mouse over the PowerPoint then use F5 to run the code

- 3,417
- 2
- 33
- 57
-
This looks promising. Which reference should I include for "UIAutomationClient"? There is a UIAutomationClient dll, but that only contains System.Windows.Automation. (.NET 4.5) -- oops, I guess it is not really needed. – tofutim Sep 12 '15 at 06:39
-
So is that still a question? I referenced UIAutomationClient, UIAutomationTypes and WindowsBase. – Cilvic Sep 12 '15 at 06:48
-
Not sure how you were able to get "using UIAutomationClient" but I just took it out. Right now I'm stuck with 'An outgoing call cannot be made since the application is dispatching an input-synchronous call.' probably because of how I am doing the call... – tofutim Sep 12 '15 at 06:53
-
I added link to the sample solution (tested this in a .net 4.5 standard Forms application) – Cilvic Sep 12 '15 at 07:28
-
-
-
textPattern.RangeFromPoint(location) and range.ExpandToEnclosingUnit(TextUnit.Word) works for notepad and Word but can only get the first Word in PowerPoint – tofutim Sep 12 '15 at 08:41