java - Habilitación de accesos directos de teclas de opción en MATLAB para Mac
swing keyboard-shortcuts (3)
Desde R2009b, MATLAB ha tenido atajos de teclado maravillosamente personalizables a través de sus Preferencias de Atajos de Teclado . Esto funciona muy bien para personalizar accesos directos usando comando y control en una Mac.
Desafortunadamente, esas combinaciones de teclas parecen ser incapaces de anular el mapa de caracteres incorporado de MATLAB. Por ejemplo, si defino option-f como cursor-next-word
(a la emacs), acepta el enlace. Al presionar la combinación de teclas, se mueve correctamente el cursor a la siguiente palabra, ¡pero adicionalmente se imprime el carácter ƒ
! Creo que esto proviene del mapa de caracteres (¿tal vez en oposición al mapa de entrada?). Ni EditorMacro ni KeyBindings pueden anular este comportamiento.
Me encontré con esta respuesta de una pregunta tangencialmente relacionada que me da esperanza. En resumen, definió una clase Java que puede manejar eventos de teclado y reemplazarlos con otra entrada de teclado. La solución, sin embargo, solo funciona según lo prescrito en Windows. Se requieren las siguientes modificaciones para ejecutar en una Mac:
Necesitaba cambiar los códigos de tecla para remapear para ''presionar'' en la cadena, así:
map = {
''$'' ''^''
''#'' char(181) % might be useful for text formatting
};
a:
map = {
''alt pressed F'' ''^''
''alt pressed B'' char(181) % might be useful for text formatting
};
Desafortunadamente, después de ejecutar el código, al presionar option-f se obtiene el cursor-next-word
y el carácter ƒ
, como antes. Sin embargo, si desactivo el enlace de cursor-next-word
de las preferencias, entonces obtengo ambos ƒ
y ^
! De hecho, incluso si utilizo una acción simple como pressed F
, KeyReplacementAction no reemplaza la acción sino que la aumenta . Parece que este comportamiento es exclusivo de MATLAB en OS X.
Parece como si simplemente no estuviera anulando el mapa de teclas correcto. He intentado explorar el tiempo de ejecución de Java, pero no estoy lo suficientemente familiarizado con el modelo de envío de eventos para saber dónde buscar. Tal vez algo dentro del mapa de teclas del sistema operativo de Java?
Editar : Desde entonces, he estado investigando un poco más. Parece como si la versión para Mac de MATLAB no respetara adecuadamente la propiedad ''consumida'' de un evento clave. Puedo adjuntar KeyReplacementAction al mapa de entrada o al inputMap
, y en ambos casos, aumente el enlace en lugar de reemplazarlo. Usé el reflejo para "desproteger" el método de consume()
para AWTEvents, pero el efecto fue el mismo que antes.
Siguiendo el trazado de la pila, parece que el evento keyEvent está cayendo a una instancia de javax.swing.KeyboardManager
. Parece que debería poder desvincular las teclas dentro del KeyboardManager, pero no puedo entender cómo acceder a la instancia desde los controladores de MATLAB que tengo. Quizás alguien más familiarizado con el modelo de eventos de Swing y el depurador de Java podría llegar más lejos.
Editar 2 : la respuesta de flolo me estimuló a mirar los mapas de teclas de X11. Varias notas:
- Matlab no parece respetar
~/.Xmodmap
o cualquier~/.Xmodmap
actualmente cargado. - Matlab utiliza la variable de entorno
$XKEYSYMDB
si existe al inicio. De lo contrario, lo carga desde$MATLAB/X11/app-defaults/XKeysymDB
. - Todo el directorio
$MATLAB/X11/app-defaults/
ve muy interesante; tal vez algunos hackers podrían hacer que esto funcione? - ¿Dónde están los mapas de teclas X11 en una Mac? ¿Cómo cambia MATLAB a diseños de teclado internacionales?
Edición 3 : Hrm, creo que X11 es una pista falsa. lsof -c MATLAB
muestra que está accediendo a /System/Library/Keyboard Layouts/AppleKeyboardLayouts.bundle
. Trabajando en eso ahora ...
Edición 4 : MATLAB sí utiliza el diseño del teclado del sistema. Creé uno sin ningún enlace como sugirió RM . Esto pareció funcionar: MATLAB se comporta correctamente. Desafortunadamente, también rompe mis combinaciones de teclas de Cocoa personalizadas en todos los demás programas. Cerca, pero no cigarro. (Lo suficientemente cerca, de hecho, que RM ganó la recompensa de +500 debido a una breve idea de que funcionó ... hasta que intenté redactar mi comentario de felicitación y descubrí que no podía navegar por el campo de texto como de costumbre).
Como petición, una solución fea: no estoy trabajando en MacOS, así que estoy entrando en el reino de "tal vez un buen consejo": bajo X existen herramientas que pueden capturar eventos X y ejecutar comandos bajo demanda, un Google rápido dio que, por ejemplo, xkbevd también existe bajo MacOS (y supongo que la herramienta java que mencionaste hace algo similar). Ahí podrías atrapar el ctrl-f y reemplazarlo con retroceso ctrl-f, por lo que anulas el carácter adicional. (Muy feo, y rompe esos códigos fuera de matlab).
Otra opción en caso de que no desee cambiar el comportamiento en la línea de comandos, pero solo en el editor: use el editor externo: puede definir en las preferencias otro, diferente del predeterminado. Allí puedes elegir emacs, vi, o lo que sea adecuado para ti (y donde funciona la reasignación)
Por cierto: en Linux, este problema no existe con matlab, por lo que parece que es realmente específico de MacOS.
Finalmente tuve la oportunidad de continuar con esto durante las vacaciones. Y encontré un kludge de una solución. Tenga en cuenta que esto está cambiando dinámicamente las clases de Java utilizadas por la GUI de Matlab en tiempo de ejecución; es completamente sin soporte y es probable que sea muy frágil. Funciona en mi versión de Matlab (r2011a) en OS X Lion.
Esto es lo que aprendí sobre cómo Swing / Matlab procesan eventos de pulsación de teclas:
- Se presiona una tecla.
- Se
inputMap
elinputMap
del componente de texto activo para ver si hay un enlace para esa pulsación de tecla.- Si hay una acción vinculada a esa combinación de teclas,
actionPerformed
métodoactionPerformed
esa acción - Si hay una cadena asociada con esa pulsación de tecla, busque la acción desde
actionMap
del componente deactionMap
y luegoactionPerformed
métodoactionPerformed
esa acciónactionPerformed
- Si hay una acción vinculada a esa combinación de teclas,
-
Keymap.getDefaultAction()
, como último paso, envíe la acción encontrada dentro delKeymap.getDefaultAction()
del componente de texto. Aquí es donde yace el problema.
Esta solución anula la acción predeterminada de Keymap con un contenedor que simplemente verifica si se presionó alguna tecla modificadora. Si lo fueron, la acción se ignora silenciosamente.
Paso 1: Crear una acción de texto personalizada en Java para ignorar las teclas modificadoras
import javax.swing.text.TextAction;
import javax.swing.Action;
import java.awt.event.ActionEvent;
public class IgnoreModifiedKeystrokesAction extends TextAction
{
private static final int ignoredModifiersMask =
ActionEvent.CTRL_MASK | ActionEvent.ALT_MASK;
private Action original;
public IgnoreModifiedKeystrokesAction(Action act)
{
super((String)act.getValue("Name"));
original = act;
}
public void actionPerformed(ActionEvent e)
{
if ((e.getModifiers() & ignoredModifiersMask) == 0) {
/* Only dispatch the original action if no modifiers were used */
original.actionPerformed(e);
}
}
public Action getOriginalAction()
{
return original;
}
}
Compilar a .jar
:
javac IgnoreModifiedKeystrokesAction.java && jar cvf IgnoreModifiedKeystrokesAction.jar IgnoreModifiedKeystrokesAction.class
Paso 2: anule el manejador de mapa de teclas predeterminado de MATLAB tanto en la ventana de comandos como en el editor (desde dentro de MATLAB)
La parte más difícil aquí es obtener los identificadores java en la ventana de comandos y el editor. Depende de la disposición y los nombres de clase de los paneles editor individuales. Esto puede cambiar entre las versiones de Matlab.
javaaddpath(''/path/to/IgnoreModifiedKeystrokesAction.jar'')
cmdwin = getCommandWindow();
editor = getEditor();
for t = [cmdwin,editor]
defaultAction = t.getKeymap().getDefaultAction();
if ~strcmp(defaultAction.class(),''IgnoreModifiedKeystrokesAction'')
newAction = IgnoreModifiedKeystrokesAction(defaultAction);
t.getKeymap().setDefaultAction(newAction);
end
end
%% Subfunctions to retrieve handles to the java text pane elements
function cw = getCommandWindow()
try
cw = handle(com.mathworks.mde.desk.MLDesktop.getInstance.getClient(''Command Window'').getComponent(0).getComponent(0).getComponent(0),''CallbackProperties'');
assert(strcmp(cw.class(),''javahandle_withcallbacks.com.mathworks.mde.cmdwin.XCmdWndView''));
catch %#ok<CTCH>
cw_client = com.mathworks.mde.desk.MLDesktop.getInstance.getClient(''Command Window'');
cw = searchChildComponentsForClass(cw_client,''com.mathworks.mde.cmdwin.XCmdWndView'');
end
if isempty(cw)
error(''Unable to find the Command Window'');
end
end
function ed = getEditor()
try
ed = handle(com.mathworks.mde.desk.MLDesktop.getInstance.getGroupContainer(''Editor'').getComponent(1).getComponent(0).getComponent(0).getComponent(0).getComponent(1).getComponent(0).getComponent(0).getComponent(0).getComponent(0).getComponent(1).getComponent(0).getComponent(0),''CallbackProperties'');
assert(strcmp(ed.class(),''javahandle_withcallbacks.com.mathworks.mde.editor.EditorSyntaxTextPane''));
catch %#ok<CTCH>
ed_group = com.mathworks.mde.desk.MLDesktop.getInstance.getGroupContainer(''Editor'');
ed = searchChildComponentsForClass(ed_group,''com.mathworks.mde.editor.EditorSyntaxTextPane'');
% TODO: When in split pane mode, there are two editor panes. Do I need
% to change actionMaps/inputMaps/Keymaps on both panes?
end
if isempty(ed)
error(''Unable to find the Editor Window'');
end
end
function obj = searchChildComponentsForClass(parent,classname)
% Search Java parent object for a child component with the specified classname
obj = [];
if ~ismethod(parent,''getComponentCount'') || ~ismethod(parent,''getComponent'')
return
end
for i=0:parent.getComponentCount()-1
child = parent.getComponent(i);
if strcmp(child.class(),classname)
obj = child;
else
obj = searchChildComponentsForClass(child,classname);
end
if ~isempty(obj)
obj = handle(obj,''CallbackProperties'');
break
end
end
end
¡Ahora es posible definir combinaciones de teclas en la ventana de preferencias estándar que usa la tecla de opción!
Paso 3 (opcional): elimine la acción personalizada
cmdwin = getCommandWindow();
editor = getEditor();
for t = [cmdwin,editor]
defaultAction = t.getKeymap().getDefaultAction();
if strcmp(defaultAction.class(),''IgnoreModifiedKeystrokesAction'')
oldAction = defaultAction.getOriginalAction();
t.getKeymap().setDefaultAction(oldAction);
end
end
javarmpath(''/path/to/IgnoreModifiedKeystrokesAction.jar'')
No tengo una solución completa, pero tengo algunos enfoques posibles que puedes probar, si aún no los has visto.
Los shorcuts de teclado de MATLAB se guardan en un archivo XML
en /Users/$user/.matlab/$version/$name_keybindings.xml
, donde $user
es su nombre de usuario, $version
la versión de MATLAB y $name
es lo que ha guardado las combinaciones de teclas como. Se ve algo como esto
<?xml version="1.0" encoding="utf-8"?>
<CustomKeySet derivedfrom="Mac" modifieddefault="false">
<Context id="Global">
<Action id="eval-file">
<Stroke alt="on" code="VK_ENTER" meta="on" sysctrl="on"/>
</Action>
<stuff here /stuff>
</Context>
</CustomKeySet>
Traté de cambiar el valor EmptyBaseSet
de EmptyBaseSet
para ver qué pasa. Como era de esperar, ninguno de los accesos directos funciona, pero el carácter Opt
todavía reproducía un carácter Unicode. Esto parece indicar que el comportamiento de acceso directo de Opt-f
o cualquier opción se debe a Mac, y fuera de las manos de MATLAB. Es el equivalente de Windows de presionar las Alt
+ teclado numérico para caracteres Unicode. Si MATLAB sabía acerca de los accesos directos a las opciones, indicaría un posible conflicto en MATLAB>Preferences>Keyboard>Shortcuts
, pero no es así. No sé suficiente XML
para decirle si puede o no desactivar Opt-f
= ƒ
editando este archivo.
Supongo que hay una gran probabilidad de que Apple se haya asegurado de que las aplicaciones no puedan jugar mucho con esta característica, ya que varios idiomas que no son inglés (alemán / eslavo / latino) utilizan estos atajos de teclado muy a menudo.
Una opción alternativa es probar Ukelele , que es un editor de diseño de teclado para Mac. Ha habido preguntas sobre SO y sitios relacionados, donde han usado Ukelele para reasignar claves muertas , otro ejemplo para llaves muertas , configuran el Cmd
izquierdo y derecho de manera diferente , intercambiando € y $ , etc. Puedes intentar redefinir tu diseño de teclado para deshabilite Opt-f
(a menos que necesite ese personaje particular fuera de MATLAB), lo que debería resolver el problema.
Por último, no me refiero a decir "deberías estar haciendo otra cosa" cuando la pregunta es "¿cómo hago esto?", Pero en general, con los Mac, he encontrado asignar Ctrl
a las ventanas / emacs Alt
atajos para ser más fácil que Opt
. Principalmente, por las mismas razones, y también porque Opt
está tan cerca de la tecla Cmd
en mi laptop que mis dedos gordos terminan presionando Cmd
cuando no quiero (nunca sucede al revés).