call keyEvent before keyPressed

This is how processing handles a keyEvent:

  protected void handleKeyEvent(KeyEvent event) {
    keyEvent = event;
    key = event.getKey();
    keyCode = event.getKeyCode();

    switch (event.getAction()) {
    case KeyEvent.PRESS:
      keyPressed = true;
      keyPressed(keyEvent);
      break;
    case KeyEvent.RELEASE:
      keyPressed = false;
      keyReleased(keyEvent);
      break;
    case KeyEvent.TYPE:
      keyTyped(keyEvent);
      break;
    }

    if (keyEventMethods != null) {
      keyEventMethods.handle(new Object[] { event.getNative() });
    }

    handleMethods("keyEvent", new Object[] { event });

    // if someone else wants to intercept the key, they should
    // set key to zero (or something besides the ESC).
    if (event.getAction() == KeyEvent.PRESS) {
      //if (key == java.awt.event.KeyEvent.VK_ESCAPE) {
      if (key == ESC) {
        exit();
      }
      // When running tethered to the Processing application, respond to
      // Ctrl-W (or Cmd-W) events by closing the sketch. Not enabled when
      // running independently, because this sketch may be one component
      // embedded inside an application that has its own close behavior.
      if (external &&
          event.getKeyCode() == 'W' &&
          ((event.isMetaDown() && platform == MACOSX) ||
           (event.isControlDown() && platform != MACOSX))) {
        // Can't use this native stuff b/c the native event might be NEWT
//      if (external && event.getNative() instanceof java.awt.event.KeyEvent &&
//          ((java.awt.event.KeyEvent) event.getNative()).getModifiers() ==
//            Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() &&
//          event.getKeyCode() == 'W') {
        exit();
      }
    }
  }

This means that if you register a keyEvent it will always be called after keyPressed:

    void setup() {
      registerMethod("keyEvent", this);
    }

    void draw() {}

    void keyEvent(KeyEvent evt) {
      println("keyEvent");
    }

    void keyPressed() {
      println("keyPressed");
    }

I think it would be much better if the keyEvent get's called before keyPressed. This way with a library, the library creator can do things before the user.

So this:

  protected void handleKeyEvent(KeyEvent event) {
    keyEvent = event;
    key = event.getKey();
    keyCode = event.getKeyCode();

    // set booleans so they are correct when a user checks for them in keyEvent
    switch (event.getAction()) {
    case KeyEvent.PRESS:
      keyPressed = true;
      break;
    case KeyEvent.RELEASE:
      keyPressed = false;
      break;
    }

    if (keyEventMethods != null) {
      keyEventMethods.handle(new Object[] { event.getNative() });
    }

    // handle the registered keyEvent's before calling keyPressed() etc.
    handleMethods("keyEvent", new Object[] { event });

    switch (event.getAction()) {
    case KeyEvent.PRESS:
      keyPressed(keyEvent);
      break;
    case KeyEvent.RELEASE:
      keyReleased(keyEvent);
      break;
    case KeyEvent.TYPE:
      keyTyped(keyEvent);
      break;
    }

    // rest of code...

Do more people agree with me?

Comments

  • edited July 2014

    MouseEvent has the order like I think it should be, first registeredMethods, and as last the user.

    protected void handleMouseEvent(MouseEvent event) {
        // http://dev.processing.org/bugs/show_bug.cgi?id=170
        // also prevents mouseExited() on the mac from hosing the mouse
        // position, because x/y are bizarre values on the exit event.
        // see also the id check below.. both of these go together.
        // Not necessary to set mouseX/Y on RELEASE events because the
        // actual position will have been set by a PRESS or DRAG event.
        // However, PRESS events might come without a preceeding move,
        // if the sketch window gains focus on that PRESS.
        final int action = event.getAction();
        if (action == MouseEvent.DRAG ||
            action == MouseEvent.MOVE ||
            action == MouseEvent.PRESS) {
          pmouseX = emouseX;
          pmouseY = emouseY;
          mouseX = event.getX();
          mouseY = event.getY();
        }
    
        // Get the (already processed) button code
        mouseButton = event.getButton();
    
        // Compatibility for older code (these have AWT object params, not P5)
        if (mouseEventMethods != null) {
          // Probably also good to check this, in case anyone tries to call
          // postEvent() with an artificial event they've created.
          if (event.getNative() != null) {
            mouseEventMethods.handle(new Object[] { event.getNative() });
          }
        }
    
        // this used to only be called on mouseMoved and mouseDragged
        // change it back if people run into trouble
        if (firstMouse) {
          pmouseX = mouseX;
          pmouseY = mouseY;
          dmouseX = mouseX;
          dmouseY = mouseY;
          firstMouse = false;
        }
    
        mouseEvent = event;
    
        // Do this up here in case a registered method relies on the
        // boolean for mousePressed.
    
        switch (action) {
        case MouseEvent.PRESS:
          mousePressed = true;
          break;
        case MouseEvent.RELEASE:
          mousePressed = false;
          break;
        }
    
        handleMethods("mouseEvent", new Object[] { event });
    
        switch (action) {
        case MouseEvent.PRESS:
    //      mousePressed = true;
          mousePressed(event);
          break;
        case MouseEvent.RELEASE:
    //      mousePressed = false;
          mouseReleased(event);
          break;
        case MouseEvent.CLICK:
          mouseClicked(event);
          break;
        case MouseEvent.DRAG:
          mouseDragged(event);
          break;
        case MouseEvent.MOVE:
          mouseMoved(event);
          break;
        case MouseEvent.ENTER:
          mouseEntered(event);
          break;
        case MouseEvent.EXIT:
          mouseExited(event);
          break;
        case MouseEvent.WHEEL:
          mouseWheel(event);
          break;
        }
    
        if ((action == MouseEvent.DRAG) ||
            (action == MouseEvent.MOVE)) {
          emouseX = mouseX;
          emouseY = mouseY;
        }
      }
    
  • I don't have a particularly strong opinion. What are the use cases for doing things before the user? Aren't there use cases where the event must be processed after the user?

    In some libraries, we can hook before and after a user event, that allows more flexibility...

  • edited July 2014

    I made a method public boolean keyPressed(char c) { to check if a key is pressed. But if the user get's a keyPressed before the library then it doesn't work.

    I fixed it like this:

     @Override
        protected void handleKeyEvent(KeyEvent event) {
    
            keyCode = event.getKeyCode();
    
    
            if (event.getAction() == KeyEvent.PRESS) {
                keys[keyCode] = true;
            }
            else if (event.getAction() == KeyEvent.RELEASE) {
                keys[keyCode] = false;
            }
    
            super.handleKeyEvent(event);
        }
    

    But this only works if the PApplet get extended by my library.

  • edited July 2014

    Your library behaves more like a 1-man PApplet fork!
    You should have a general plan to focus on rather than trying to alter every detail on it.
    Also, it's not smart to deviate too much from the original, since that's gonna make every re-emerge a daunting task!

  • I have a general plan :) And the remaining stuff I have to do has nothing to do with PApplet.

    Some things might break in future but I don't mind :)

  • I would agree with @PhiLho's comments.

    In my case the current order has not caused any problems with the G4P library when using GTextField and GTextArea objects.

    The only reason I can see for wanting the library to process the keyEvent BEFORE the sketch is if you want to modify the keyEvent object before forwarding it to the sketch.

    It might be helpful if you give us an idea what you are trying to achieve.

  • I want the user to be able to check for multiple keys being pressed at the same time. This already works:

    public void keyPressed() {
    
            // check for multiple keys to be pressed at the same time
            if (keyPressed(CONTROL) && keyPressed('s')) {
                println("save");
            }
    
        }
    

    But to made that work i extended PApplet and used:

    protected void handleKeyEvent(KeyEvent event) {
    
            keyCode = event.getKeyCode();
    
            if (event.getAction() == KeyEvent.PRESS) {
                keys[keyCode] = true;
            }
            else if (event.getAction() == KeyEvent.RELEASE) {
                keys[keyCode] = false;
            }
    
            super.handleKeyEvent(event);
        }
    

    Cause else I would always be one step behind. Makes sense for this to change the order right?

  • edited July 2014

    You're gonna need a boolean[] keys = new boolean[1<<020]; in order to have a full Unicode-16 storage! :-?

  • edited July 2014

    For the function key's or something? Only a few keys on my keyboard produce a high number.

    And if processing would change the order of handling things, that wouldn't hurt right?

  • edited July 2014

    You shouldn't confine your "library" for US keyboards only!
    Japanese, Chinese, Arabic, etc., gonna use full keyCode spectrum!
    If you decide for a subset keyCode range, you gotta make a method which checks the index argument range!
    More complete & easier solution is the full 1<<020 array's length for Unicode-16! :-B

  • Damn, i wish i had a Chinese keyboard :)

    1<<020 it is then.

Sign In or Register to comment.