GP-6899 - Accessibility help updates

This commit is contained in:
dragonmacher
2026-09-17 19:20:07 -04:00
committed by Ryan Kurtz
parent 1c779da13a
commit 88f02f225e
8 changed files with 169 additions and 182 deletions

View File

@@ -11,61 +11,105 @@
<META name="generator" content="Microsoft FrontPage 4.0"> <META name="generator" content="Microsoft FrontPage 4.0">
</HEAD> </HEAD>
<BODY> <BODY>
<H1 align="center">Ghidra Accessibility</H1> <H1 align="center">Ghidra Accessibility</H1>
<P>Ghidra strives to be as accessible as possible to all users, including those relying on keyboard-only operation and screen readers. This document summarizes built-in accessibility features, recommended usage patterns, and known limitations.</P>
<BLOCKQUOTE>
<P>Ghidra strives to be as accessible as possible to all users, including those relying on
keyboard-only operation and screen readers. This document summarizes built-in accessibility
features, recommended usage patterns, and known limitations.</P>
<H2>Screen-Reader Guidance</H2> <H2>Screen-Reader Guidance</H2>
<P>Most of Ghidra's UI is built in Java/Swing, so screen reader behavior may differ from a web browser. To get the best results:</P>
<BLOCKQUOTE>
<P>Most of Ghidra's UI is built in Java/Swing, so screen reader behavior may differ from a web
browser. To get the best results:</P>
<UL> <UL>
<LI>Use a modern Java-aware screen reader (e.g. NVDA on Windows).</LI> <LI>Use a modern Java-aware screen reader (e.g. NVDA on Windows).</LI>
<LI>Enable "focus following caret" or "announce focus changes" so you hear when UI components gain keyboard focus.</LI>
<LI>Pause briefly after opening new dialogs or views, as Swing can sometimes batch events.</LI> <LI>Enable "focus following caret" or "announce focus changes" so you hear when UI components
gain keyboard focus.</LI>
<LI>Pause briefly after opening new dialogs or views, as Swing can sometimes batch
events.</LI>
</UL> </UL>
</BLOCKQUOTE>
<H2>Keyboard Navigation</H2> <H2>Keyboard Navigation</H2>
<P>Ghidra provides comprehensive keyboard navigation support to traverse UI components, windows, and providers. For full details, including focus traversal and navigation shortcuts, see the <A href="help/topics/KeyboardNavigation/KeyboardNavigation.html">Keyboard Navigation</A> topic.</P>
<H2>Quick Action Dialog (Ctrl + 3)</H2> <BLOCKQUOTE>
<P>Ghidra's Quick Action dialog provides a fast, keyboard-first way to find and run any action. Press <B>Ctrl + 3</B> to open it, then:</P> <P>Ghidra provides comprehensive keyboard navigation support to traverse UI components,
windows, and providers. For full details, including focus traversal and navigation shortcuts,
see the <A href="help/topics/KeyboardNavigation/KeyboardNavigation.html">Keyboard
Navigation</A> topic.</P>
</BLOCKQUOTE>
<H2>Quick Action Dialog (Ctrl-3)</H2>
<BLOCKQUOTE>
<P>Ghidra's
<A href="help/topics/KeyboardNavigation/KeyboardNavigation.html#ActionChooserDialog">
Quick Action Dialog</A> provides a fast, keyboard-first way to find and run any action.
Press <B>Ctrl-3</B> to open it, then:</P>
<UL> <UL>
<LI>Begin typing any portion of an action name</LI> <LI>Begin typing any portion of an action name</LI>
<LI>Use <B>Up</B>/<B>Down</B> arrows to navigate the list.</LI> <LI>Use <B>Up</B>/<B>Down</B> arrows to navigate the list.</LI>
<LI>Repeat <B>Ctrl + 3</B> to expand from local to global actions.</LI>
<LI>Press <B>Enter</B> to execute the selected command.</LI> <LI>Press <B>Enter</B> to execute the selected command.</LI>
<LI>Repeat <B>Ctrl + 3</B> to expand from local to global actions.</LI>
<LI>The dialog remembers recent commands across sessions for quick recall.</LI>
</UL> </UL>
<P>This dialog is invaluable for screen-reader users or anyone who prefers keyboard navigation over menus.</P>
<H2>Script Launcher (Ctrl + Shift + S)</H2> <P>The dialog remembers recently used actions across sessions for quick recall. This feature is
<P>A quick launcher exists for Ghidra scripts. For details, see the Script Manager topic: <A href="help/topics/GhidraScriptMgrPlugin/GhidraScriptMgrPlugin.htm">Script Manager</A>.</P> invaluable for screen-reader users or anyone who prefers keyboard navigation over menus.</P>
<OL> </BLOCKQUOTE>
<LI>Press <B>Ctrl + Shift + S</B>.</LI>
<LI>Begin typing your script's name (wildcards and substrings allowed).</LI> <H2>Script Launcher (Ctrl-Shift-S)</H2>
<LI>Navigate the filtered list with Up/Down, then Enter to run.</LI>
<LI>Recently run scripts float to the top automatically.</LI> <BLOCKQUOTE>
</OL> <P>Ghidra's
<A href="help/topics/GhidraScriptMgrPlugin/GhidraScriptMgrPlugin.htm#Script_Quick_Launch">
Script Quick Launcher</A> provides a quick way to run desired scripts.
Press <B>Ctrl-Shift-S</B> to open it, then:
</P>
<H2>Other Accessibility-Focused Enhancements</H2>
<UL> <UL>
<LI><B>Customizable Key Bindings</B>: Assign or modify keyboard shortcuts via Edit -> Tool Options -> Key Bindings, or press F4 while hovering over a toolbar icon or menu item to set a shortcut (see <A href="../Tool/ToolOptions_Dialog.htm#KeyBindings_Option">Key Bindings</A>).</LI> <LI>Begin typing your script's name (wildcards and substrings allowed).</LI>
<LI><B>Accessible Names and Roles</B>: Most dialogs now expose meaningful AccessibleName and AccessibleRole fields.</LI>
<LI><B>Dialog Checkbox Improvements</B>: Spacebar toggles and arrow keys navigate checkbox groups reliably.</LI> <LI>Navigate the filtered list with Up/Down, then Enter to run.</LI>
<LI><B>Decompilation View</B>: Reduced redundant reads when moving the caret.</LI>
<LI><B>Filter Dialogs</B>: Improved focus order and announceable fields in filter dialogs (e.g., Analyze -> Filters).</LI>
</UL> </UL>
<P>The dialog remembers recentlyl used scripts for quick recall.</P>
</BLOCKQUOTE>
<H2>Known Limitations</H2> <H2>Known Limitations</H2>
<BLOCKQUOTE>
<UL> <UL>
<LI>Swing's accessibility support is not as mature as HTML/ARIA; you may encounter missing or stale descriptions, focus swapping, or limited screen-reader gestures.</LI> <LI>Swing's accessibility support is not as mature as HTML/ARIA. You may encounter missing or
stale descriptions, focus swapping, or limited screen-reader gestures.</LI>
<LI>Browser-style reporting (tabular UI state summaries) is not available.</LI> <LI>Browser-style reporting (tabular UI state summaries) is not available.</LI>
</UL> </UL>
</BLOCKQUOTE>
<H2>Related Topics</H2> </BLOCKQUOTE>
<P class="relatedtopic">Related Topics:</P>
<UL> <UL>
<LI><A href="help/topics/KeyboardNavigation/KeyboardNavigation.html">Keyboard Navigation</A></LI> <LI><A href="help/topics/KeyboardNavigation/KeyboardNavigation.html">Keyboard
<LI><A href="help/topics/GhidraScriptMgrPlugin/GhidraScriptMgrPlugin.htm">Script Manager</A></LI> Navigation</A></LI>
<LI><A href="help/topics/GhidraScriptMgrPlugin/GhidraScriptMgrPlugin.htm">Script
Manager</A></LI>
</UL><BR> </UL><BR>
</BODY> </BODY>
</HTML> </HTML>

View File

@@ -132,7 +132,7 @@
Manager.</P> Manager.</P>
</BLOCKQUOTE> </BLOCKQUOTE>
<H3><A name="Script_Quick_Launch"></A>Script Quick Launch</H3> <H3><A name="Script_Quick_Launch"></A>Script Quick Launcher</H3>
<BLOCKQUOTE> <BLOCKQUOTE>
<P align="left">This key binding action shows a dialog to quickly find and run scripts. <P align="left">This key binding action shows a dialog to quickly find and run scripts.

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,17 +20,13 @@ import java.io.InputStream;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import docking.ActionContext;
import docking.action.DockingAction;
import docking.action.MenuData;
import docking.tool.ToolConstants;
import ghidra.app.CorePluginPackage; import ghidra.app.CorePluginPackage;
import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.PluginCategoryNames;
import ghidra.framework.main.ApplicationLevelOnlyPlugin; import ghidra.framework.main.ApplicationLevelOnlyPlugin;
import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus; import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.framework.preferences.Preferences; import ghidra.framework.preferences.Preferences;
import ghidra.util.HelpLocation; import ghidra.util.Swing;
import ghidra.util.SystemUtilities; import ghidra.util.SystemUtilities;
import utilities.util.FileUtilities; import utilities.util.FileUtilities;
@@ -48,7 +44,6 @@ public class TipOfTheDayPlugin extends Plugin implements ApplicationLevelOnlyPlu
private static final String SHOW_TIPS = "SHOW_TIPS"; private static final String SHOW_TIPS = "SHOW_TIPS";
private TipOfTheDayDialog dialog; private TipOfTheDayDialog dialog;
private DockingAction action;
public TipOfTheDayPlugin(PluginTool tool) { public TipOfTheDayPlugin(PluginTool tool) {
super(tool); super(tool);
@@ -56,19 +51,6 @@ public class TipOfTheDayPlugin extends Plugin implements ApplicationLevelOnlyPlu
@Override @Override
protected void init() { protected void init() {
action = new DockingAction("Tips of the day", getName()) {
@Override
public void actionPerformed(ActionContext context) {
dialog.doShow(tool.getToolFrame());
}
};
action.setMenuBarData(new MenuData(new String[] { "Help", "Tip of the Day" },
ToolConstants.HELP_CONTENTS_MENU_GROUP));
action.setEnabled(true);
action.setHelpLocation(new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Tip_of_the_day"));
tool.addAction(action);
List<String> tips = null; List<String> tips = null;
try { try {
tips = loadTips(); tips = loadTips();
@@ -91,8 +73,6 @@ public class TipOfTheDayPlugin extends Plugin implements ApplicationLevelOnlyPlu
@Override @Override
protected void dispose() { protected void dispose() {
writePreferences(); writePreferences();
action.dispose();
dialog.close(); dialog.close();
} }
@@ -101,7 +81,7 @@ public class TipOfTheDayPlugin extends Plugin implements ApplicationLevelOnlyPlu
String showTipsStr = Preferences.getProperty(SHOW_TIPS, "true", true); String showTipsStr = Preferences.getProperty(SHOW_TIPS, "true", true);
int tipIndex = Integer.parseInt(tipIndexStr); int tipIndex = Integer.parseInt(tipIndexStr);
final boolean showTips = Boolean.parseBoolean(showTipsStr); boolean showTips = Boolean.parseBoolean(showTipsStr);
if (showTips) { if (showTips) {
tipIndex = (++tipIndex) % dialog.getNumberOfTips(); tipIndex = (++tipIndex) % dialog.getNumberOfTips();
writePreferences(tipIndex, showTips); writePreferences(tipIndex, showTips);
@@ -110,7 +90,7 @@ public class TipOfTheDayPlugin extends Plugin implements ApplicationLevelOnlyPlu
dialog.setTipIndex(tipIndex); dialog.setTipIndex(tipIndex);
dialog.setShowTips(showTips); dialog.setShowTips(showTips);
SystemUtilities.runSwingLater(() -> { Swing.runLater(() -> {
if (showTips && !SystemUtilities.isInTestingMode()) { if (showTips && !SystemUtilities.isInTestingMode()) {
dialog.show(tool.getToolFrame()); dialog.show(tool.getToolFrame());
} }

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -16,6 +16,7 @@
package ghidra.app.plugin.runtimeinfo; package ghidra.app.plugin.runtimeinfo;
import docking.action.builder.ActionBuilder; import docking.action.builder.ActionBuilder;
import docking.tool.ToolConstants;
import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.PluginCategoryNames;
import ghidra.framework.main.ApplicationLevelOnlyPlugin; import ghidra.framework.main.ApplicationLevelOnlyPlugin;
import ghidra.framework.main.UtilityPluginPackage; import ghidra.framework.main.UtilityPluginPackage;
@@ -50,7 +51,7 @@ public class RuntimeInfoPlugin extends Plugin implements ApplicationLevelOnlyPlu
.onAction(context -> showInstalledProcessors()) .onAction(context -> showInstalledProcessors())
.enabled(true) .enabled(true)
.menuPath("Help", supportedActionName) .menuPath("Help", supportedActionName)
.menuGroup("YYY") // trying to put this just above the last menu entry .menuGroup(ToolConstants.HELP_RUNTIME_MENU_GROUP)
.helpLocation(getInstalledProcessorsHelpLocation()) .helpLocation(getInstalledProcessorsHelpLocation())
.buildAndInstall(tool); .buildAndInstall(tool);
@@ -59,7 +60,7 @@ public class RuntimeInfoPlugin extends Plugin implements ApplicationLevelOnlyPlu
.onAction(context -> showRuntimeInfo()) .onAction(context -> showRuntimeInfo())
.enabled(true) .enabled(true)
.menuPath("Help", runtimeInfoActionName) .menuPath("Help", runtimeInfoActionName)
.menuGroup("YYY") .menuGroup(ToolConstants.HELP_RUNTIME_MENU_GROUP)
.helpLocation(getRuntimeInfoHelpLocation()) .helpLocation(getRuntimeInfoHelpLocation())
.buildAndInstall(tool); .buildAndInstall(tool);
} }

View File

@@ -20,44 +20,57 @@
<BLOCKQUOTE> <BLOCKQUOTE>
<P>Ghidra supports standard keyboard navigation for traversing component focus <P>Ghidra supports standard keyboard navigation for traversing component focus
cycles within each window. In general, TAB and &lt;CTRL&gt; TAB will transfer focus to cycles within each window. In general, <B>Tab</B> and <B>Ctrl-Tab</B> will transfer focus to
the next component. And &lt;SHIFT&gt; TAB and &lt;CTRL&gt;&lt;SHIFT&gt;TAB will transfer the next component. <B>Shift-Tab</B> and <B>Ctrl-Shift-Tab</B> will transfer
focus to the previous component in the cycle. TAB and &lt;SHIFT&gt;TAB do not always work focus to the previous component.
as they are sometimes used by individual components such as text components, but the
&lt;CTRL&gt; versions should work universally.</P>
<BLOCKQUOTE>
<P><IMG src="help/shared/note.png" border="0">
<B>Tab</B> and <B>Shift-Tab</B> do not always work
as they are sometimes used by individual components, such as text components. The
<B>Ctrl</B> versions should work universally.</P>
</BLOCKQUOTE>
<P>Ghidra also provides some handy shortcut keys for navigation:</P> <P>Ghidra also provides some handy shortcut keys for navigation:</P>
<UL> <UL>
<LI>&lt;CTRL&gt;F3 - Transfer focus to the next window or dialog.</LI> <LI><B>Ctrl-F3</B> - Transfer focus (jump) to the next window or dialog.</LI>
<LI>&lt;CTRL&gt;&lt;SHIFT&gt;F3 - Transfer focus to the previous window or dialog.</LI> <LI><B>Ctrl-Shift-F3</B> - Transfer focus (jump) to the previous window or
dialog.</LI>
<LI>&lt;CTRL&gt;J - Transfer focus (Jump) to the next component provider (titled <LI><B>Ctrl-J</B> - Transfer focus (jump) to the next component provider (titled
component).</LI> component).</LI>
<LI>&lt;CTRL&gt;&lt;SHIFT&gt;J - Transfer focus (Jump) to the previous component <LI><B>Ctrl-Shift-J</B> - Transfer focus (jump) to the previous component
provider.</LI> provider.</LI>
<LI>
<B>Ctrl-F6</B> - Transfer focus (jump) to the last active component
provider. This allows the user to jump back and forth between recently used provider.
</LI>
</UL> </UL>
</BLOCKQUOTE> </BLOCKQUOTE>
<H2>Actions</H2> <H2>Actions</H2>
<BLOCKQUOTE> <BLOCKQUOTE>
<P>Global menus can be reached using the various accelerator keys such as &lt;ALT&gt;F to <P>Global menus can be reached using the various accelerator keys such as <B>Alt-F<B> to
access the File menu.</P> access the File menu.</P>
<P>Context menus can be invoked using the &lt;SHIFT&gt;F10 key or the dedicated context <P>Context menus can be invoked using the Shift-F10 key or the dedicated context
menu key available on some keyboards.</P> menu key available on some keyboards.</P>
<P>Toolbar actions currently can't be directly accessed via the keyboard unless a <P>Toolbar actions currently can't be directly accessed via the keyboard unless a
keybinding is assigned to them.</P> keybinding is assigned to them.</P>
</BLOCKQUOTE> </BLOCKQUOTE>
<H2>Actions Dialog</H2><A NAME="ActionChooserDialog"/> <A NAME="ActionChooserDialog"/><H2>Quick Action Dialog</H2>
<BLOCKQUOTE> <BLOCKQUOTE>
<P>The Actions Dialog displays a list of all actions (or commands) relevant to the <P>The Quick Action Dialog displays a list of all actions (or commands) relevant to the
currently focused component window or dialog and allows the user to select and invoke any currently focused component window or dialog and allows the user to select and invoke any
valid, enabled action using either the mouse or keyboard.</P> valid, enabled action using either the mouse or keyboard.</P>
@@ -70,24 +83,24 @@
<P>Initially, the dialog shows just the local toolbar and menu items for the currently <P>Initially, the dialog shows just the local toolbar and menu items for the currently
focused component, along with all relevant popup and keyboard actions. Repeatedly focused component, along with all relevant popup and keyboard actions. Repeatedly
pressing the keybinding assigned to this action (default is &LT;CTRL&GT; 3) will show pressing the keybinding assigned to this action (default is <B>Ctrl-3</B>) will show
additional, less relevant actions. additional, less relevant actions.
<P>Displayed actions in the list can be selected via the mouse or by using the up/down <P>Displayed actions in the list can be selected via the mouse or by using the up/down
arrows to move the current selection. Pressing the OK button or pressing the arrows to move the current selection. Pressing the OK button or pressing the
&lt;ENTER&gt; key will cause the dialog to close and the action to be invoked.</P> <B>Enter</B> key will cause the dialog to close and the action to be invoked.</P>
<P>Also, the list can be filtered by typing in the provided text box.</P> <P>Also, the list can be filtered by typing in the provided text box.</P>
<BLOCKQUOTE> <BLOCKQUOTE>
<P><IMG border="0" src="help/shared/note.png" alt="">This dialog can be invoked using <P><IMG border="0" src="help/shared/note.png" alt="">This dialog can be invoked using
its assigned keybinding (default is &LT;CTRL&GT; 3).</P> its assigned keybinding (default is <B>Ctrl-3</B>).</P>
<P><IMG border="0" src="help/shared/note.png" alt="">Help (F1) and Assign Keybinding <P><IMG border="0" src="help/shared/note.png" alt="">Help (<B>F1</B>) and Assign Keybinding
(F4) actions work on the selected action.</P> (<B>F4</B>) actions work on the selected action.</P>
<P><IMG border="0" src="help/shared/note.png" alt="">Bringing up this dialog and pressing <P><IMG border="0" src="help/shared/note.png" alt="">Bringing up this dialog and pressing
(&lt;CTRL&gt; 3) a few times to show all local and global actions is a great way to (<B>Ctrl-3</B>) a few times to show all local and global actions is a great way to
explore all the actions Ghidra actions. </P> explore all the actions Ghidra actions. </P>

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -81,6 +81,9 @@ public interface ToolConstants extends DockingToolConstants {
/** A group for actions that link directly to help content */ /** A group for actions that link directly to help content */
public static final String HELP_CONTENTS_MENU_GROUP = "AAAHelpContents"; public static final String HELP_CONTENTS_MENU_GROUP = "AAAHelpContents";
/** A group for actions that show system runtime information */
public static final String HELP_RUNTIME_MENU_GROUP = "RRRHelpContents";
/** /**
* Constant for the options menu group for the Tool Options menu item * Constant for the options menu group for the Tool Options menu item
*/ */

View File

@@ -788,14 +788,15 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
addHelpActions(); addHelpActions();
// our log file action // our log file action
DockingAction action = new DockingAction("Show Log", ToolConstants.TOOL_OWNER) { DockingAction action = new DockingAction("View Log", ToolConstants.TOOL_OWNER) {
@Override @Override
public void actionPerformed(ActionContext context) { public void actionPerformed(ActionContext context) {
showGhidraUserLogFile(); showGhidraUserLogFile();
} }
}; };
action.setMenuBarData( action.setMenuBarData(
new MenuData(new String[] { ToolConstants.MENU_HELP, "Show Log" }, null, "BBB")); new MenuData(new String[] { ToolConstants.MENU_HELP, "Show Log" }, null,
ToolConstants.HELP_RUNTIME_MENU_GROUP));
action.setEnabled(true); action.setEnabled(true);
addAction(action); addAction(action);

View File

@@ -15,53 +15,24 @@
*/ */
package ghidra.framework.plugintool; package ghidra.framework.plugintool;
import static ghidra.framework.model.ToolTemplate.TOOL_INSTANCE_NAME_XML_NAME; import static ghidra.framework.model.ToolTemplate.*;
import static ghidra.framework.model.ToolTemplate.TOOL_NAME_XML_NAME;
import java.awt.Component; import java.awt.*;
import java.awt.Dimension;
import java.awt.FocusTraversalPolicy;
import java.awt.Image;
import java.awt.KeyboardFocusManager;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport; import java.beans.PropertyChangeSupport;
import java.net.URL; import java.net.URL;
import java.util.Arrays; import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function; import java.util.function.Function;
import javax.swing.Icon; import javax.swing.*;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.KeyStroke;
import org.jdom2.Element; import org.jdom2.Element;
import docking.AbstractDockingTool; import docking.*;
import docking.ActionContext; import docking.action.*;
import docking.ActionToGuiHelper;
import docking.ComponentProvider;
import docking.DialogComponentProvider;
import docking.DockingUtils;
import docking.DockingWindowManager;
import docking.ErrLogDialog;
import docking.ErrorReporter;
import docking.action.ActionContextProvider;
import docking.action.DockingAction;
import docking.action.DockingActionIf;
import docking.action.KeyBindingData;
import docking.action.MenuData;
import docking.action.builder.ActionBuilder; import docking.action.builder.ActionBuilder;
import docking.actions.PopupActionProvider; import docking.actions.PopupActionProvider;
import docking.actions.ToolActions; import docking.actions.ToolActions;
@@ -72,48 +43,24 @@ import docking.tool.ToolConstants;
import docking.tool.util.DockingToolConstants; import docking.tool.util.DockingToolConstants;
import docking.util.image.ToolIconURL; import docking.util.image.ToolIconURL;
import docking.widgets.OptionDialog; import docking.widgets.OptionDialog;
import ghidra.framework.Application;
import ghidra.framework.OperatingSystem; import ghidra.framework.OperatingSystem;
import ghidra.framework.Platform; import ghidra.framework.Platform;
import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.main.AppInfo; import ghidra.framework.main.AppInfo;
import ghidra.framework.main.UserAgreementDialog; import ghidra.framework.main.UserAgreementDialog;
import ghidra.framework.model.DomainFile; import ghidra.framework.model.*;
import ghidra.framework.model.DomainObject; import ghidra.framework.options.*;
import ghidra.framework.model.Project;
import ghidra.framework.model.ProjectManager;
import ghidra.framework.model.ToolListener;
import ghidra.framework.model.ToolServices;
import ghidra.framework.model.ToolTemplate;
import ghidra.framework.options.Options;
import ghidra.framework.options.OptionsChangeListener;
import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.dialog.ManagePluginsDialog; import ghidra.framework.plugintool.dialog.ManagePluginsDialog;
import ghidra.framework.plugintool.mgr.DialogManager; import ghidra.framework.plugintool.mgr.*;
import ghidra.framework.plugintool.mgr.EventManager; import ghidra.framework.plugintool.util.*;
import ghidra.framework.plugintool.mgr.OptionsManager;
import ghidra.framework.plugintool.mgr.ServiceManager;
import ghidra.framework.plugintool.mgr.ToolTaskManager;
import ghidra.framework.plugintool.util.DefaultPluginsConfiguration;
import ghidra.framework.plugintool.util.PluginEventListener;
import ghidra.framework.plugintool.util.PluginException;
import ghidra.framework.plugintool.util.ServiceListener;
import ghidra.framework.plugintool.util.TransientToolState;
import ghidra.framework.plugintool.util.UndoRedoToolState;
import ghidra.framework.project.ProjectDataService; import ghidra.framework.project.ProjectDataService;
import ghidra.framework.project.extensions.ExtensionTableDialog; import ghidra.framework.project.extensions.ExtensionTableDialog;
import ghidra.util.HelpLocation; import ghidra.util.*;
import ghidra.util.Msg;
import ghidra.util.Swing;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.Task; import ghidra.util.task.*;
import ghidra.util.task.TaskLauncher;
import ghidra.util.task.TaskListener;
import ghidra.util.task.TaskMonitor;
import help.Help; import help.Help;
import help.HelpService; import help.HelpService;
import resources.ResourceManager;
/** /**
* Base class that is a container to manage plugins and their actions, and to coordinate the * Base class that is a container to manage plugins and their actions, and to coordinate the
@@ -1176,6 +1123,37 @@ public abstract class PluginTool extends AbstractDockingTool {
} }
protected void addHelpActions() { protected void addHelpActions() {
HelpService help = Help.getHelpService();
int subgroup = 0;
new ActionBuilder("Contents", ToolConstants.TOOL_OWNER)
.menuPath(ToolConstants.MENU_HELP, "&Contents")
.menuGroup(ToolConstants.HELP_CONTENTS_MENU_GROUP, Integer.toString(subgroup++))
.helpLocation(new HelpLocation("Misc", "Welcome_to_Ghidra_Help"))
.inWindow(ActionBuilder.When.ALWAYS)
.onAction(c -> help.showHelp(null, false, getToolFrame()))
.buildAndInstall(this);
new ActionBuilder("Accessibility", ToolConstants.TOOL_OWNER)
.menuPath(ToolConstants.MENU_HELP, "&Accessibility")
.menuGroup(ToolConstants.HELP_CONTENTS_MENU_GROUP, Integer.toString(subgroup++))
.helpLocation(new HelpLocation("Accessibility", "AccessibilityOverview"))
.inWindow(ActionBuilder.When.ALWAYS)
.onAction(c -> {
help.showHelp(new HelpLocation("Accessibility", "AccessibilityOverview"));
})
.buildAndInstall(this);
new ActionBuilder("User Agreement", ToolConstants.TOOL_OWNER)
.menuPath(ToolConstants.MENU_HELP, "&User Agreement")
.menuGroup(ToolConstants.HELP_CONTENTS_MENU_GROUP, Integer.toString(subgroup++))
.helpLocation(new HelpLocation(ToolConstants.ABOUT_HELP_TOPIC, "User_Agreement"))
.inWindow(ActionBuilder.When.ALWAYS)
.onAction(
c -> DockingWindowManager.showDialog(new UserAgreementDialog(false, false)))
.buildAndInstall(this);
new ActionBuilder("About Ghidra", ToolConstants.TOOL_OWNER) new ActionBuilder("About Ghidra", ToolConstants.TOOL_OWNER)
.menuPath(ToolConstants.MENU_HELP, "&About Ghidra") .menuPath(ToolConstants.MENU_HELP, "&About Ghidra")
.menuGroup("ZZA") .menuGroup("ZZA")
@@ -1184,16 +1162,7 @@ public abstract class PluginTool extends AbstractDockingTool {
.onAction(c -> DockingWindowManager.showDialog(new AboutDialog())) .onAction(c -> DockingWindowManager.showDialog(new AboutDialog()))
.buildAndInstall(this); .buildAndInstall(this);
new ActionBuilder("User Agreement", ToolConstants.TOOL_OWNER) ErrorReporter reporter = ErrLogDialog.getErrorReporter();
.menuPath(ToolConstants.MENU_HELP, "&User Agreement")
.menuGroup(ToolConstants.HELP_CONTENTS_MENU_GROUP)
.helpLocation(new HelpLocation(ToolConstants.ABOUT_HELP_TOPIC, "User_Agreement"))
.inWindow(ActionBuilder.When.ALWAYS)
.onAction(
c -> DockingWindowManager.showDialog(new UserAgreementDialog(false, false)))
.buildAndInstall(this);
final ErrorReporter reporter = ErrLogDialog.getErrorReporter();
if (reporter != null) { if (reporter != null) {
new ActionBuilder("Report Bug", ToolConstants.TOOL_OWNER) new ActionBuilder("Report Bug", ToolConstants.TOOL_OWNER)
.menuPath(ToolConstants.MENU_HELP, "&Report Bug...") .menuPath(ToolConstants.MENU_HELP, "&Report Bug...")
@@ -1203,30 +1172,6 @@ public abstract class PluginTool extends AbstractDockingTool {
.onAction(c -> reporter.report(getToolFrame(), "User Bug Report", null)) .onAction(c -> reporter.report(getToolFrame(), "User Bug Report", null))
.buildAndInstall(this); .buildAndInstall(this);
} }
HelpService help = Help.getHelpService();
new ActionBuilder("Contents", ToolConstants.TOOL_OWNER)
.menuPath(ToolConstants.MENU_HELP, "&Contents")
.menuGroup(ToolConstants.HELP_CONTENTS_MENU_GROUP)
.helpLocation(new HelpLocation("Misc", "Welcome_to_Ghidra_Help"))
.inWindow(ActionBuilder.When.ALWAYS)
.onAction(c -> help.showHelp(null, false, getToolFrame()))
.buildAndInstall(this);
new ActionBuilder("Accessibility", ToolConstants.TOOL_OWNER)
.menuPath(ToolConstants.MENU_HELP, "&Accessibility")
.menuGroup("ZZZ")
.helpLocation(new HelpLocation("Accessibility", "AccessibilityOverview"))
.inWindow(ActionBuilder.When.ALWAYS)
.onAction(c -> {
help.showHelp(new HelpLocation("Accessibility", "AccessibilityOverview"));
})
.buildAndInstall(this);
} }
/** /**