#### <sup>[Ollin](../../index.md) → [Documentation](../index.md) → [Helpers](index.md) → `Input`</sup>

---

## Input

Pointer and keyboard input are plain properties and overridable methods on the sketch.

### Contents

- [mouseX / mouseY](#mouse)
- [mouse / previousMouse](#mousePoint)
- [mouseIsPressed](#mouseIsPressed)
- [mousePressed / mouseReleased](#mousePressed)
- [pressure / pressureIsAvailable](#pressure)
- [stylus](#stylus)
- [scrollDeltaY / mouseScrolled](#scroll)
- [pinchScale / turnAngle / fingersPinched / fingersTurned](#pinch): two fingers on the trackpad
- [key / keyCode / keyIsPressed](#key)
- [keyPressed / keyReleased](#keyPressed)
- [isKeyDown](#isKeyDown)
- [moveAxis](#moveAxis)
- [typedText / textTyped / composingText](#typed-text): text the way a text field receives it
- [droppedFiles / filesDropped](#droppedFiles)
- [chooseFiles / chosenFiles / filesChosen](#chooseFiles): a file picked through the open panel
- [pointerShape / hidePointer / showPointer](#pointer): the pointer over the canvas
- [Keyboard focus in the hosts](#keyboardFocus)

<a name="mouse"></a>

### mouseX / mouseY

```swift
mouseX: Double
mouseY: Double
```

The cursor position in sketch coordinates (points, top-left origin, y-down). When the window opens, both values start from the cursor's actual position. So a mouse-driven sketch responds on the first frame instead of reading (0, 0) until the first move. After that they follow the pointer as it moves over the canvas.

```swift
override func draw() {
    background(.white)
    fill(.black)
    drawCircle(mouseX, mouseY, 24)   // a dot follows the cursor
}
```

Two calls remap the mouse into their own coordinates. One is [`withViewBox`](../drawing/drawing.md#viewbox), which does it for the length of its block. The other is [`viewControl`](../drawing/drawing.md#viewcontrol), which does it for the rest of the frame. The remap keeps a sketch written for the whole canvas working when the view is not the whole canvas. In both cases, `mouseX` and `mouseY` give the position in the content under the pointer, not the position on the screen. The pointer values are restored before the next frame.

<a name="mousePoint"></a>

### mouse / previousMouse

```swift
mouse: Vector2
previousMouse: Vector2
```

`mouse` is the same cursor position as one point. The geometry calls take a point directly, so you can pass it without unpacking it. `previousMouse` is where the cursor was when the previous frame drew.

```swift
drawLine(previousMouse, mouse)          // ink follows the pointer
let speed = (mouse - previousMouse).length
if circle.contains(mouse) { … }
```

`mouse - previousMouse` is this frame's drag, so you do not need to track the motion yourself. On the first frame `previousMouse` equals `mouse`, so the first delta is zero rather than a jump from the corner. `previousMouse` holds the canvas-space position the window reported. The coordinate remaps above apply to `mouse` for their frame, so they never change `previousMouse`.

<a name="mouseIsPressed"></a>

### mouseIsPressed

```swift
mouseIsPressed: Bool
```

Whether a mouse button is currently held over the canvas. It is the polling counterpart to the one-shot hooks below, and it works the same way as `keyIsPressed`. Poll it in `draw()` for anything that should continue while the button is down, such as dragging, painting, or steering. `mouseX`/`mouseY` keep updating through the drag.

```swift
override func draw() {
    if mouseIsPressed {
        drawCircle(mouseX, mouseY, 12)   // paint while the button is down
    }
}
```

<a name="mousePressed"></a>

### mousePressed / mouseReleased

```swift
mousePressed()
mouseReleased()
```

Override these to respond to a click. Each fires once per press or release, and `mouseX`/`mouseY` hold the event's location. Use `mousePressed()` to regenerate an otherwise static sketch on demand. Use `mouseReleased()` to act on a finished drag or stroke. The `DigitReader` example classifies its drawing in `mouseReleased()`.

```swift
override func mousePressed() {
    randomSeed(frameCount)   // re-roll the randomness on each click
}
```

<a name="pressure"></a>

### pressure / pressureIsAvailable

```swift
pressure: Double            // 0...1, 0 when nothing is held
pressureIsAvailable: Bool   // whether this device can measure it at all
```

How hard the pointer is pressed. On a pressure-sensing device (a Force Touch trackpad, a pen tablet) the value varies continuously through a press. On a device that cannot measure pressure the value is `1` while a button is down. A pressure-driven sketch still works there, but only at that single level.

`pressureIsAvailable` tells you which kind of device you have. The answer comes from the event, not from the machine, so it is `false` until the first press. Read it in `mousePressed()` rather than in `setup()`:

```swift
override func mousePressed() {
    brush = pressureIsAvailable ? .pressure(light: 0.1) : .speed(fast: 0.15)
}
```

Ollin asks the trackpad for the drawing gesture, which is a single stage over the full range. A press therefore reads as a smooth amount, and no force-click fires look-up in the middle of a stroke. See [Marks](../drawing/marks.md) for the brush that reads pressure.

<a name="stylus"></a>

### stylus

```swift
stylus.tilt: Vector2            // how far it leans, -1...1 each axis, .zero upright
stylus.twist: Double            // how far the barrel is turned, radians, 0..<2π
stylus.isEraser: Bool           // the end on the tablet is the eraser
stylus.isNearby: Bool           // a stylus is over the tablet, hovering or drawing
stylus.tiltIsAvailable: Bool    // whether a lean has ever been reported
```

What a tablet says about the stylus beyond where it is and how hard it is pressed. How hard is [`pressure`](#pressure) rather than a member here, since a trackpad measures that too and no trackpad has a lean.

`tilt` is the pen leaning away from upright: `x` positive when the top of the pen leans right, `y` positive when it leans down the canvas, and the vector's length is how far from upright it is, near 1 when the pen is nearly flat. It is what a broad-edged nib is made of, since a chisel laid across the lean draws thick one way and thin the other:

```swift
let angle = stylus.tiltIsAvailable ? atan2(stylus.tilt.y, stylus.tilt.x) + .pi / 2 : .pi / 4
```

`twist` moves only on an art pen. `isEraser` is the end being used, which a stylus reports by arriving as a different pointing device when it is turned over. `isNearby` covers hovering as well as drawing, so a cursor can be shown under a pen that has not touched down yet.

`tiltIsAvailable` is the same kind of answer `pressureIsAvailable` is: it comes from the events rather than from the machine, so it is false until a pen has been used, and it latches on once one has, since a stylus lifted out of range would otherwise take the pen path away in the middle of a stroke. Everything else is zero and false under a mouse, so a sketch written for a stylus still runs there.

A stylus's values are recorded into a [take](../output/recording.md) and replayed with the rest of the input. See [Marks](../drawing/marks.md) for the brush that reads a press, and `Examples/Input/Pen` for a nib that reads the lean.

<a name="scroll"></a>

### scrollDeltaY / mouseScrolled

```swift
scrollDeltaY: Double   // how far the wheel moved this frame, 0 when it did not
mouseScrolled()        // fires once per wheel event
```

How far the scroll wheel, or two fingers scrolling on a trackpad, moved this frame. Every movement since the last frame is added in, so none is lost between frames. Positive is a scroll up. Inside `mouseScrolled()` the value is that one event's movement, and by the next `draw()` it is the whole frame's.

```swift
var zoom = 1.0

override func draw() {
    zoom *= pow(1.02, scrollDeltaY)
}
```

[`viewControl`](../drawing/drawing.md#viewcontrol) and [`cameraControl`](../3d/camera.md) zoom with the wheel already.

<a name="pinch"></a>

### pinchScale / turnAngle / fingersPinched / fingersTurned

```swift
pinchScale: Double   // how much two fingers changed the size this frame, 1 when still
turnAngle: Double    // how far two fingers turned this frame, radians, 0 when still
fingersPinched()     // fires once per pinch event
fingersTurned()      // fires once per turn event
```

Two fingers on the trackpad. `pinchScale` is a factor: `1.1` when the fingers spread a tenth farther apart this frame, `0.9` as they close, `1` while nothing pinches. Every pinch since the last frame is multiplied in, so multiplying a size by it follows the fingers exactly. `turnAngle` is the turn in radians, positive clockwise on the screen, which is the way [`rotate`](../drawing/drawing.md#rotate) turns a positive angle. So adding it to an angle and rotating by that keeps a shape under the fingers:

```swift
var size = 300.0
var spin = 0.0

override func draw() {
    size *= pinchScale
    spin += turnAngle
    translate(width / 2, height / 2)
    rotate(spin)
    drawRect(Rectangle(center: .zero, width: size, height: size))
}
```

Both are this frame's change, the way `mouse - previousMouse` is, so the sketch keeps the totals itself. The hooks fire once per event, and inside them the value is that one event's change. Use them for a response that comes in steps, such as a dial that clicks every fifteen degrees:

```swift
var notch = 0.0
var petals = 7

override func fingersTurned() {
    notch += turnAngle
    if notch >= .pi / 12 { notch -= .pi / 12; petals += 1 }
}
```

[`viewControl`](../drawing/drawing.md#viewcontrol) zooms with a pinch about the pointer, and [`cameraControl`](../3d/camera.md) dollies with one: spreading the fingers to twice the distance brings the camera to half its distance. When the phone shows the sketch ([`PhoneDevice.show`](../tools/onthephone.md)), two fingers on its screen pinch and turn the sketch the same way. A mouse has no pinch, so `pinchScale` stays `1` and `turnAngle` stays `0` under one.

A pinch and a turn are recorded into a [take](../output/recording.md) and replayed with the rest of the input. A performance that zoomed and turned then renders offline the way it was played. `Examples/Input/PinchAndTurn` sizes and spins a rose and clicks its petal count with the turn.

<a name="key"></a>

### key / keyCode / keyIsPressed

```swift
key: Character?
keyCode: KeyCode?
keyIsPressed: Bool
```

The most recent key event, split into two properties. A key that produces a character arrives as `key`, so a letter, a digit, punctuation, or the space bar reads as `"a"`, `"5"`, or `" "`. A key with no useful character arrives as `keyCode` instead, so you match a named value rather than a magic number. That means an arrow or a function key reads as `.leftArrow`, `.return`, `.escape`, or `.function(1)`. Exactly one of the two is set for a given event, and the other is `nil`. Both are set on press *and* release, so the hooks below can read which key fired.

`keyIsPressed` is `true` whenever any key is held.

```swift
override func draw() {
    background(.white)
    if key == "r" { background(.red) }        // a character key
    if keyCode == .leftArrow { /* … */ }      // a named key
}
```

The named keys are `upArrow` / `downArrow` / `leftArrow` / `rightArrow`, `return`, `enter`, `tab`, `escape`, `delete`, `forwardDelete`, `home` / `end` / `pageUp` / `pageDown`, and `function(_:)`. `return` is the main Return key, and `enter` is the keypad one. `delete` is Backspace, and `F1` is `.function(1)`.

<a name="keyPressed"></a>

### keyPressed / keyReleased

```swift
keyPressed()
keyReleased()
```

Override these to respond to keys. Each fires once per physical press or release, and auto-repeat does not fire `keyPressed()` again. `key`/`keyCode` hold the key that fired. The hooks are for discrete actions, so for a continuous response while a key is *held* (steering, movement), poll `isKeyDown(_:)` in `draw()` instead.

```swift
override func keyPressed() {
    if key == " " { paused.toggle() }       // space toggles
    if keyCode == .escape { reset() }
}
```

<a name="isKeyDown"></a>

### isKeyDown

```swift
isKeyDown(_ character: Character) -> Bool
isKeyDown(_ code: KeyCode) -> Bool
```

Whether a specific key is currently held. It is the polling counterpart to the one-shot `keyPressed()` hook, for movement that should continue while a key is down. Call it from `draw()`.

```swift
override func draw() {
    if isKeyDown(.leftArrow)  || isKeyDown("a") { x -= speed }
    if isKeyDown(.rightArrow) || isKeyDown("d") { x += speed }
}
```

The character form is case-sensitive, so `isKeyDown("w")` and `isKeyDown("W")` differ by whether Shift was down at the press.

<a name="moveAxis"></a>

### moveAxis

```swift
moveAxis: Vector2
```

The held movement keys (WASD and the arrows) as one direction. Each axis is in `-1...1`, in canvas orientation, so up is `(0, -1)` and right is `(1, 0)`. Opposite keys held together cancel to zero.

```swift
position += moveAxis * speed * deltaTime
```

A 3D sketch reads the same value and maps y onto its own forward direction. The usual choice is for canvas up to mean "ahead", so `-moveAxis.y` is the throttle.

<a name="typed-text"></a>

### typedText / textTyped / composingText

```swift
typedText() -> String
textTyped()
composingText: String
caretPosition: Vector2?
```

The keyboard read as text, the way a text field receives it. `key` reports the keys themselves, so Option-E then E is two presses of `e`. `typedText()` reports what those presses typed once the system's input methods composed them: one "é". A character picked in the emoji viewer (Control-Command-Space) arrives as itself. Chinese or Japanese typed through an input method arrives once a candidate is chosen. Holding a key repeats it, as it does in a text field, even though `keyPressed()` fires once per press.

`typedText()` returns the text typed since the last call, oldest first, and reading it empties it. `textTyped()` is called each time text arrives, so a sketch can take it there or read it in `draw()`, whichever it prefers. Return arrives as `"\n"` and Tab as `"\t"`. Delete arrives as a backspace character, `"\u{8}"`, which `append(typing:)` reads as taking the last character away:

```swift
var caption = ""

override func draw() {
    background(.white)
    caption.append(typing: typedText())
    fill(.black)
    textSize(64)
    drawText(caption + composingText, 60, 200)
}
```

While an input method is still composing, `composingText` holds the reading it shows: the underlined hiragana before a kanji is picked, or the accent a dead key holds until the next key. It is empty the rest of the time. Draw it after the typed text, in a color or with an underline of its own, the way a text field does. Once the input method confirms, the text arrives through `typedText()` and `composingText` empties. Set `caretPosition` to the bottom of the line being typed, in canvas coordinates. The input method then opens its list of candidates just below it. Left `nil`, the list opens below the pointer.

Text reaches the sketch while its canvas holds the keyboard (see [Keyboard focus in the hosts](#keyboardFocus)). Losing the keyboard drops a composition half written, as a text field does. A take records typed text and compositions, and a replay repeats them. A headless export types nothing. `Examples/Input/TypedText` puts what you type on the canvas and shows the last key beside the last text it typed.

<a name="droppedFiles"></a>

### droppedFiles / filesDropped

```swift
droppedFiles() -> [String]
filesDropped()
```

Files dropped on the window from the Finder. `droppedFiles()` returns the paths dropped since the last call, oldest first, and reading them empties the list. `filesDropped()` is called once at each drop, after the paths have arrived and with `mouseX`/`mouseY` at the drop point, so a sketch can respond there or poll in `draw()`, whichever it prefers. Anything the Finder can hand over arrives: a picture for `loadImage`, a clip, a font, a table. A drop is live input outside a take, neither recorded nor replayed.

```swift
override func filesDropped() {
    for path in droppedFiles() {
        if let picture = try? loadImage(path) { pictures.append((picture, mouse)) }
    }
}
```

Every host takes the drop wherever the sketch is running: the live window, the gallery, and the performance stage with its code hidden. With the code showing, the editor over the stage takes the drop as text instead.

<a name="chooseFiles"></a>

### chooseFiles / chosenFiles / filesChosen

```swift
chooseFiles(withExtensions extensions: [String] = [], allowsMultiple: Bool = false)
chosenFiles() -> [String]
filesChosen()
```

Files the person picks through the system's open panel, for a sketch that asks for a picture or a table instead of waiting for a drop. `chooseFiles` shows the panel over the sketch's window as a sheet and returns at once, so the frames keep coming while it is open. When the panel closes on a pick, the paths join `chosenFiles()` as `String` paths, oldest first, and `filesChosen()` fires once. Reading `chosenFiles()` empties the list, as `droppedFiles()` does. A panel closed without a pick adds nothing and fires nothing.

`extensions` limits what the panel offers, written without the dot (`"png"`, `"csv"`) and in any case; empty, the default, offers every file. An extension the system has no type for still matches files by name. `allowsMultiple` lets the person pick several at once. While a panel is open, a second call does nothing.

```swift
var photo: Image?

override func keyPressed() {
    if key == "o" { chooseFiles(withExtensions: ["png", "jpg", "heic"]) }
}

override func filesChosen() {
    for path in chosenFiles() { photo = (try? loadImage(path)) ?? photo }
    redraw()   // a still sketch shows the new picture
}
```

A pick is live input outside a take, like a drop: neither recorded nor replayed. The panel is a Mac window; on a phone or a tablet, and in an export, the call does nothing.

<a name="pointer"></a>

### pointerShape / hidePointer / showPointer

```swift
pointerShape(_ shape: PointerShape)
hidePointer()
showPointer()
```

The pointer over the canvas. `pointerShape` gives it one of the system's shapes. `hidePointer()` takes it away, for a sketch that draws its own (a brush outline, a reticle) at `mouse`. Both hold until changed, and both apply only over the canvas. The rest of the window, and a host's sidebar beside the canvas, keep the ordinary arrow.

The shape and the hiding are kept apart. A shape set while the pointer is hidden is the one `showPointer()` brings back. So a sketch can pick its next shape without showing the pointer early. A call that changes nothing costs one comparison, so a sketch can set the shape in `draw()` every frame from what is under the pointer:

```swift
override func draw() {
    let overDisc = (mouse - center).length < 80
    pointerShape(overDisc ? .openHand : .crosshair)
    drawCircle(center: center, radius: 80)
}
```

`PointerShape` names the system's own cursors: `.arrow` (the default), `.crosshair`, `.pointingHand`, `.openHand`, `.closedHand`, `.iBeam`, `.notAllowed`, `.zoomIn`, `.zoomOut`, `.columnResize`, `.rowResize`, and `.dragCopy`.

An installation that hides the pointer ([`Installation.hidesPointer`](../output/installation.md)) hides it over the whole screen whatever the sketch asks, and the sketch's own hiding never undoes it. On a phone or a tablet there is no pointer, and in an export there is no window; both calls do nothing there.

<a name="keyboardFocus"></a>

### Keyboard focus in the hosts

A window that *is* the sketch gives the sketch the keyboard as soon as it opens. That covers a standalone `swift run` and the live host, so everything above works with no click first. The examples gallery is different. Its example list keeps the keyboard, so the arrow keys navigate the examples. In the gallery, a sketch that reads keys shows a small **"Click the sketch to use the keyboard"** prompt over the canvas. Clicking the sketch gives it the keys, and clicking back in the example list returns them.

When you embed `SketchView` in your own SwiftUI app, the `keyboardFocus:` parameter sets the same policy. `.automatic` is the default, and it claims the keys when the view appears. `.onClick` leaves the keys to the rest of the window until the canvas is clicked. `showsKeyboardHint:` shows that same prompt for sketches that want keys:

```swift
SketchView(sketch, keyboardFocus: .onClick, showsKeyboardHint: true)
```

Typed text follows the keys: whoever holds the keyboard gets the text. On the performance stage the editor holds the keys, so what you type goes into the code, and a click on the canvas hands both to the sketch.
