package org.geogebra.desktop.gui; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import javax.swing.text.JTextComponent; import org.geogebra.common.gui.inputfield.AltKeys; import org.geogebra.common.util.StringUtil; import org.geogebra.common.util.debug.Log; import org.geogebra.common.util.lang.Unicode; import org.geogebra.desktop.main.AppD; /* * Michael Borcherds * * Implements KeyListener * adds support for alt-codes (and alt-shift-) for special characters * (ctrl on MacOS) */ public class GeoGebraKeys implements KeyListener { private static StringBuilder altCodes = new StringBuilder(); private boolean altPressed; @Override public void keyPressed(KeyEvent e) { // swallow eg ctrl-a ctrl-b ctrl-p on Mac if (AppD.MAC_OS && e.isControlDown()) { e.consume(); // Application.debug("keyPressed"); } } @Override public void keyTyped(KeyEvent e) { // Application.debug("keyTyped"+e.getKeyChar()); if (AppD.isAltDown(e)) { if (!altPressed) { altCodes.setLength(0); // Application.debug("alt pressed"); } altPressed = true; } else { if (altCodes.length() > 0) { // intercept wrong character and replace with correct Alt-code char insertStr = (char) Integer.parseInt(altCodes.toString()); JTextComponent comp = (JTextComponent) e.getComponent(); int pos = comp.getCaretPosition(); String oldText = comp.getText(); StringBuilder sb = new StringBuilder(); sb.append(oldText.substring(0, pos)); sb.append(insertStr); sb.append(oldText.substring(pos)); comp.setText(sb.toString()); comp.setCaretPosition(pos + 1); e.consume(); } altPressed = false; altCodes.setLength(0); } // we don't want to trap AltGr // as it is used eg for entering {[}] is some locales // NB e.isAltGraphDown() doesn't work if (e.isAltDown() && e.isControlDown()) { return; } } @Override public void keyReleased(KeyEvent e) { // when decimal comma typed on numeric keypad on eg German keyboard, // replace with . if ((e.getKeyCode() == KeyEvent.VK_SEPARATOR || e.getKeyChar() == ',') && e.getKeyLocation() == KeyEvent.KEY_LOCATION_NUMPAD) { Log.warn("replacing decimal , with decimal ."); JTextComponent comp = (JTextComponent) e.getComponent(); int pos = comp.getCaretPosition(); String oldText = comp.getText(); StringBuilder sb = new StringBuilder(); // pos - 1 to remove "," sb.append(oldText.substring(0, pos - 1)); sb.append("."); sb.append(oldText.substring(pos)); comp.setText(sb.toString()); comp.setCaretPosition(pos); e.consume(); } // Application.debug("keyReleased"); // ctrl pressed on Mac // or alt on Windows boolean modifierKeyPressed = AppD.isAltDown(e); if (modifierKeyPressed) { String insertStr = ""; // works nicely for alt or ctrl pressed (Windows/Mac) String keyString = StringUtil .toLowerCase(KeyEvent.getKeyText(e.getKeyCode())); // Application.debug(KeyEvent.getKeyText(e.getKeyCode()).toLowerCase().charAt(0)+""); // Application.debug(e+""); // Application.debug(keyString); // support for alt codes if (e.isAltDown() && e.getKeyLocation() == KeyEvent.KEY_LOCATION_NUMPAD) { char c = e.getKeyChar(); // make sure it's not eg alt-* if (c >= '0' && c <= '9') { altCodes.append(e.getKeyChar()); // Application.debug("alt:"+altCodes); } } boolean numpad = e.getKeyLocation() == KeyEvent.KEY_LOCATION_NUMPAD; // Numeric keypad numbers eg NumPad-8, NumPad * if (!e.isAltDown() && numpad) { keyString = e.getKeyChar() + ""; } Log.debug("Key pressed " + StringUtil.toHexString(e.getKeyChar()) + " " + keyString); // workaround for different Java versions!! if ("minus".equals(keyString)) { keyString = "-"; } else if ("plus".equals(keyString)) { keyString = "+"; } else if ("comma".equals(keyString)) { keyString = ","; } else if ("period".equals(keyString)) { keyString = "."; } else if ("equals".equals(keyString)) { keyString = "="; } else if (keyString.length() > 1) { Log.debug("Unknown keyString: " + keyString); } switch (e.getKeyChar()) { default: // do nothing break; // workaround for shifted characters: // (different in different locales) case '+': case '*': case '=': case '-': case '>': case '<': // Italian keyboard, keyString="unknown keycode: 0x0" for these // two // French keyboard, keyString= eg "2" (so we need to leave it // for Alt-2 to work) case Unicode.eGrave: case Unicode.eAcute: if (keyString.length() > 1) { keyString = e.getKeyChar() + ""; } } // don't want to act on eg "Shift" if (keyString.length() == 1) { insertStr = AltKeys.getAltSymbols( Character.toUpperCase(keyString.charAt(0)), e.isShiftDown(), false); if (insertStr == null) { insertStr = ""; } } // insert into the text component if (!"".equals(insertStr)) { JTextComponent comp = (JTextComponent) e.getComponent(); int pos = comp.getCaretPosition(); // if we have a DynamicTextInputPane then using setText to // insert will destroy any dynamic objects, so use its // insertString method instead. if (comp instanceof DynamicTextInputPane) { ((DynamicTextInputPane) comp).insertString(pos, insertStr, null); } else // all other cases use setText { String oldText = comp.getText(); StringBuilder sb = new StringBuilder(); sb.append(oldText.substring(0, pos)); sb.append(insertStr); sb.append(oldText.substring(pos)); comp.setText(sb.toString()); comp.setCaretPosition(pos + insertStr.length()); } e.consume(); } } } }