Skip to content

Commit

Permalink
Fix problem with the shortcut service that only read default key mapp…
Browse files Browse the repository at this point in the history
…ings. It will now listen to the key map settings and update a local cache. (#2167)
  • Loading branch information
breiler authored Feb 26, 2023
1 parent b843e8a commit bec3444
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,13 @@ protected void registerListener() {

private String getKeyAsString(KeyEvent e) {
KeyStroke keyStroke = KeyStroke.getKeyStroke(e.getKeyCode(), e.getModifiersEx());
return Utilities.keyToString(keyStroke, false);
return Utilities.keyToString(keyStroke, true);
}

private Optional<ActionReference> getContinuousActionByShortcut(String keyAsString) {
Optional<String> actionId = shortcutService.getActionIdForShortcut(keyAsString);
if (!actionId.isPresent()) {
return Optional.empty();
}

Optional<ActionReference> actionById = actionRegistrationService.getActionById(actionId.get());
return actionById.filter(action -> actionById.get().getAction() instanceof ContinuousAction);
return shortcutService.getActionIdForShortcut(keyAsString)
.flatMap(actionRegistrationService::getActionById)
.filter(action -> action.getAction() instanceof ContinuousAction);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,49 @@ This file is part of Universal Gcode Sender (UGS).
*/
package com.willwinder.ugs.nbp.lib.services;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.apache.commons.lang3.StringUtils;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileAttributeEvent;
import org.openide.filesystems.FileChangeListener;
import org.openide.filesystems.FileEvent;
import org.openide.filesystems.FileRenameEvent;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataFolder;
import org.openide.loaders.DataShadow;
import org.openide.loaders.InstanceDataObject;
import org.openide.util.lookup.ServiceProvider;

import javax.swing.KeyStroke;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;

/**
* A service that can be used to find actions using their shortcut key mapping
* in the format defined in {@link org.openide.util.Utilities#stringToKey(String)}
* in the format defined in {@link org.openide.util.Utilities#keyToString(KeyStroke, boolean)}
* (remember to use portable format)
*
* @author Joacim Breiler
*/
@ServiceProvider(service = ShortcutService.class)
public class ShortcutService {
public class ShortcutService implements FileChangeListener {

private static final Logger LOGGER = Logger.getLogger(ShortcutService.class.getSimpleName());

/**
* Cache the found shortcuts to speed things up using the shortcut as key and the actionId as value.
*/
private final Cache<String, String> shortcutCache = CacheBuilder.newBuilder()
.expireAfterWrite(20, TimeUnit.SECONDS)
.build();
private final Map<String, String> shortcutMap = new ConcurrentHashMap<>();

/**
* The current keymap used
*/
private String currentKeymap;

public ShortcutService() {
reloadShortcuts();
FileUtil.getSystemConfigRoot().addRecursiveListener(this);
}

/**
* Finds a shortcut in format defined in {@link org.openide.util.Utilities#stringToKey(String)}
Expand All @@ -51,19 +69,78 @@ public class ShortcutService {
* @return a shortcut reference
*/
public Optional<String> getActionIdForShortcut(String keyAsString) {
String actionId = shortcutCache.getIfPresent(keyAsString);
if (StringUtils.isNotEmpty(actionId)) {
return Optional.of(actionId);
return Optional.ofNullable(shortcutMap.get(keyAsString));
}


@Override
public void fileFolderCreated(FileEvent fileEvent) {
// Not used
}

@Override
public void fileDataCreated(FileEvent fileEvent) {
if (!fileEvent.getFile().getPath().startsWith(getKeymapConfigRoot())) {
return;
}

DataFolder folder = DataFolder.findFolder(FileUtil.getSystemConfigFile(getKeymapConfigRoot()));
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);
}

@Override
public void fileChanged(FileEvent fileEvent) {
fileDataCreated(fileEvent);
}

@Override
public void fileDeleted(FileEvent fileEvent) {
if (!fileEvent.getFile().getPath().startsWith("Keymaps/" + currentKeymap + "/")) {
return;
}

FileObject rootFileObject = FileUtil.getConfigFile("Shortcuts/" + keyAsString + ".shadow");
if (rootFileObject == null) {
return Optional.empty();
shortcutMap.remove(fileEvent.getFile().getName());
LOGGER.fine(() -> String.format("Removed shortcut: %s", fileEvent.getFile().getName()));
}

@Override
public void fileRenamed(FileRenameEvent fileRenameEvent) {
// Not used
}

@Override
public void fileAttributeChanged(FileAttributeEvent fileAttributeEvent) {
if (!fileAttributeEvent.getFile().getPath().equals("Keymaps") && fileAttributeEvent.getName().equals("currentKeymap")) {
return;
}

String name = rootFileObject.getName();
actionId = rootFileObject.getAttribute("originalFile").toString();
shortcutCache.put(name, actionId);
return Optional.of(actionId);
reloadShortcuts();
}

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

private 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() {
currentKeymap = FileUtil.getConfigFile("Keymaps").getAttribute("currentKeymap").toString();
LOGGER.fine(() -> String.format("Reloading shortcuts using keymap %s", currentKeymap));

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

0 comments on commit bec3444

Please sign in to comment.