Use this file to discover all available pages before exploring further.
Typist is built with a modular architecture that intercepts keyboard events and routes them through state-specific handlers. This page explains how the mod is structured and how events flow through the system.
The main entry point (mod/entrypoint.lua) intercepts all keyboard events and routes them through a priority-based handler chain:
return function(Controller, key) -- Priority 1: Skip if text input is active if G.CONTROLLER and G.CONTROLLER.text_input_hook then -- do nothing -- Priority 2: Global keybindings (run info, options) elseif layout.global_map[key] then layout.global_map[key]() -- Priority 3: Paused menu handler elseif G.SETTINGS.paused then require("typist.mod.state-handlers")[G.STATES.MENU](key) -- Priority 4: Card area with leader key elseif cardarea_handler(area, key, held_keys) then -- handled by card area -- Priority 5: Top area (jokers + consumables) elseif top_area_handler(key) then -- handled by top area -- Priority 6: State-specific handlers elseif state_handlers[G.STATE] and G.GAME.STOP_USE == 0 then state_handlers[G.STATE](key, held_keys) endend
The priority order is crucial: text input blocks everything, global keys override states, and card areas take precedence over state handlers.
State handlers (mod/state-handlers.lua) implement game state-specific keyboard behavior. Each handler is a function that receives the pressed key and currently held keys:
state_handlers[G.STATES.SELECTING_HAND] = function(key, held_keys) -- Handle preview deck if held_keys[layout.preview_deck] then -- Show deck preview end -- Handle free selection elseif layout.free_select_map[key] then G.hand:__typist_toggle_card_by_index(layout.free_select_map[key]) -- Handle play/discard elseif key == layout.proceed then G.FUNCS.play_cards_from_highlighted() endend
Card area handlers (mod/cardarea-handler.lua) provide unified keyboard control for any card collection (hand, jokers, consumables, shop, packs):
return function(area, key, held_keys) local target = layout.free_select_map[key] -- Select card if none selected if target and #area.highlighted == 0 then CardArea.__typist_toggle_card_by_index(area, target) return true end local c = area.highlighted[1] -- Sell card if key == layout.dismiss then if c:can_sell_card() then c:sell_card() end -- Use card elseif key == layout.proceed then G.FUNCS.use_card(e) -- Move card to target position elseif target then tu.list_move_item(area.cards, src_pos, target) end return trueend
Unacorn Card - Drag a card away from boss blind shuffling:
local function unacorn_card(card, held_keys) card.__typist_unacorned = true card.states.drag.is = true -- Event loop to keep card at top of screen Event { func = function() if held_keys[layout.unacorn_card] then card.T.y = 3 -- Keep at top else -- Release card card.__typist_unacorned = nil card.states.drag.is = false end end }end