Saturday, 19 October 2013

User Input

Minecraft retrieves input from the user using two library Classes - Mouse and Keyboard.

This class provides a range of information about mousebutton clicks and cursor movement.  Minecraft vanilla uses a variety of the methods depending on whether the user is in a GUI (eg inventory screen) or is walking around in the world.

Minecraft uses the Keyboard directly for keypresses which can't be re-bound by the user.  For example the function keys, the hotbar slot selection keys 0 .. 8, etc.
  • .isKeyDown for determining whether a key is pressed
  • getEventKey for responding to key pushes (i.e. change of state from "not pressed" to "pressed").
Keyboard contains a table of all the key codes at the front.

KeyBinding (eg GameSettings.keyBindAttack)
Minecraft uses KeyBindings to assign keypresses or mouse clicks to a particular action, for example keyBindAttack can be changed from Left Mouse Button to "m".  (Minecraft uses negative keycodes for mouse buttons: -100 = left, -99 = right, -98 = middle)

KeyBinding provides:
  • .pressed is true if this key is being held down
  • .isPressed() which returns true if the key has been pressed.  It should really be called retrieveKeyPress() or similar:  KeyBinding counts the number of times that user pushes a key, i.e. pressing and holding for 2 seconds still only counts as a single push.  Each time isPressed is called, it decreases this count by one.  (A better name for  .pressTime would be .pressCount, similarly.onTick() would better be called incrementPressCount() ).
 Forge provides a similar functionality using KeyHandler.

The user input from Mouse and Keyboard is processed in three different places:
  1. Minecraft.runTick() handles GUI input, non-bindable keys (eg function keys), and a number of bindable actions such as drop, attack (left mouse button), use item (right mouse button).
  2. EntityClientPlayerSP.onLivingUpdate handles movement input (left, right, forward, back, jump, sneak, etc).
  3. EntityRenderer.updateCameraAndRender() handles movement of the camera (moving the mouse when walking around in-world) using mouseHelper.mouseXYChange();
The diagrams below show these in more detail.

The vanilla code imposes a number of constraints on the way the user input is interpreted, especially the left and right mouse button clicks - for example what happens when the clicks are held down.  It is possible to "intercept" some of the bound keys to gain more control over them, for example see here.  Forge also provides a cancelable event to intercept mouse actions (especially useful for the scroll wheel) - MouseEvent.

User movement is processed in .onLivingUpdate and sent to the server using Packets 10-13, 19, 27

Minecraft.runTick() is responsible for handling most of the user input.

Minecraft.clickMouse handles right- and left- mouse button clicks (the initial click only).  Ongoing effects while holding the left button down are handled by Minecraft.runTick().  Holding the right button down for a non-useable item (eg items which can't be eaten or drunk) causes repeated calls to clickMouse.