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

Deactivate continuous jogging when a key is released #2390

Merged
merged 1 commit into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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";
}
}
}