Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keyboard Navigation #3193

Open
wants to merge 39 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
31e818b
Focus component search box with /
Venkata-Sai-Vishwanath-robo Jul 5, 2024
fe22d80
shortcuts for refreshing companion screen and resetting connection
Venkata-Sai-Vishwanath-robo Jul 5, 2024
a6cd6c5
Rename component with Alt + R
Venkata-Sai-Vishwanath-robo Jul 5, 2024
800c48c
Switch between design and blocks view
Venkata-Sai-Vishwanath-robo Jul 7, 2024
9c4646c
Navigation for the project explorer
Venkata-Sai-Vishwanath-robo Jul 7, 2024
e9af08a
Navigation for dropdowns
Venkata-Sai-Vishwanath-robo Jul 7, 2024
ec12849
css
Venkata-Sai-Vishwanath-robo Jul 7, 2024
64b4e99
Merge branch 'master' into keyboardNavigation
Venkata-Sai-Vishwanath-robo Jul 7, 2024
e8fc45a
shortcuts for blockly editor
Venkata-Sai-Vishwanath-robo Jul 7, 2024
b699190
Merge branch 'keyboardNavigation' of https://github.com/Venkata-Sai-V…
Venkata-Sai-Vishwanath-robo Jul 7, 2024
87eb4c5
checkbox text for screen readers
Venkata-Sai-Vishwanath-robo Jul 8, 2024
14501ed
Accessibility
Venkata-Sai-Vishwanath-robo Jul 8, 2024
d1f02f6
Tooltips and messages
Venkata-Sai-Vishwanath-robo Jul 8, 2024
b296f6c
better version of project explorer navigation
Venkata-Sai-Vishwanath-robo Jul 10, 2024
4e2a979
neo
Venkata-Sai-Vishwanath-robo Jul 14, 2024
d53b293
adding components using keyboard only
Venkata-Sai-Vishwanath-robo Jul 31, 2024
347b05b
focus SourceStructureExplorerItem on selection change.
Venkata-Sai-Vishwanath-robo Jul 31, 2024
79f7391
Focus trap for new folder and new project dialog box
Venkata-Sai-Vishwanath-robo Jul 31, 2024
6115d95
component adding
Venkata-Sai-Vishwanath-robo Aug 5, 2024
cd1c39e
property editors made keyboard accessible
Venkata-Sai-Vishwanath-robo Aug 8, 2024
18484a3
better focus visibility for checkboxes and ColorChoicePropertyEditor
Venkata-Sai-Vishwanath-robo Aug 8, 2024
f4cb850
Dropdown button maintaing focus, check box visibility and UI settings…
Venkata-Sai-Vishwanath-robo Aug 11, 2024
9a96f1a
Color choice property editor maintains focus after selection.
Venkata-Sai-Vishwanath-robo Aug 11, 2024
25d4f32
tree highlight and focus-trap in move projects dialog
Venkata-Sai-Vishwanath-robo Aug 14, 2024
e7e3b0f
Focus search text box with / (better code)
Venkata-Sai-Vishwanath-robo Aug 19, 2024
e5d131f
single line imports
Venkata-Sai-Vishwanath-robo Aug 19, 2024
dc22e43
fix : Constructor visibility
Venkata-Sai-Vishwanath-robo Aug 19, 2024
5963325
dialog boxes
Venkata-Sai-Vishwanath-robo Aug 23, 2024
b6f6330
updated isTextboxFocused method
Venkata-Sai-Vishwanath-robo Aug 23, 2024
2a52e64
Update: Component adding
Venkata-Sai-Vishwanath-robo Aug 25, 2024
4c98faf
Shortcuts Dialog box
Venkata-Sai-Vishwanath-robo Aug 25, 2024
5f40827
fix: shortcuts dialog
Venkata-Sai-Vishwanath-robo Aug 26, 2024
ce12f23
Component Moving
Venkata-Sai-Vishwanath-robo Aug 26, 2024
7ecfa20
tree highlighting upon click
Venkata-Sai-Vishwanath-robo Aug 26, 2024
ab4c3d4
Shortcuts dialog for neo
Venkata-Sai-Vishwanath-robo Aug 28, 2024
1ea4775
Shortcuts to focus the Viewer and Properties, using V and P
Venkata-Sai-Vishwanath-robo Sep 1, 2024
0244b78
fix: dropdown opens with no pre-selected item.
Venkata-Sai-Vishwanath-robo Sep 8, 2024
7e7cad3
chore: remove unused code.
Venkata-Sai-Vishwanath-robo Sep 8, 2024
080be5d
revert: remove unused code.
Venkata-Sai-Vishwanath-robo Sep 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions appinventor/appengine/src/com/google/appinventor/client/Ode.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.google.appinventor.client.editor.EditorManager;
import com.google.appinventor.client.editor.FileEditor;
import com.google.appinventor.client.editor.ProjectEditor;
import com.google.appinventor.client.editor.simple.components.MockComponent;
import com.google.appinventor.client.editor.simple.palette.DropTargetProvider;
import com.google.appinventor.client.editor.youngandroid.BlocklyPanel;
import com.google.appinventor.client.editor.youngandroid.DesignToolbar;
Expand Down Expand Up @@ -82,7 +83,11 @@
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.MouseWheelEvent;
import com.google.gwt.event.dom.client.MouseWheelHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
Expand All @@ -94,6 +99,7 @@
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
Expand All @@ -117,6 +123,8 @@
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.widgetideas.client.event.KeyDownHandler;

import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand Down Expand Up @@ -1609,6 +1617,15 @@ public DialogBox createEmptyTrashDialog(boolean showDialog) {
dialogBox.show();
}

Event.addNativePreviewHandler(new Event.NativePreviewHandler() {
@Override
public void onPreviewNativeEvent(Event.NativePreviewEvent event) {
if (event.getTypeInt() == Event.ONKEYDOWN && dialogBox.isShowing()) {
dialogBox.hide();
}
}
});

return dialogBox;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -655,15 +655,15 @@ public interface OdeMessages extends Messages, AutogeneratedOdeMessages {
@Description("Message providing details about starting a USB connection.")
String usbMenuItem();

@DefaultMessage("Reset Connection")
@DefaultMessage("Reset Connection (Alt + Shift + R)")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to revisit this choice, since Alt on Windows typically maps to Cmd on macOS, and Cmd + R will refresh the page.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to revisit this choice, since Alt on Windows typically maps to Cmd on macOS, and Cmd + R will refresh the page.

Does't Ctrl usually map to Cmd on MacOS in GUI aps? I usually expect Alt to map to Option.

I realize that we have a Ctrl button, and that works as Ctrl for a lot of command line stuff. There's no consistent official mapping.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback @ewpatton. I will look into these and fix them.
I will once go through the shortcuts in macOS and see for any more overlaps.
I still need to add code that adjusts the shortcut key messages based on whether the user is on Windows or macOS.
The community feedback is still pending, and I plan to complete it by the end of this week.

@Description("Reset all connections.")
String resetConnectionsMenuItem();

@DefaultMessage("Hard Reset")
@Description("Hard Reset the Emulator.")
String hardResetConnectionsMenuItem();

@DefaultMessage("Refresh Companion Screen")
@DefaultMessage("Refresh Companion Screen (Alt + R)")
@Description("Refresh the companion screen.")
String refreshCompanionMenuItem();

Expand Down Expand Up @@ -725,6 +725,10 @@ public interface OdeMessages extends Messages, AutogeneratedOdeMessages {
@Description("Redisplay the Splash Screen")
String showSplashMenuItem();

@DefaultMessage("Show Keyboard Shortcuts (Alt + ?)")
@Description("Display the Shortcuts dialog")
String showShortcuts();

@DefaultMessage("Library")
@Description("Name of Library link")
String libraryMenuItem();
Expand Down Expand Up @@ -1254,7 +1258,7 @@ public interface OdeMessages extends Messages, AutogeneratedOdeMessages {
String blocksLoadFailure(String formName);

// Used in editor/youngandroid/palette/YoungAndroidPalettePanel.java
@DefaultMessage("Search Components...")
@DefaultMessage("Type / to search components")
@Description("Text shown in the component palette search box")
String searchComponents();

Expand Down Expand Up @@ -5119,6 +5123,39 @@ String newerVersionComponentException(String componentType, int srcCompVersion,
@Description("")
String MaximumRangeMethods();

@DefaultMessage(
"<table border='1' cellpadding='8' cellspacing='0'>" +
"<thead>" +
"<tr>" +
"<th>Action</th>" +
"<th>Key Combination</th>" +
"</tr>" +
"</thead>" +
"<tbody>" +
"<tr><td>Focus Component search box</td><td>/</td></tr>" +
"<tr><td>Focus Components tree</td><td>T</td></tr>" +
"<tr><td>Focus Viewer</td><td>V</td></tr>" +
"<tr><td>Focus Properties Panel</td><td>P</td></tr>" +
"<tr><td>Switch between Designer and Block editor</td><td>Ctrl + Alt</td></tr>" +
"<tr><td>Rename Component</td><td>Alt + N</td></tr>" +
"<tr><td>Reset Connection</td><td>Alt + Shift + R</td></tr>" +
"<tr><td>Refresh Companion Screen</td><td>Alt + R</td></tr>" +
"<tr><td>Open/Close Backpack</td><td>Alt + B</td></tr>" +
"<tr><td>Switch between Inline and External Inputs</td><td>Alt + I</td></tr>" +
"<tr><td>Add comment to a block</td><td>Alt + K</td></tr>" +
"<tr><td>Expand/Collapse block</td><td>Alt + O</td></tr>" +
"<tr><td>Navigate up the blocks</td><td>Alt + S</td></tr>" +
"<tr><td>Navigate down the blocks</td><td>Alt + W</td></tr>" +
"<tr><td>Zoom in</td><td>Alt + +</td></tr>" +
"<tr><td>Zoom out</td><td>Alt + -</td></tr>" +
"<tr><td>Re-center</td><td>Alt + G</td></tr>" +
"<tr><td>Navigate Components</td><td>↑/↓</td></tr>" +
"<tr><td>Open this dialog</td><td>Alt + ?</td></tr>" +
"</tbody>" +
"</table>")
@Description("")
String KeyBoardShortcuts();

// =========== ListPicker
@DefaultMessage("ItemTextColor")
@Description("")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@
<ai:DropDownItem name="ShowSplash" caption="{messages.showSplashMenuItem}">
<actions:ShowSplashAction/>
</ai:DropDownItem>
<ai:DropDownItem name="ShowShortcuts" caption="{messages.showShortcuts}">
<actions:ShowShortcutsAction/>
</ai:DropDownItem>
</ai:DropDownButton>

<!-- Admin Menu -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2023 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

package com.google.appinventor.client.actions;

import static com.google.appinventor.client.Ode.MESSAGES;

import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.VerticalPanel;

public class ShowShortcutsAction implements Command {

private DialogBox db;

public ShowShortcutsAction() {
db = new DialogBox(true, false);
db.setText("Keyboard Shortcuts");
db.setStyleName("ode-DialogBox");
db.setHeight("200px");
db.setWidth("400px");
db.setGlassEnabled(true);
db.setAnimationEnabled(true);

shortcutKeyHandler();
}

@Override
public void execute() {
VerticalPanel DialogBoxContents = new VerticalPanel();
HTML message = new HTML(MESSAGES.KeyBoardShortcuts());
DialogBoxContents.add(message);
db.setWidget(DialogBoxContents);
db.center();
db.show();
}

private void shortcutKeyHandler() {
Event.addNativePreviewHandler(new Event.NativePreviewHandler() {
@Override
public void onPreviewNativeEvent(Event.NativePreviewEvent event) {
NativeEvent nativeEvent = event.getNativeEvent();
if (event.getTypeInt() == Event.ONKEYDOWN && nativeEvent.getAltKey() && nativeEvent.getKeyCode() == 191 && !db.isShowing()) {
nativeEvent.preventDefault();
execute();
} else if (event.getTypeInt() == Event.ONKEYDOWN && db.isShowing()) {
nativeEvent.preventDefault();
db.hide();
}
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
Expand All @@ -42,6 +43,7 @@ interface SimpleVisibleComponentsPanelUiBinder extends UiBinder<VerticalPanel, S
@UiField(provided = true) protected ListBox listboxPhonePreview; // A ListBox for Holo/Material/iOS preview styles
private final int[][] drop_lst = { {320, 505}, {480, 675}, {768, 1024} };
private final String[] drop_lst_phone_preview = { "Android Material", "Android Holo", "iOS" };
@UiField protected CheckBox HiddenComponentsCheckbox;

// Corresponding panel for non-visible components (because we allow users to drop
// non-visible components onto the form, but we show them in the non-visible
Expand Down Expand Up @@ -218,6 +220,10 @@ public void enablePhonePreviewCheckBox(boolean enable){
listboxPhonePreview.setEnabled(enable);
}

public void focusCheckbox() {
HiddenComponentsCheckbox.setFocus(true);
}

/**
* Associates a Simple form component with this panel.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<ui:with field="messages" type="com.google.appinventor.client.OdeMessages"/>
<g:VerticalPanel styleName="ode-SimpleFormDesigner">
<g:VerticalPanel ui:field="phoneScreen" stylePrimaryName="ode-SimpleFormDesigner">
<ed:HiddenComponentsCheckbox text="{messages.showHiddenComponentsCheckbox}"/>
<ed:HiddenComponentsCheckbox ui:field="HiddenComponentsCheckbox" text="{messages.showHiddenComponentsCheckbox}"/>
<g:ListBox ui:field="listboxPhoneTablet">
<g:item value="0">
<ui:text from="{messages.previewPhoneSize}"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.HasAllTouchHandlers;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.TouchCancelHandler;
import com.google.gwt.event.dom.client.TouchEndHandler;
import com.google.gwt.event.dom.client.TouchMoveHandler;
Expand Down Expand Up @@ -110,22 +112,25 @@ private class RenameDialog extends DialogBox {
private final LabeledTextBox newNameTextBox;

RenameDialog(String oldName) {
super(false, true);

super(false, false);
setGlassEnabled(true);
setStylePrimaryName("ode-DialogBox");
setText(MESSAGES.renameTitle());
VerticalPanel contentPanel = new VerticalPanel();

Button topInvisible = new Button();
contentPanel.add(topInvisible);

LabeledTextBox oldNameTextBox = new LabeledTextBox(MESSAGES.oldNameLabel());
oldNameTextBox.setText(getName());
oldNameTextBox.setEnabled(false);
contentPanel.add(oldNameTextBox);

newNameTextBox = new LabeledTextBox(MESSAGES.newNameLabel());
newNameTextBox.setText(oldName);
newNameTextBox.getTextBox().addKeyUpHandler(new KeyUpHandler() {
newNameTextBox.getTextBox().addKeyDownHandler(new KeyDownHandler() {
@Override
public void onKeyUp(KeyUpEvent event) {
public void onKeyDown(KeyDownEvent event) {
int keyCode = event.getNativeKeyCode();
if (keyCode == KeyCodes.KEY_ENTER) {
handleOkClick();
Expand All @@ -150,9 +155,26 @@ public void onClick(ClickEvent event) {
handleOkClick();
}
});

Button bottomInvisible = new Button();
bottomInvisible.setStyleName("FocusTrap");
topInvisible.setStyleName("FocusTrap");
topInvisible.addFocusHandler(new FocusHandler() {
@Override
public void onFocus(FocusEvent event) {
okButton.setFocus(true);
}
});
bottomInvisible.addFocusHandler(new FocusHandler() {
public void onFocus(FocusEvent event) {
newNameTextBox.setFocus(true);
}
});

HorizontalPanel buttonPanel = new HorizontalPanel();
buttonPanel.add(cancelButton);
buttonPanel.add(okButton);
buttonPanel.add(bottomInvisible);
buttonPanel.setSize("100%", "24px");
contentPanel.add(buttonPanel);
contentPanel.setSize("320px", "100%");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import com.google.appinventor.client.ComponentsTranslation;
import com.google.appinventor.client.editor.simple.SimpleEditor;
import com.google.appinventor.client.editor.simple.SimpleNonVisibleComponentsPanel;
import com.google.appinventor.client.editor.youngandroid.properties.YoungAndroidLengthPropertyEditor;
import com.google.appinventor.client.widgets.properties.TextPropertyEditor;
import com.google.appinventor.components.common.ComponentConstants;
Expand Down Expand Up @@ -158,4 +159,9 @@ public void onPropertyChange(String propertyName, String newValue) {
refreshForm();
}
}
}

public SimpleNonVisibleComponentsPanel getNonVisibleComponentsPanel() {
return editor.getNonVisibleComponentsPanel();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,24 @@

package com.google.appinventor.client.editor.simple.palette;

import java.util.List;

import com.google.appinventor.client.ComponentsTranslation;
import com.google.appinventor.client.editor.simple.components.MockComponent;
import com.google.appinventor.client.editor.simple.components.MockComponentsUtil;
import com.google.appinventor.client.editor.simple.components.MockContainer;
import com.google.appinventor.client.editor.simple.components.MockForm;
import com.google.appinventor.client.editor.simple.components.MockVisibleComponent;
import com.google.appinventor.client.widgets.dnd.DragSourcePanel;
import com.google.appinventor.client.widgets.dnd.DragSourceSupport;
import com.google.appinventor.client.widgets.dnd.DropTarget;
import com.google.gwt.event.dom.client.DoubleClickEvent;
import com.google.gwt.event.dom.client.DoubleClickHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.TouchStartEvent;
Expand Down Expand Up @@ -114,6 +126,40 @@ public void onTouchStart(TouchStartEvent event) {
select(getWidget());
}
});
addFocusHandler(new FocusHandler() {
@Override
public void onFocus(FocusEvent event) {
select(getWidget());
}
});
addKeyDownHandler(new KeyDownHandler() {
@Override
public void onKeyDown (KeyDownEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
addComponent();
}
}
});
addDoubleClickHandler(new DoubleClickHandler() {
public void onDoubleClick (DoubleClickEvent event) {
addComponent();
}
});
}

private void addComponent() {
MockComponent component = createMockComponent();
MockVisibleComponent mockVisibleComponent = (MockVisibleComponent) dropTargetProvider.getDropTargets()[0];
MockForm form = mockVisibleComponent.getForm();
MockComponent selectedComponent = form.getLastSelectedComponent();
if (selectedComponent instanceof MockContainer && ((MockContainer) selectedComponent).willAcceptComponentType(component.getType()) && component.isVisibleComponent()) {
((MockContainer) selectedComponent).addComponent(component);
} else if (form.willAcceptComponentType(component.getType()) && component.isVisibleComponent()) {
form.addComponent(component);
} else if (form.willAcceptComponentType(component.getType()) && !component.isVisibleComponent()) {
form.addComponent(component);
form.getNonVisibleComponentsPanel().addComponent(component);
}
}

/**
Expand Down
Loading