In this tutorial, we will look at controlling Max actions using two common controllers – your computer's mouse and keyboard. We will also see how to convert numbers into letters, and identify particular keystrokes.
It is not always convenient – or even useful – to use external hardware for controlling Max patches. Sometimes the computer itself contains all of the control mechanisms that you need to work with your patches. Working with the mouse and keyboard can give us extensive control of our patches without having to worry about any other devices.
Take a look at the patcher 08mKeyboardAndMouseInput, which will be our example patch for this tutorial. At the left side of the window is a small patch that connects a metro
object to two new Max objects labeled mousestate
. Click on the checkbox to turn on the metro
, then move your mouse around the screen. You will notice that the number
boxes connected to the mousestate
object report information as your mouse moves, and that the connected checkbox is turned on whenever you click the mouse button.
The output of the mousestate
object provides button-status and cursor-position information about the mouse/cursor when the cursor is positioned within a Max patcher window. It provides a value stating whether the mouse button is "clicked" as well as two sets of coordinates: absolute mouse position on the x and y axis, and a delta position showing the movement since that last time the mousestate
was polled. The absolute position is based on screen coordinates, not
coordinates within the patcher window, so you can track movement anywhere on your computer screen. It also means that the results of mousestate
will vary depending on the size of your computer screen real estate. Screen coordinates on the computer are reverse-cartesian
, which is to say that the upper-left hand coordinate of your screen will be , , and the lower-right coordinate will be the size of your screen minus 1 (e.g. a 1024x768 display will give you the coordinates , when the mouse is at the bottom-right edge).
The delta value reports changes in mouse position – but when are changes actually reported? The change (as well as the absolute position) are only reported when a metro
object to generate messages. This is called polling
, and allows you to control the density of messages that are created by an object. This is especially important in the case of an object like mousestate
, where massive streams of unwanted data could be generated if it acted automatically. The only output that does not require active polling is the mouse button notification (the left outlet of the object).
message is received in the object’s inlet – hence, the use of the
Adjacent to the mousestate
object is the modifiers
object. This will track (from left-to-right) the shift and caps-lock keys on your keyboard, as well as the Cmd, Control and Option keys on a Macintosh system or the Alt, right-hand mouse keys or Ctrl keys on a Windows system. All of these outputs require polling as well, but are a great way to capture the state of the modifier keys as special cases within your patch.
The next three small patches demonstrate capturing key presses on your computer keyboard. Unlike mouse messages, keystrokes produce output only when pressed and released, so there is no need to use polling to reduce message density. In the leftmost patch, the key
object is used to get the ASCII value of a key when it is pressed. That output is sent to a number
box (to display the value), then passed to an itoa
object – which translates that integer value into an alphanumeric symbol. This is sent to the Max window (via a print
object), where you can see the letter of the pressed key. Try typing your name and watching the Max window; notice that the integers coming out of the key
object are correctly converted to their corresponding symbol. Keys that generate non-printing
characters, e.g. the return key (ASCII ) and the tab key (ASCII ) generate the correct numerical values from the key
object, but print a single blank line in the Max window.
Just to the right is another small patch that uses the keyup
object. This is almost identical to the key
object, except that it doesn’t report any key information until the key is released. This is useful for situations where you want an action to only occur while a key is being pressed; you could turn the action on when you receive a message from key
, then turn it off when you get a message from keyup
The next small patch feeds the output of a key
object to an object called numkey
. This is a very convenient object that allows you to work with numeric keyboard input in the integer domain. Start by typing in a few numbers – you will see them being accumulated into a number from the right-hand outlet. If you hit the return
key, you will see that the number is reported as an integer from the left outlet. This means that the numkey
object is performing all of the accumulation and translation of keyboard values into a numeric outlet. Note that this patch is limited to integer output; if you want a floating point output, you would need to add a floating-point argument (like 0.0) to the numkey
object to tell it to respect the decimal point and report floating-point output.
Finally, the right-most patch shows an object called mousefilter
in action. When we click and drag the upper slider
, we see that no output is generated until the mouse button is released. This is another convenience object that can be used to limit the generation of unwanted intermediate data. In this case, you may not want to perform any action until the movement of the slider
is complete. By funneling the slider
object's output through mousefilter
, all output is suppressed until the mouse button is released.
Let's use some of these objects and techniques to create a patch that works "intelligently" based on keyboard and mouse activity. Create two metro
objects with arguments of , and connect button
objects to their outlets – these will be our test subjects. Using the left-most patch as a starting point, connect the left-most outlet of mousestate
(which reports the mouse button state) to the left inlet of the two metro
objects. Lock the patch and verify that pressing the mouse button turns on the metro
objects, and releasing them causes the metro
objects to stop.
Next, let’s track the horizontal mouse position using a slider
. Add a slider
to the patch, and connect it to the second outlet of mousestate
. In order to have this make sense, we will need to change the range of the slider
. Use the message (or use the Object Inspector) to change the maximum range of the slider to the width of your screen in pixels – this will be something like , , or (depending on the resolution of your screen). Now, if you turn on the metro
object polling the mousestate
, you should see the slider move in tandem with horizontal movements of your mouse.
Let's use this value to control the output speed of the two metro
objects. Connect the outlet of the slider to the right inlet of the first metro
you created. Now, as you move the mouse (with the button held down), you will see the speed of the first metro
change based on the mouse's current position. Let's also use the slider to control the second metro
object's speed, but scaled using a math operator. Add a object to the patch with an argument of , and connect it between the slider
and the second metro
object’s right inlet. Now, as you move the mouse (and press the mouse button), you will see that the second metro
takes twice as long to fire as the first, but both are being controlled by the mouse position.
Finally, lets use the keyboard to change the scale of that numkey
object's left outlet (the one that only reports values after the return key is hit), we can connect it to the right inlet of the *
object. Now, we can change the scaling of the second metro
by entering in a number using the number keys – and do so without having to click on the number
box to make the change. You can test this by entering a number (try for example), hitting return, then testing the mouse click function. You should see the metro
objects respond to the current mouse position.
object. Using the output of the
This tutorial shows how the computer itself can be used as a controller for your Max patch. Rather than depending solely on user interface elements, you can query the mouse and keyboard directly, and use the resultant values to alter the actions of your work.
Convert integers to ASCII characters
Report key presses on the computer keyboard
Report key releases on the computer keyboard
Report modifier key presses on the computer keyboard
Report the status and location of the mouse
Pass numbers only when the mouse button is up
Interpret numbers typed on the computer keyboard