DatumHueEnterprise v0.0.24datumhue.com
Contents

namespaceInput37 functions, 2 propertiesUI apps only

datumhue.input

Focus-scoped keyboard, mouse, touch, gamepad readers and cursor control. Touch is a separate device from the mouse: a screen touch never presses a mouse button, so the touch readers and the mouse button readers can be polled side by side without double-counting a tap.

Returns handles
Subscription, Vec2

Fields 2

FieldTypeAccessDescription
last_sourceinput.InputSourceread-onlyRead-only. The device that produced the most recent input. Within one frame a gamepad wins over touch, touch over the mouse and the mouse over the keyboard. Cursor motion while a touch is held is the touch's, not the mouse's (a finger can move the cursor).
last_gamepadinteger?read-onlyRead-only. The id, as gamepads numbers it, of the pad in the player's hands: the connected pad that last pressed a button or pushed a stick past a 0.25 deadzone, else the first connected pad. A stick counts as it crosses the deadzone after coming back within 0.125 of centre, so a stick held out, wavering at the deadzone or already out when its pad connects does not move the name. When pads speak in the same frame, the pad already named keeps the name, else the lowest id takes it. Nil while no pad is connected.

Functions 37

datumhue.input.on_text

functionUI apps only
datumhue.input.on_text(callback: function) -> Subscription

Subscribe callback to text-producing keystrokes on the focused app; it receives the layout-resolved text (Shift / keyboard layout applied, OS auto-repeat included). Returns a subscription; call :unsubscribe() to stop. Special keys (backspace, enter, arrows) come through is_key_pressed/on_key.

Example
local typed = ""
-- Text as the keyboard layout writes it, Shift applied.
local sub = datumhue.input.on_text(function(text)
    typed = typed .. text
end)
-- sub:unsubscribe() stops it.

datumhue.input.on_key

functionUI apps only
datumhue.input.on_key(callback: function) -> Subscription

Subscribe callback to key press and release on the focused app; it receives the physical key name (an input.Key) and whether the key is now pressed. Returns a subscription; call :unsubscribe() to stop.

Example
-- Keys are named by where they sit, whatever the layout.
datumhue.input.on_key(function(key, pressed)
    if key == "escape" and pressed then
        print("escape pressed")
    end
end)

datumhue.input.on_button

functionUI apps only
datumhue.input.on_button(callback: fun(button: input.GamepadButton, pressed: boolean, pad_id: integer)) -> Subscription

Subscribe callback to gamepad button press and release on the focused app, from every connected pad; pad_id numbers the pad as gamepads does. A pad has no key repeat: a held button is heard once going down and once coming up, and a pad that disconnects releases the buttons held on it under the id it had. An analog trigger is pressed and released at the travel is_button_pressed reads. The buttons focus navigation acts on (A, B, X, the D-pad and the triggers) are heard too, as on_key hears the keys it acts on; the keys and requests they stand for never reach on_key. Returns a subscription; call :unsubscribe() to stop.

datumhue.input.bind_action

functionUI apps only
datumhue.input.bind_action(name: string, options: input.ActionBindOptions)

Bind a named action to keys / mouse buttons / gamepad buttons / any screen touch; replaces any existing binding. Query it with is_action_down / is_action_pressed / is_action_released. Lets controls be remapped without rewriting input checks.

Example
datumhue.input.bind_action("jump", {
    keys = { "space", "w" },
    gamepad_buttons = { "south" },
    touch = true,
})
datumhue.on_update(function(dt)
    if datumhue.input.is_action_pressed("jump") then
        print("jump")
    end
end)

options input.ActionBindOptions options 4 keys

KeyTypeDefaultDescription
keysinput.Key[]no key triggers itKeys that trigger the action.
mouse_buttons"left" | "right" | "middle" | "back" | "forward"[]no mouse button triggers itMouse buttons that trigger the action.
gamepad_buttonsinput.GamepadButton[]no gamepad button triggers itGamepad buttons (on any connected pad) that trigger the action.
touchbooleanfalseWhen true, any screen touch triggers the action.

datumhue.input.unbind_action

functionUI apps only
datumhue.input.unbind_action(name: string)

Remove a named action binding (idempotent).

datumhue.input.action_label

functionUI apps only
datumhue.input.action_label(action: string, source?: input.InputSource) -> string?

The words a prompt shows for the input bound to action on source: a key's label in the player's keyboard layout, named as the platform's keycaps print it (Option on a Mac, Alt elsewhere), a pad button's name in the family of the pad last_gamepad names, a mouse button's name, or the text, else the accessible label, of the first shown touch button that presses the action. Labels resolve in the app's locale. Without source, the device input.last_source names, a mouse read as the keyboard. Nil when the action has no binding on that device.

Example
local saved = datumhue.storage.open():get("jump_key"):ready().value
local key = saved and saved:text() or "space" -- kept from a past run
datumhue.input.bind_action("jump", { keys = { key } })
print(datumhue.input.action_label("jump", "keyboard")) --> Space
local capture -- the next key pressed takes "jump"
capture = datumhue.input.on_key(function(new_key, pressed)
    if pressed then
        capture:unsubscribe()
        datumhue.input.bind_action("jump", { keys = { new_key } })
        datumhue.storage.open():set("jump_key", datumhue.bytes(new_key))
    end
end)

datumhue.input.is_action_down

functionUI apps only
datumhue.input.is_action_down(name: string) -> boolean

Whether any input bound to the named action is currently held, or a touch button of your app that holds it (UiElement:touch_button), bound or not.

datumhue.input.is_action_pressed

functionUI apps only
datumhue.input.is_action_pressed(name: string) -> boolean

Whether any input bound to the named action, or a touch button of your app that holds it, was pressed since the app's previous update tick. Each press reads true in exactly one tick, and none is lost when a tick spans several frames.

datumhue.input.is_action_released

functionUI apps only
datumhue.input.is_action_released(name: string) -> boolean

Whether any input bound to the named action, or a touch button of your app that holds it, was released since the app's previous update tick. Each release reads true in exactly one tick, and none is lost when a tick spans several frames.

datumhue.input.action_vector

functionUI apps only
datumhue.input.action_vector(negative_x: string, positive_x: string, negative_y: string, positive_y: string) -> number, number

Compose a 2D movement vector and return its x and y components: each of the four named actions contributes one unit on its axis while held, the pad last_gamepad names adds its left stick (past a 0.25 deadzone) and d-pad, each touch stick of your app a touch holds adds its stick past the same deadzone, and the result is clamped to length 1. Screen convention — y grows downward, so positive_y is toward the bottom of the screen and stick/d-pad up pulls toward negative_y. Unbound action names contribute nothing.

Example
local keys = { left = "a", right = "d", up = "w", down = "s" }
for action, key in pairs(keys) do
    datumhue.input.bind_action(action, { keys = { key } })
end
-- Hold "s" for a frame: y grows downward.
datumhue.debug.input.key("s", true)
datumhue.time.wait_frames(1)
local x, y = datumhue.input.action_vector("left", "right", "up", "down")
print(x, y) --> 0.0 1.0
datumhue.debug.input.key("s", false)

datumhue.input.is_key_down

functionUI apps only
datumhue.input.is_key_down(key: input.Key) -> boolean

Whether a key is currently held.

datumhue.input.is_key_pressed

functionUI apps only
datumhue.input.is_key_pressed(key: input.Key) -> boolean

Whether a key was pressed since the app's previous update tick. Each press reads true in exactly one tick, and none is lost when a tick spans several frames.

datumhue.input.is_key_released

functionUI apps only
datumhue.input.is_key_released(key: input.Key) -> boolean

Whether a key was released since the app's previous update tick. Each release reads true in exactly one tick, and none is lost when a tick spans several frames.

datumhue.input.mouse_position

functionUI apps only
datumhue.input.mouse_position() -> Vec2?

Cursor position in window logical pixels from the window's top-left, or nil. Not scaled by the zoom: for positions to compare with your UI, use app_mouse_position.

datumhue.input.app_mouse_position

functionUI apps only
datumhue.input.app_mouse_position() -> Vec2?

Cursor position in UI px from the top-left of your app's content area, the frame UiElement.bounds uses, at every zoom and stretch mode. Nil off the window and before your UI's first layout.

datumhue.input.mouse_delta

functionUI apps only
datumhue.input.mouse_delta() -> Vec2

Mouse movement since last frame.

datumhue.input.is_mouse_down

functionUI apps only
datumhue.input.is_mouse_down(button: input.MouseButton) -> boolean

Whether a mouse button is held.

datumhue.input.is_mouse_pressed

functionUI apps only
datumhue.input.is_mouse_pressed(button: input.MouseButton) -> boolean

Whether a mouse button was pressed since the app's previous update tick. Each press reads true in exactly one tick, and none is lost when a tick spans several frames.

datumhue.input.is_mouse_released

functionUI apps only
datumhue.input.is_mouse_released(button: input.MouseButton) -> boolean

Whether a mouse button was released since the app's previous update tick. Each release reads true in exactly one tick, and none is lost when a tick spans several frames.

datumhue.input.scroll_delta

functionUI apps only
datumhue.input.scroll_delta() -> Vec2

Scroll-wheel movement since last frame.

datumhue.input.touches

functionUI apps only
datumhue.input.touches() -> input.Touch[]

Array of the screen touches currently pressed, ordered by id. Empty when nothing touches the screen.

returns input.Touch record 4 keys

KeyTypeDescription
idintegerIdentifier for the touch, stable from press to release. The system may reuse an id after the touch ends.
posVec2Current position in window pixels (same frame as mouse_position).
start_posVec2Position where the touch started, in window pixels.
force?numberPressure of the touch, normalized toward 1; absent when the hardware doesn't report pressure.

datumhue.input.is_touch_down

functionUI apps only
datumhue.input.is_touch_down(id: integer) -> boolean

Whether the touch with this id is currently pressed.

datumhue.input.is_touch_pressed

functionUI apps only
datumhue.input.is_touch_pressed(id: integer) -> boolean

Whether the touch with this id started since the app's previous update tick. Each press reads true in exactly one tick, and none is lost when a tick spans several frames.

datumhue.input.is_touch_released

functionUI apps only
datumhue.input.is_touch_released(id: integer) -> boolean

Whether the touch with this id ended since the app's previous update tick (a touch the system cancels counts as ended). Each release reads true in exactly one tick, and none is lost when a tick spans several frames.

datumhue.input.app_touch_position

functionUI apps only
datumhue.input.app_touch_position(id: integer) -> Vec2?

Position of the touch with this id in UI px from the top-left of your app's content area, the frame app_mouse_position uses. Nil when the touch isn't pressed and before your UI's first layout.

Example
datumhue.on_update(function(dt)
    for _, touch in ipairs(datumhue.input.touches()) do
        -- touch.pos is in window pixels; this is in UI px from the
        -- top-left of the app's content area, the frame
        -- UiElement.bounds uses.
        local at = datumhue.input.app_touch_position(touch.id)
        print(touch.id, at)
    end
end)

datumhue.input.gamepads

functionUI apps only
datumhue.input.gamepads() -> integer[]

Array of connected gamepad ids. An id is the pad's 1-based position in the connected list, not a stable hardware identifier — ids shift when a pad connects or disconnects, so re-enumerate rather than caching them.

datumhue.input.is_button_down

functionUI apps only
datumhue.input.is_button_down(pad_id: integer, button: input.GamepadButton) -> boolean

Whether a gamepad button is held.

datumhue.input.is_button_pressed

functionUI apps only
datumhue.input.is_button_pressed(pad_id: integer, button: input.GamepadButton) -> boolean

Whether a gamepad button was pressed since the app's previous update tick. Each press reads true in exactly one tick, and none is lost when a tick spans several frames.

datumhue.input.is_button_released

functionUI apps only
datumhue.input.is_button_released(pad_id: integer, button: input.GamepadButton) -> boolean

Whether a gamepad button was released since the app's previous update tick. Each release reads true in exactly one tick, and none is lost when a tick spans several frames.

datumhue.input.stick

functionUI apps only
datumhue.input.stick(pad_id: integer, side: input.StickSide) -> Vec2

Gamepad stick vector.

Example
datumhue.on_update(function(dt)
    for _, pad in ipairs(datumhue.input.gamepads()) do
        -- y is up: pushed forward, a stick reads vec2(0, 1).
        local aim = datumhue.input.stick(pad, "right")
        if aim:length() > 0.25 then
            print("aiming at", aim:to_angle())
        end
    end
end)

datumhue.input.dpad

functionUI apps only
datumhue.input.dpad(pad_id: integer) -> Vec2

Gamepad d-pad vector.

datumhue.input.trigger

functionUI apps only
datumhue.input.trigger(pad_id: integer, side: input.StickSide) -> number

Gamepad trigger value 0..1.

datumhue.input.rumble

functionUI apps only
datumhue.input.rumble(pad_id: integer, opts: input.RumbleOptions)

Rumble a gamepad's motors. A pad without motors does nothing. A pad index with no pad connected does nothing.

Example
-- The pad in the player's hands: motor strengths 0..1, duration in
-- seconds.
local pad = datumhue.input.last_gamepad
if pad then
    datumhue.input.rumble(
        pad,
        { strong = 0.8, weak = 0.2, duration = 0.3 }
    )
end

opts input.RumbleOptions options 3 keys

KeyTypeDefaultDescription
strongnumber0Strong (low-frequency) motor intensity, 0..1.
weaknumber0Weak (high-frequency) motor intensity, 0..1.
durationnumber0.1Rumble duration in seconds.

datumhue.input.stop_rumble

functionUI apps only
datumhue.input.stop_rumble(pad_id: integer)

Stop all rumble on a gamepad. A pad index with no pad connected does nothing.

datumhue.input.set_cursor_visible

functionUI apps only
datumhue.input.set_cursor_visible(visible: boolean)

Show or hide the cursor (applies while focused).

datumhue.input.set_cursor_locked

functionUI apps only
datumhue.input.set_cursor_locked(locked: boolean)

Lock or release the cursor (applies while focused).

datumhue.input.set_cursor_icon

functionUI apps only
datumhue.input.set_cursor_icon(icon: input.CursorIcon)

Set the cursor icon by name (applies while focused).

Types 6

input.CursorIcon

enum
ValueDescription
"default"
"pointer"
"crosshair"
"text"
"move"
"grab"
"grabbing"
"not_allowed"
"help"
"wait"
"progress"
"cell"
"copy"
"alias"
"context_menu"
"vertical_text"
"col_resize"
"row_resize"
"n_resize"
"s_resize"
"e_resize"
"w_resize"
"ne_resize"
"nw_resize"
"se_resize"
"sw_resize"
"nesw_resize"
"nwse_resize"
"ew_resize"
"ns_resize"
"zoom_in"
"zoom_out"

Used by: datumhue.input.set_cursor_icon, datumhue.wm.override_cursor_icon

input.GamepadButton

enum
ValueDescription
"south"
"east"
"north"
"west"
"c"
"z"
"left_trigger"
"left_trigger2"
"right_trigger"
"right_trigger2"
"select"
"start"
"mode"
"left_thumb"
"right_thumb"
"dpad_up"
"dpad_down"
"dpad_left"
"dpad_right"

Used by: datumhue.input.on_button, datumhue.input.is_button_down, datumhue.input.is_button_pressed, datumhue.input.is_button_released, datumhue.debug.input.gamepad

Nested in: input.ActionBindOptions, wm.GrabEvent, wm.GrabOptions

input.InputSource

enum
ValueDescription
"keyboard"Flipped by any key press. The initial value before any input arrives.
"mouse"Flipped by a mouse button press, scrolling, or cursor motion while no touch is down.
"gamepad"Flipped by a gamepad button, or a stick pushed past a 0.25 deadzone.
"touch"Flipped by a touch start or move.

Used by: datumhue.input.action_label, datumhue.input.last_source

Nested in: events.InputSource, ui.ContextEvent, ui.DragEvent

input.Key

enum
ValueDescription
"shift"
"control"
"alt"
"super"
"a"
"b"
"c"
"d"
"e"
"f"
"g"
"h"
"i"
"j"
"k"
"l"
"m"
"n"
"o"
"p"
"q"
"r"
"s"
"t"
"u"
"v"
"w"
"x"
"y"
"z"
"0"
"1"
"2"
"3"
"4"
"5"
"6"
"7"
"8"
"9"
"space"
"enter"
"escape"
"backspace"
"tab"
"shift_left"
"shift_right"
"control_left"
"control_right"
"alt_left"
"alt_right"
"arrow_up"
"arrow_down"
"arrow_left"
"arrow_right"
"minus"
"equal"
"bracket_left"
"bracket_right"
"semicolon"
"quote"
"backquote"
"backslash"
"comma"
"period"
"slash"
"delete"
"insert"
"home"
"end"
"page_up"
"page_down"
"f1"
"f2"
"f3"
"f4"
"f5"
"f6"
"f7"
"f8"
"f9"
"f10"
"f11"
"f12"
"context_menu"

Used by: datumhue.input.is_key_down, datumhue.input.is_key_pressed, datumhue.input.is_key_released, datumhue.debug.input.key, datumhue.debug.input.tap

Nested in: input.ActionBindOptions, wm.Chord, wm.GrabEvent

input.MouseButton

enum
ValueDescription
"left"
"right"
"middle"
"back"
"forward"

Used by: datumhue.input.is_mouse_down, datumhue.input.is_mouse_pressed, datumhue.input.is_mouse_released, datumhue.debug.input.click, datumhue.debug.input.mouse_button, PlotArea:on_click

Nested in: chart.BrushOptions, chart.PanZoomOptions, draw.PanZoomOptions, input.ActionBindOptions

input.StickSide

enum
ValueDescription
"left"
"right"

Used by: datumhue.input.stick, datumhue.input.trigger, datumhue.debug.input.gamepad_stick, datumhue.debug.input.gamepad_trigger

datumhue.com

(c) 2026 Shuusei AB. Quote excerpts of this manual, with attribution to DatumHue, in your own documentation, tutorials, course materials, reviews, and other writing or video. Republishing it in whole or in substantial part needs written permission: support@datumhue.com.

Victor Mono is licensed under the SIL Open Font License 1.1
Copyright (c) 2024, Rune Bjørnerås (https://github.com/rubjo)

This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL


-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------

PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.

The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.

DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.

"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).

"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).

"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.

"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.

PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:

1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.

2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.

3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.

4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.

5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.

TERMINATION
This license becomes null and void if any of the above conditions are
not met.

DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Try

    ↑↓ selectEnter openTab filter

    Settings

    Theme
    Text
    Print

    Keyboard shortcuts

    / or Ctrl KSearch
    ↑ ↓ EnterPick a result
    TabNext result filter
    j kNext or previous entry
    [ ]Previous or next page
    yCopy a link to the current entry
    ?These shortcuts
    EscClose

    On this page