Seeing that there is some confusion with UI elements, and how to communicate with your composition in realtime, here is a short primer on how to use a keyboard for text input in Vuo. Note that this relies on my ListTools found here for the ability to erase text easily.
With a mission statement of wanting to type to a composition in realtime, see what you are typing, and doing something with each typed element, we can end up with something like this:
Starting off, we need some way to get keyboard input from the running composition. The nodes responsible for this can be found by searching for vuo.keyboard in the sidebar. This presents us with two options, where the main source of input for this application is “Receive Keyboard Typing”. This offers three ways to interpret keyboard data (I guess from a buffer somewhere). Here you can opt for “Typed Line”, “Typed Word” or “Typed Character”. Each of these has its own pros and cons. “Typed Line” and “Typed Word” are similar in the sense that they collect everything you type until you either press return
(line) or space
(word). Neither of these will provide you with realtime feedback on what you are typing though. That’s where “Typed Character” comes in, as it just passes along every button you press on the keyboard. The caveat here is that all key presses including return
and delete
are passed along which means we have to apply some filtering of the input data (@jstrecker; keys like these could possibly be filtered out by default? Or maybe the “Compare Texts” node could include a UTF8-hex mode?).
Knowing that we need to filter out some keys for this composition in the main input node “Receive Keyboard Buttons” comes in to play. This node is usually used for control applications. Here you can specify events from single buttons, or single buttons with modifier keys vastly expanding the amount of options for control of an application from the keyboard. I’m using these here to get back the functionality of pressing enter to end the line/confirm the input, and to get a way to erase text. More on that later.
Before we move on to the filtering, we need to have an idea of how to collect and display all the key presses. As it is a stream of data, the “Enqueue” node comes to mind. This will not only enable us to collect each character, it will also enable us to ignore or delete a character and reset the whole input by adjusting the list length before feeding it to an “Append Texts” node. However, there is one glaring issue with this; it deletes based on the first character we typed not the last. No problem though, as the behaviour is changed by one word in the source code. The aptly named “Queue” node can now be found in my MM.ListTools node set. (@jstrecker; could this behaviour be defined/selected in the “Enqueue” node in the future?).
With that sorted out, we can move on to filtering. Basically we want there to be a bouncer at a gate that opens for our characters and increases the guest list by 1, and blocks the path with an angry stare and crossed arms if it’s something else. In computer we want to have a boolean TRUE if any of our key presses are of characters we want, and a FALSE if it is something else. If we search for “Compare” in the sidebar, we get the node “Compare Texts” which looks like something we should be able to use for this purpose.
Now, if we had to have a comparison node for each character, this would be very tedious and probably more than a bit ineffective. Luckily we can use the “Matches Regex” mode for the bulk of it which makes this a lot easier. For more on regex, see the Wikipedia article. For this operation we will only be interested in using the OR pattern. In regex this is defined by the character | (option
+ 7
). There is a bit of tedium involved in typing a|b|c|… but a lot less than there would be if using separate nodes per character. When we have entered in our alphabet/character set, remembering to include a space for space (| |), we can feed the boolean output to a “Select Input” node. The FALSE option is set to 0, and the TRUE option is set to 1. This is again fed to a counter which is fed to the “Max Item Count” of the “Queue” node. What all of this effectively does is only increasing the size of the queue when there is a desired character, and blocking any expansion of the string if the character isn’t included in the filter. This also means that we can implement deleting of characters with a few easy steps.
Note that using regex disables you from filtering regex operators. This means that if you want to include symbols like !?() they will need their own comparators which can be combined with the regex one using an “Are Any True” node before going to the counter.
Now, to enable erasing of characters, all we have to do is connect the “Pressed” port of a “Receive Keyboard Buttons” node with “Key” set to “Delete” to the “Decrement” port of the “Count” node. To make it update properly, it will also need to trigger the “Add Item” of the “Queue” node and the “Texts” input of the “Append Texts” node. And that’s it for the pure input side of things.
To view the input, add a “Make Text Layer” node, and connect it to the output of the “Append Texts” node.
Next are the nodes to keep and process the previously entered text by pressing return
and to initialize by pressing option
+ return
. To do this add two additional “Receive Keyboard Buttons” nodes. Set one to trigger by pressing return
, and the other to trigger by pressing return
with option
as a modifier key.
Next add a “Hold” node, and a “Spin Off Event” node. Connect the output of the “Append Texts” node to the “Hold” node’s “Value” input, and the return
event to the “Update” port. Connect the “Spin Off Event” node’s “Spun Off” event to the previous “Count” node’s “Set Count” input with a value of 1, and to the “Queue” node’s “Clear List” input. This ensures that you send whatever is in the “Hold” node off to the next step before erasing it from the “Queue” node and resetting the “Count” node.
The output from the “Hold” node is now containing a single instance of VuoText. This can be stored to a table, a tree or a plain file, or as in the following example just be processed directly. Note that this will only keep the data as long as the composition is running.
Employing the same trick as earlier, utilizing a “Count” and an “Enqueue” node enables us to have an arbitrary amount of items in a list, and being able to reset and delete. As this doesn’t implement erasing the last item, the stock node will do. This count node could also be omitted if a fixed count (for tiling for instance) was desired. The count here is increased by pressing return
, and reset by pressing option
+ return
. Note that the option
+ return
event also have to be connected to the “Add Item” input of the “Enqueue” node to trigger the reset through those nodes.
The output from the “Enqueue” node is now a list of VuoText. This can be passed to a “Process List” node where it will create a layer for each item in the list, randomly rotate and displace it, and then output it as a list of layers from the “Process List” “Finished Processing” output. These layers are then combined to one layer, and sent off to rendering.
When this is all done, a quick tip would be scrapping what’s not needed from the example, publish an input for the “Window” ports and an output with the desired text object. Save the composition, move it to the user library, and you will have this as a node to use in your projects without having to set it up again.
There are probably a few things that can be improved in this composition, the counter can for instance go to the negative range if you press delete
enough times, and sometimes you have to hit delete
twice for it to start erasing. It might be me not setting it up right, although I assume this is a 0/1 issue with the list and what event going where first. Anyways, it is text input to a running composition. It has been available for quite some time, and it is more flexible than fixed nodes. Happy typing!
Oh! And get the example composition here!