Skip to content

Commit

Permalink
Deactivate continuous jogging when a key is released (#2390)
Browse files Browse the repository at this point in the history
  • Loading branch information
breiler authored Dec 14, 2023
1 parent 3eb1055 commit 0117e56
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This file is part of Universal Gcode Sender (UGS).
package com.willwinder.universalgcodesender.services;

import com.willwinder.universalgcodesender.listeners.ControllerState;
import com.willwinder.universalgcodesender.model.Axis;
import com.willwinder.universalgcodesender.model.BackendAPI;
import com.willwinder.universalgcodesender.model.PartialPosition;
import com.willwinder.universalgcodesender.model.UnitUtils.Units;
Expand Down Expand Up @@ -251,7 +252,12 @@ public boolean useStepSizeZ() {
}

public boolean showABCStepSize() {
return getSettings().showABCStepSize();
boolean hasAbcAxes = backend.getController() != null &&
(backend.getController().getCapabilities().hasAxis(Axis.A) ||
backend.getController().getCapabilities().hasAxis(Axis.B) ||
backend.getController().getCapabilities().hasAxis(Axis.C));

return getSettings().showABCStepSize() && hasAbcAxes;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,14 @@ public void release() {
return;
}

((ContinuousAction) actionReference.get().getAction()).actionDeactivated();
if (actionReference.get().getAction() instanceof ContinuousAction continuousAction) {
continuousAction.actionDeactivated();
}
actionReference.set(null);
isLongPressed = false;
}

public boolean isLongPressed() {
return isLongPressed;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ This file is part of Universal Gcode Sender (UGS).
import com.willwinder.ugs.nbp.lib.services.ActionReference;
import com.willwinder.ugs.nbp.lib.services.ActionRegistrationService;
import com.willwinder.ugs.nbp.lib.services.ShortcutService;
import static java.awt.event.KeyEvent.KEY_PRESSED;
import static java.awt.event.KeyEvent.KEY_RELEASED;
import org.openide.modules.OnStart;
import org.openide.util.Lookup;
import org.openide.util.Utilities;
Expand All @@ -38,9 +40,6 @@ This file is part of Universal Gcode Sender (UGS).
import java.util.Optional;
import java.util.logging.Logger;

import static java.awt.event.KeyEvent.KEY_PRESSED;
import static java.awt.event.KeyEvent.KEY_RELEASED;

/**
* A shortcut listener that will attempt to intercept shortcuts to continuous actions.
* If key was pressed shorter than a certain threshold the normal
Expand Down Expand Up @@ -68,7 +67,7 @@ public class ContinuousActionShortcutListener implements Runnable, KeyEventDispa
private final ContinuousActionExecutor executor;

public ContinuousActionShortcutListener() {
shortcutService = Lookup.getDefault().lookup(ShortcutService.class);
shortcutService = new ShortcutService();
actionRegistrationService = Lookup.getDefault().lookup(ActionRegistrationService.class);
executor = new ContinuousActionExecutor(LONG_PRESS_DELAY);
}
Expand All @@ -95,7 +94,7 @@ private String getKeyAsString(KeyEvent e) {
}

private Optional<ActionReference> getContinuousActionByShortcut(String keyAsString) {
return shortcutService.getActionIdForShortcut(keyAsString)
return shortcutService.getActionIdForShortcut(keyAsString)
.flatMap(actionRegistrationService::getActionById)
.filter(action -> action.getAction() instanceof ContinuousAction);
}
Expand All @@ -110,6 +109,13 @@ public boolean dispatchKeyEvent(KeyEvent keyEvent) {
return false;
}

// On any key release we should abort a long pressed executor
if (keyEvent.getID() == KEY_RELEASED && executor.isLongPressed()) {
executor.release();
keyEvent.consume();
return false;
}

// Try to find an continuous action for the current keys
String keyAsString = getKeyAsString(keyEvent);
Optional<ActionReference> actionById = getContinuousActionByShortcut(keyAsString);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ This file is part of Universal Gcode Sender (UGS).
*/
package com.willwinder.ugs.nbp.core.services;

import static com.willwinder.ugs.nbp.core.services.JogSizeAction.Operation.*;
import com.willwinder.ugs.nbp.lib.services.ActionRegistrationService;
import com.willwinder.universalgcodesender.i18n.Localization;
import com.willwinder.universalgcodesender.model.UnitUtils.Units;
Expand All @@ -27,8 +28,6 @@ This file is part of Universal Gcode Sender (UGS).

import java.io.IOException;

import static com.willwinder.ugs.nbp.core.services.JogSizeAction.Operation.*;

/**
* A service for registering jog actions such as menu items and shortcuts
*
Expand Down Expand Up @@ -57,19 +56,19 @@ private void initActions() {

// Jog plus/minus X
ars.registerAction(JogActionService.class.getCanonicalName() + ".xPlus", Localization.getString("jogging.xPlus") ,
category, "M-RIGHT" , menuPath, 0, localized, new JogAction(1, 0, 0, 0, 0, 0));
category, "D-RIGHT" , menuPath, 0, localized, new JogAction(1, 0, 0, 0, 0, 0));
ars.registerAction(JogActionService.class.getCanonicalName() + ".xMinus", Localization.getString("jogging.xMinus"),
category, "M-LEFT" , menuPath, 0, localized, new JogAction(-1, 0, 0, 0, 0, 0));
category, "D-LEFT" , menuPath, 0, localized, new JogAction(-1, 0, 0, 0, 0, 0));
// Jog plus/minus Y
ars.registerAction(JogActionService.class.getCanonicalName() + ".yPlus", Localization.getString("jogging.yPlus") ,
category, "M-UP" , menuPath, 0, localized, new JogAction(0, 1, 0, 0, 0,0));
category, "D-UP" , menuPath, 0, localized, new JogAction(0, 1, 0, 0, 0,0));
ars.registerAction(JogActionService.class.getCanonicalName() + ".yMinus", Localization.getString("jogging.yMinus"),
category, "M-DOWN" , menuPath, 0, localized, new JogAction( 0,-1, 0,0 ,0 ,0));
category, "D-DOWN" , menuPath, 0, localized, new JogAction( 0,-1, 0,0 ,0 ,0));
// Jog plus/minus Z
ars.registerAction(JogActionService.class.getCanonicalName() + ".zPlus", Localization.getString("jogging.zPlus") ,
category, "SM-UP" , menuPath, 0, localized, new JogAction(0, 0, 1, 0,0, 0));
category, "SD-UP" , menuPath, 0, localized, new JogAction(0, 0, 1, 0,0, 0));
ars.registerAction(JogActionService.class.getCanonicalName() + ".zMinus", Localization.getString("jogging.zMinus"),
category, "SM-DOWN" , menuPath, 0, localized, new JogAction(0, 0,-1, 0,0,0));
category, "SD-DOWN" , menuPath, 0, localized, new JogAction(0, 0,-1, 0,0,0));
// Jog plus/minus A
ars.registerAction(JogActionService.class.getCanonicalName() + ".aPlus", Localization.getString("jogging.aPlus") ,
category, null , menuPath, 0, localized, new JogAction(0, 0, 0, 1, 0, 0));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@
import com.willwinder.ugs.nbp.lib.services.ActionReference;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import javax.swing.JLabel;
import java.awt.event.KeyEvent;

import static org.mockito.ArgumentMatchers.any;
import org.mockito.Mock;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import org.mockito.MockitoAnnotations;

import javax.swing.JLabel;
import java.awt.event.KeyEvent;

public class ContinuousActionExecutorTest {

Expand Down Expand Up @@ -73,6 +73,20 @@ public void longKeyPressAndChangeActionShouldAbortFirstAction() throws Interrupt
verifyNoMoreInteractions(action);
}

@Test
public void longKeyPressAndReleaseAnyKeyShouldAbortFirstAction() throws InterruptedException {
KeyEvent anyKey = mock(KeyEvent.class);

target.setCurrentAction(actionReference);
target.keyPressed(keyEvent);
Thread.sleep(120);
target.keyReleased(anyKey);

verify(action, times(1)).actionActivate();
verify(action, times(1)).actionDeactivated();
verifyNoMoreInteractions(action);
}

@Test
public void keyPressAndChangeActionShouldAbortFirstAction() {
target.setCurrentAction(actionReference);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ This file is part of Universal Gcode Sender (UGS).
*/
package com.willwinder.ugs.nbp.lib.services;

import static com.willwinder.ugs.nbp.lib.services.ShortcutService.createShortcut;
import org.apache.commons.lang3.StringUtils;
import org.openide.cookies.InstanceCookie;
import org.openide.filesystems.FileObject;
Expand All @@ -26,7 +27,7 @@ This file is part of Universal Gcode Sender (UGS).
import org.openide.util.Exceptions;
import org.openide.util.lookup.ServiceProvider;

import javax.swing.*;
import javax.swing.Action;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -143,12 +144,7 @@ public void registerAction(String id, String name, String category, String short
// Add/Update Shortcut //
/////////////////////////
if (shortcut != null && shortcut.length() > 0) {
in = FileUtil.createFolder(root, "Shortcuts");
obj = in.getFileObject(shortcut, SHADOW);
if (obj == null) {
obj = in.createData(shortcut, SHADOW);
obj.setAttribute("originalFile", originalFile);
}
createShortcut(id, category, shortcut);
}

invalidateCache();
Expand Down Expand Up @@ -241,7 +237,7 @@ public Optional<ActionReference> lookupAction(String category, String name) {
* Get actions organized by category.
*/
public Map<String, List<ActionReference>> getCategoryActions() {
if(actionCache.isEmpty()) {
if (actionCache.isEmpty()) {
FileObject rootFileObject = FileUtil.getConfigFile("Actions/");
actionCache = getCategoryActions(rootFileObject);
}
Expand Down Expand Up @@ -344,6 +340,7 @@ private void invalidateCache() {

/**
* Returns all actions by the given category
*
* @param category the name of the category to fetch
* @return a list of actions
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ This file is part of Universal Gcode Sender (UGS).
*/
package com.willwinder.ugs.nbp.lib.services;

import org.apache.commons.io.IOUtils;
import org.openide.filesystems.FileAttributeEvent;
import org.openide.filesystems.FileChangeListener;
import org.openide.filesystems.FileEvent;
Expand All @@ -30,10 +31,14 @@ This file is part of Universal Gcode Sender (UGS).
import org.openide.util.lookup.ServiceProvider;

import javax.swing.KeyStroke;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
Expand All @@ -51,12 +56,7 @@ public class ShortcutService implements FileChangeListener {
/**
* Cache the found shortcuts to speed things up using the shortcut as key and the actionId as value.
*/
private final Map<String, String> shortcutMap = new ConcurrentHashMap<>();

/**
* The current keymap used
*/
private String currentKeymap = "NetBeans";
public static final Map<String, String> shortcutMap = new ConcurrentHashMap<>();

public ShortcutService() {
reloadShortcuts();
Expand All @@ -81,17 +81,19 @@ public void fileFolderCreated(FileEvent fileEvent) {

@Override
public void fileDataCreated(FileEvent fileEvent) {
if (!fileEvent.getFile().getPath().startsWith(getKeymapConfigRoot())) {
String currentKeymap = getCurrentKeymap();
String keymapConfigRoot = "Keymaps/" + currentKeymap;
if (!fileEvent.getFile().getPath().startsWith(keymapConfigRoot)) {
return;
}

DataFolder folder = DataFolder.findFolder(FileUtil.getSystemConfigFile(getKeymapConfigRoot()));
DataFolder folder = DataFolder.findFolder(FileUtil.getSystemConfigFile(keymapConfigRoot));
String keyAsString = fileEvent.getFile().getName();
Collections.list(folder.children()).stream()
.filter(DataShadow.class::isInstance).map(DataShadow.class::cast)
.filter(f -> f.getName().equals(keyAsString))
.findFirst()
.ifPresent(ShortcutService.this::setShortcut);
.ifPresent(ShortcutService::setShortcut);
}

@Override
Expand All @@ -101,6 +103,7 @@ public void fileChanged(FileEvent fileEvent) {

@Override
public void fileDeleted(FileEvent fileEvent) {
String currentKeymap = getCurrentKeymap();
if (!fileEvent.getFile().getPath().startsWith("Keymaps/" + currentKeymap + "/")) {
return;
}
Expand All @@ -123,30 +126,63 @@ public void fileAttributeChanged(FileAttributeEvent fileAttributeEvent) {
reloadShortcuts();
}

private String getKeymapConfigRoot() {
return "Keymaps/" + currentKeymap;
}

private void setShortcut(DataShadow file) {
private static void setShortcut(DataShadow file) {
InstanceDataObject cookie = file.getCookie(InstanceDataObject.class);
String actionId = cookie.getPrimaryFile().getPath();
shortcutMap.put(file.getName(), actionId);
LOGGER.fine(() -> String.format("Set shortcut: %s -> %s", file.getName(), actionId));
}

private void reloadShortcuts() {
FileObject keymaps = FileUtil.getConfigFile("Keymaps");
if (keymaps == null || keymaps.getAttribute("currentKeymap") == null) {
return;
}

currentKeymap = keymaps.getAttribute("currentKeymap").toString();
private static void reloadShortcuts() {
String currentKeymap = getCurrentKeymap();
LOGGER.fine(() -> String.format("Reloading shortcuts using keymap %s", currentKeymap));

shortcutMap.clear();
DataFolder folder = DataFolder.findFolder(FileUtil.getSystemConfigFile(getKeymapConfigRoot()));
DataFolder folder = DataFolder.findFolder(FileUtil.getSystemConfigFile("Keymaps/" + currentKeymap));
Collections.list(folder.children()).stream()
.filter(DataShadow.class::isInstance).map(DataShadow.class::cast)
.forEach(this::setShortcut);
.forEach(ShortcutService::setShortcut);
}

public static void createShortcut(String id, String category, String shortcut) throws IOException {
String currentKeymap = getCurrentKeymap();
FileObject root = FileUtil.getConfigRoot();
FileObject keyMapsFolder = root.getFileObject("Keymaps");
if (keyMapsFolder == null) {
keyMapsFolder = FileUtil.createFolder(root, "Keymaps");
}

FileObject keyMapsNetBeansFolder = keyMapsFolder.getFileObject(currentKeymap);
if (keyMapsNetBeansFolder == null) {
keyMapsNetBeansFolder = keyMapsFolder.createFolder(currentKeymap);
}

FileObject shortcutFile = keyMapsNetBeansFolder.getFileObject(shortcut, "shadow");
if (shortcutFile == null) {
shortcutFile = keyMapsNetBeansFolder.createData(shortcut, "shadow");
OutputStream outputStream = shortcutFile.getOutputStream();
IOUtils.write("nbfs://nbhost/SystemFileSystem/Actions/" + category + "/" + id + ".instance", outputStream, Charset.defaultCharset());
outputStream.close();
}
}

private static String getCurrentKeymap() {
try {
FileObject keymaps = FileUtil.getConfigFile("Keymaps");
if (keymaps == null) {
FileObject root = FileUtil.getConfigRoot();
keymaps = FileUtil.createFolder(root, "Keymaps");
}

if (keymaps.getAttribute("currentKeymap") == null) {
keymaps.setAttribute("currentKeymap", "NetBeans");
}

return keymaps.getAttribute("currentKeymap").toString();
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Could get keymaps folder", e);
return "NetBeans";
}
}
}

0 comments on commit 0117e56

Please sign in to comment.