Specialized components
Input and interaction system
Input pointer management
19 min
overview input pointer management is the subsystem responsible for tracking and managing individual pointer inputs such as mouse cursors, touch points, and other screen space interaction devices this system enables the engine to handle multiple simultaneous pointers across different rendering contexts, providing essential support for complex user interfaces and multi touch interactions core components the input pointer management system consists of two primary elements inputpointercomponent the inputpointercomponent represents a single, specific pointer input and maintains its current state when attached to an entity, it provides the following key properties property type description pointerid number unique identifier for the specific pointer (e g , mouse = 1, first touch = 2) cameraentity entity reference to the camera entity rendering the canvas this pointer interacts with position vector2 current normalized 2d coordinates ( 1 to +1 range) relative to the associated canvas lastposition vector2 previous frame's position movement vector2 change in position since the last frame // conceptual representation of inputpointercomponent data inputpointercomponent data { pointerid 1, // first pointer (e g , mouse) cameraentity entityidforcamera, // associated camera position { x 0 5, y 0 2 }, // current normalized position lastposition { x 0 48, y 0 21 }, movement { x 0 02, y 0 01 } // movement delta } inputpointerstate the inputpointerstate serves as a central registry for all active pointers in the system it maintains a mapping between pointer identifiers and their corresponding entities, enabling efficient lookup of pointer entities // conceptual representation of inputpointerstate inputpointerstate data { pointers map\<camerapointerhash, entity>(\[ \["canvas 101 pointer 1", entityformouseoncanvas101], \["canvas 202 pointer 1", entityfortouch1oncanvas202], \["canvas 202 pointer 2", entityfortouch2oncanvas202] ]) } the camerapointerhash is a unique string identifier created by combining the camera entity id and the pointer id, providing a consistent way to reference specific pointer instances pointer lifecycle the lifecycle of a pointer in the system follows these stages 1\ creation when a new pointer input is detected (e g , mouse movement on a canvas or a touch event) the canvasinputreactor receives a browser pointer event the system checks if an entity already exists for this camera/pointer combination if not, a new entity is created an inputpointercomponent is attached to this entity 2\ registration once the pointer entity is created the inputpointercomponent reactor automatically runs it creates a camerapointerhash from the cameraentity and pointerid it registers the entity in the inputpointerstate pointers map 3\ updates as the pointer moves or changes state browser events trigger updates to the inputpointercomponent the system updates position , calculates movement , and stores lastposition these updates flow through to any systems or components using the pointer data 4\ removal when a pointer is no longer active (e g , touch end or mouse leave) the inputpointercomponent may be removed from its entity the reactor's cleanup function removes the entry from inputpointerstate pointers the pointer entity may be destroyed or recycled sequencediagram participant user participant browser participant reactor as canvasinputreactor participant entity as pointer entity participant ipc as inputpointercomponent participant ips as inputpointerstate user >>browser initiates pointer input browser >>reactor pointer event reactor >>ips check for existing pointer alt new pointer reactor >>entity create new entity reactor >>ipc attach component ipc >>ips register in pointer map else existing pointer reactor >>entity get existing entity reactor >>ipc update properties end user >>browser moves pointer browser >>reactor pointer move event reactor >>ipc update position & calculate movement user >>browser ends pointer input browser >>reactor pointer up/leave event reactor >>ipc remove component ipc >>ips unregister from pointer map technical implementation inputpointerstate definition // simplified from components/inputpointercomponent ts export const inputpointerstate = definestate({ name 'inputpointerstate', initial() { return { pointers new map\<camerapointerhash, entity>() }; } }); // helper function to create the unique hash key function createcamerapointerhash(camera entity, pointer number) camerapointerhash { return `canvas ${camera} pointer ${pointer}` as camerapointerhash; } inputpointercomponent definition // simplified from components/inputpointercomponent ts export const inputpointercomponent = definecomponent({ name 'inputpointercomponent', schema { pointerid s number({ default 1 }), position t vec2(), lastposition t vec2(), movement t vec2(), cameraentity s entity() }, // reactor to maintain inputpointerstate reactor () => { const entity = useentitycontext(); const comp = usecomponent(entity, inputpointercomponent); useimmediateeffect(() => { const pid = comp pointerid value; const cament = comp cameraentity value; const hash = createcamerapointerhash(cament, pid); getstate(inputpointerstate) pointers set(hash, entity); return () => { getstate(inputpointerstate) pointers delete(hash); }; }, \[comp pointerid, comp cameraentity]); return null; } }); canvasinputreactor implementation // simplified from functions/clientinputhooks tsx function handlepointerevent(event pointerevent, cameraentity entity) { // get existing pointer entity or create a new one const pointerentity = inputpointercomponent getpointerbyid(cameraentity, event pointerid) || createentity(); // ensure it has an inputsourcecomponent setcomponent(pointerentity, inputsourcecomponent, { sourceentity cameraentity }); // calculate normalized coordinates const normalizedx = (event clientx / canvaswidth) 2 1; const normalizedy = (event clienty / canvasheight) 2 + 1; // update the inputpointercomponent setcomponent(pointerentity, inputpointercomponent, { pointerid event pointerid, cameraentity cameraentity, position new vector2(normalizedx, normalizedy) // lastposition and movement are handled internally }); } practical usage accessing a specific pointer // get a pointer entity by camera and pointer id const pointerentity = inputpointercomponent getpointerbyid(cameraentity, pointerid); if (pointerentity !== undefinedentity) { const pointerdata = getcomponent(pointerentity, inputpointercomponent); // access pointer properties const position = pointerdata position; const movement = pointerdata movement; // use position for ui placement or interaction logic } tracking all pointers for a camera // in a react component or system const activepointers = inputpointercomponent usepointersforcamera(cameraentity); // process all active pointers for (const pointerentity of activepointers) { const pointerdata = getcomponent(pointerentity, inputpointercomponent); // render cursor or handle interaction for each pointer drawcursor(pointerdata position x, pointerdata position y); } integration with other systems the input pointer management system integrates with several other components of the engine input sources pointer entities typically have both inputpointercomponent and inputsourcecomponent raycasting pointer positions are used to create rays for 3d interaction ui systems ui components use pointer data for hover states, drag operations, and click handling multi touch gestures multiple pointers can be tracked simultaneously for pinch, rotate, and other gestures conclusion the input pointer management system provides a robust framework for handling diverse pointer inputs across multiple rendering contexts by maintaining a clear separation between physical pointer devices and their logical representation in the engine, this system enables support for multiple simultaneous pointers (essential for multi touch) association of pointers with specific cameras and canvases normalized 2d coordinates for consistent ui interaction efficient lookup of pointer entities for event handling this completes our exploration of the ir engine's input and interaction system throughout this documentation, we've covered how raw device inputs are captured by input sources how these inputs are standardized into button and axis states how game entities listen for and respond to inputs how the input system coordinates the overall process how the engine determines which entities are being targeted how individual pointers are managed across different contexts with this comprehensive understanding, developers can create sophisticated, responsive, and intuitive interactions in their ir engine applications