/** 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--);
        }
      }
    }
  }