/** Eliminate redundant modifier keys surrounding keystrokes or keystrings. */ private void removeExtraModifiers() { setStatus("Removing extra modifiers"); for (int i = 0; i < steps.size(); i++) { Step step = (Step) steps.get(i); if (isKey(step, ANY_KEY, PRESS)) { Event se = (Event) step; String cs = se.getAttribute(XMLConstants.TAG_KEYCODE); int code = AWT.getKeyCode(cs); boolean remove = false; boolean foundKeyStroke = false; if (AWT.isModifier(code)) { for (int j = i + 1; j < steps.size(); j++) { Step next = (Step) steps.get(j); if (isKey(next, cs, RELEASE)) { if (foundKeyStroke) { steps.remove(j); remove = true; } break; } else if (isKeyStroke(next, ANY_KEY) || isKeyString(next)) { foundKeyStroke = true; remove = true; } else if (!isKey(next, ANY_KEY, EITHER)) { break; } } } if (remove) { steps.remove(i--); } } } }
private boolean isKey(Step step, String code, int type) { boolean match = false; if (step instanceof Event) { Event se = (Event) step; match = "KeyEvent".equals(se.getType()) && (type == EITHER || (type == PRESS && "KEY_PRESSED".equals(se.getKind())) || (type == RELEASE && "KEY_RELEASED".equals(se.getKind()))) && (code == ANY_KEY || code.equals(se.getAttribute(XMLConstants.TAG_KEYCODE))); } return match; }
/** Eliminate redundant key press/release events surrounding a keytyped event. */ private void coalesceKeyEvents() { setStatus("Coalescing key events"); for (int i = 0; i < steps.size(); i++) { Step step = (Step) steps.get(i); if (isKey(step, ANY_KEY, PRESS)) { // In the case of modifiers, remove only if the presence of // the key down/up is redundant. Event se = (Event) step; String cs = se.getAttribute(XMLConstants.TAG_KEYCODE); int code = AWT.getKeyCode(cs); // OSX option modifier should be ignored, since it is used to // generate input method events. boolean isOSXOption = Platform.isOSX() && code == KeyEvent.VK_ALT; if (AWT.isModifier(code) && !isOSXOption) continue; // In the case of non-modifier keys, walk the steps until we // find the key release, then optionally replace the key press // with a keystroke, or remove it if the keystroke was already // recorded. This sorts out jumbled key press/release events. boolean foundKeyStroke = false; boolean foundRelease = false; for (int j = i + 1; j < steps.size(); j++) { Step next = (Step) steps.get(j); // If we find the release, remove it and this if (isKey(next, cs, RELEASE)) { foundRelease = true; String target = ((Event) next).getComponentID(); steps.remove(j); steps.remove(i); // Add a keystroke only if we didn't find any key // input between press and release (except on OSX, // where the option key generates input method events // which aren't recorded). if (!foundKeyStroke && !isOSXOption) { String mods = se.getAttribute(XMLConstants.TAG_MODIFIERS); String[] args = (mods == null || "0".equals(mods) ? new String[] {target, cs} : new String[] {target, cs, mods}); Step typed = new Action(getResolver(), null, "actionKeyStroke", args); steps.add(i, typed); setStatus("Insert artifical " + typed); } else { setStatus("Removed redundant key events (" + cs + ")"); --i; } break; } else if (isKeyStroke(next, ANY_KEY) || isKeyString(next)) { foundKeyStroke = true; // If it's a numpad keycode, use the numpad // keycode instead of the resulting numeric character // keystroke. if (cs.startsWith("VK_NUMPAD")) { foundKeyStroke = false; steps.remove(j--); } } } // We don't like standalone key presses if (!foundRelease) { setStatus("Removed extraneous key press (" + cs + ")"); steps.remove(i--); } } } }