import { Matrix4, Object3D, Quaternion, Ray, Vector3 } from "three";
import { Context } from "../engine_context.js";
import { IPointerHitEventReceiver } from "../engine_input.js";
import type { ButtonName, IGameObject, Vec3, XRControllerButtonName, XRGestureName } from "../engine_types.js";
import type { NeedleXRHitTestResult, NeedleXRSession } from "./NeedleXRSession.js";
/** true when selectstart was ever received.
 * On VisionOS 1.1 we always have select events (as per the spec), so this is always true
 */
declare type ControllerAxes = "xr-standard-thumbstick" | "xr-standard-touchpad";
declare type StickName = "xr-standard-thumbstick" | "xr-standard-touchpad";
declare type Mapping = "xr-standard";
declare type ComponentType = "button" | "thumbstick" | "squeeze" | "touchpad";
declare type GamepadKey = "button" | "xAxis" | "yAxis";
declare type NeedleXRControllerButtonName = ButtonName | "primary-button" | "primary";
declare type ComponentMap = {
    type: ComponentType;
    rootNodeName?: string;
    gamepadIndices?: {
        [key in GamepadKey]?: number;
    };
    visualResponses?: {
        [key: string]: {
            states: Array<string>;
        };
    };
};
declare type InputDeviceLayout = {
    selectComponentId: string;
    components: {
        [key: string]: ComponentMap;
    };
    mapping: Mapping;
    gamepad: Array<XRControllerButtonName>;
    axes: Array<{
        componentId: ControllerAxes;
        axis: "x-axis" | "y-axis";
    }>;
};
/**
 * A NeedleXRController wraps a connected XRInputDevice that is either a physical controller or a hand
 * You can access specific buttons using `getButton` and `getStick`
 * To get spatial data in rig space (position, rotation) use the `gripPosition`, `gripQuaternion`, `rayPosition` and `rayQuaternion` properties
 * To get spatial data in world space use the `gripWorldPosition`, `gripWorldQuaternion`, `rayWorldPosition` and `rayWorldQuaternion` properties
 * Inputs will also be emitted as pointer events on `this.context.input` - so you can receive controller inputs on objects using the appropriate input events on your components (e.g. `onPointerDown`, `onPointerUp` etc) - use the `pointerType` property to check if the event is from a controller or not
 * @link https://developer.mozilla.org/en-US/docs/Web/API/XRInputSource
 * @category XR
 */
export declare class NeedleXRController implements IPointerHitEventReceiver {
    /** the Needle XR Session */
    readonly xr: NeedleXRSession;
    get context(): Context;
    /**
     * https://developer.mozilla.org/en-US/docs/Web/API/XRInputSource
     */
    readonly inputSource: XRInputSource;
    /** the input source index */
    readonly index: number;
    /** When enabled the controller will create input events in the Needle Engine input system (e.g. when a button is pressed or the controller is moved)
     * You can disable this if you don't want inputs to go through the input system but be aware that this will result in `onPointerDown` component callbacks to not be invoked anymore for this XRController
    */
    emitEvents: boolean;
    /** Is the controller still connected?  */
    get connected(): boolean;
    private _connected;
    get isTracking(): boolean;
    private _isTracking;
    /** the input source gamepad giving raw access to the gamepad values
     * You should usually use the `getButton` and `getStick` methods instead to get access to named buttons and sticks
     */
    get gamepad(): Gamepad | undefined;
    private __gamepad?;
    /** @returns true if this is a hand (otherwise this is a controller) */
    get isHand(): boolean;
    /**
     * If this is a hand then this is the hand info (XRHand)
     * @link https://developer.mozilla.org/en-US/docs/Web/API/XRHand
     */
    get hand(): XRHand | undefined;
    private __hand?;
    /** threejs XRHandSpace, shorthand for `context.renderer.xr.getHand(controllerIndex)`
     * @link https://threejs.org/docs/#api/en/renderers/webxr/WebXRManager.getHand
    */
    get handObject(): import("three").XRHandSpace;
    /** The input source profiles */
    get profiles(): string[];
    /** The device input layout */
    get layout(): InputDeviceLayout | undefined;
    /** shorthand for `inputSource.targetRayMode` */
    get targetRayMode(): (XRTargetRayMode | "transient-pointer");
    /** shorthand for `inputSource.targetRaySpace` */
    get targetRaySpace(): XRSpace;
    /** shorthand for `inputSource.gripSpace` */
    get gripSpace(): XRSpace | undefined;
    /**
     * If the controller if held in the left or right hand (or if it's a left or right hand)
     **/
    get side(): XRHandedness;
    private __side;
    /** is right side. shorthand for `side === 'right'` */
    get isRight(): boolean;
    /** is left side. shorthand for `side === 'left'` */
    get isLeft(): boolean;
    /** is XR stylus, e.g. Logitech MX Ink */
    get isStylus(): boolean;
    /** The XRTransientInputHitTestSource can be used to perform hit tests with the controller ray against the real world.
     * see https://developer.mozilla.org/en-US/docs/Web/API/XRSession/requestHitTestSourceForTransientInput for more information
     * Requires the hit-test feature to be enabled in the XRSession
     *
     * NOTE: The hit test source should be cancelled once it's not needed anymore. Call `cancelHitTestSource` to do this
     */
    getHitTestSource(): XRTransientInputHitTestSource | undefined;
    get hasHitTestSource(): XRTransientInputHitTestSource | undefined;
    /** Make sure to cancel the hittest source once it's not needed anymore */
    cancelHitTestSource(): void;
    private _hitTestSource;
    private _hasSelectEvent;
    get hasSelectEvent(): boolean;
    private _isMxInk;
    private _isMetaQuestTouchController;
    /** Perform a hit test against the XR planes or meshes. shorthand for `xr.getHitTest(controller)`
     * @returns the hit test result (with position and rotation in worldspace) or null if no hit was found
     */
    getHitTest(): NeedleXRHitTestResult | null;
    /** This is cleared at the beginning of each frame */
    private readonly _handJointPoses;
    /** Get the hand joint pose from the current XRFrame. Results are cached for a frame to avoid calling getJointPose multiple times */
    getHandJointPose(joint: XRJointSpace, frame?: XRFrame): XRJointPose | null | undefined;
    /** Grip matrix in grip space */
    private readonly _gripMatrix;
    /** Grip position in grip space */
    private readonly _gripPosition;
    /** Grip rotation in grip space */
    private readonly _gripQuaternion;
    private readonly _linearVelocity;
    private readonly _rayPositionRaw;
    private readonly _rayRotationRaw;
    /** ray matrix in grip space */
    private readonly _rayMatrix;
    /** Ray position in rig space */
    private readonly _rayPosition;
    /** Ray rotation in rig space */
    private readonly _rayQuaternion;
    /** Grip position in rig space */
    get gripPosition(): Vector3;
    /** Grip rotation in rig space */
    get gripQuaternion(): Quaternion;
    get gripMatrix(): Matrix4;
    /** Grip linear velocity in rig space
     * @link https://developer.mozilla.org/en-US/docs/Web/API/XRPose/linearVelocity
     */
    get gripLinearVelocity(): Vector3;
    /** Ray position in rig space */
    get rayPosition(): Vector3;
    /** Ray rotation in rig space */
    get rayQuaternion(): Quaternion;
    /** Controller grip position in worldspace */
    get gripWorldPosition(): Vector3;
    private readonly _gripWorldPosition;
    /** Controller grip rotation in wordspace */
    get gripWorldQuaternion(): Quaternion;
    private readonly _gripWorldQuaternion;
    /** Controller ray position in worldspace (this value is calculated once per frame by default - call `updateRayWorldPosition` to force an update) */
    get rayWorldPosition(): Vector3;
    private readonly _rayWorldPosition;
    /** Recalculates the ray world position */
    updateRayWorldPosition(): void;
    /** Controller ray rotation in wordspace (this value is calculated once per frame by default - call `updateRayWorldQuaternion` to force an update) */
    get rayWorldQuaternion(): Quaternion;
    private readonly _rayWorldQuaternion;
    get pinchPosition(): Vector3;
    private readonly _pinchPosition;
    /** Recalculates the ray world quaternion */
    updateRayWorldQuaternion(): void;
    /** The controller ray in worldspace */
    get ray(): Ray;
    private readonly _ray;
    /** Recalculated once per update */
    private _hand_wristDotUp;
    /**
     * The dot product of the hand palm with the up vector.
     * This is a number between -1 and 1, where 1 means the palm is directly up and -1 means the palm is directly down (upside down).
     * This value is undefined if there's no hand
     */
    get handWristDotUp(): number | undefined;
    /**
     * @returns true if the hand is upside down
     */
    get isHandUpsideDown(): boolean;
    /**
     * @returns true if the hand is upside down and we got a pinch down event this frame.
     */
    get isTeleportGesture(): boolean | undefined;
    /** The controller object space.
     * You can use it to attach objects to the controller.
     * Children will be automatically detached and put into the scene when the controller disconnects
     */
    get object(): IGameObject;
    private readonly _object;
    private readonly _gripSpaceObject?;
    private readonly _raySpaceObject?;
    /** Assigned the model that you use for rendering. This can be used as a hint for other components */
    model: Object3D | null;
    private readonly _debugAxesHelper;
    private readonly _debugGripAxesHelper;
    private readonly _debugRayAxesHelper;
    /** returns the URL of the default controller model */
    getModelUrl(): Promise<string | null>;
    constructor(session: NeedleXRSession, device: XRInputSource, index: number);
    private _hitTestSourcePromise;
    private _requestHitTestSource;
    onPointerHits: (_evt: any) => void;
    onUpdate(frame: XRFrame): void;
    onRenderDebug(): void;
    private onUpdateFrame;
    /** Called when the input source disconnects */
    onDisconnected(): void;
    /**
     * Get a gamepad button
     * @link https://github.com/immersive-web/webxr-gamepads-module/blob/main/gamepads-module-explainer.md
     * @param key the controller button name e.g. x-button
     * @returns the gamepad button if it exists on the controller - otherwise undefined
     */
    getButton(key: NeedleXRControllerButtonName): NeedleGamepadButton | undefined | null;
    /** Get a gesture state */
    getGesture(key: XRGestureName): NeedleGamepadButton | null;
    /**
     * Get the pointer id for a specific button of this input device.
     * This is useful if you want to check if a button (e.g. trigger) is currently being in use which can be queried on the inputsystem.
     * @returns the pointer id for the button or undefined if the button is not supported
     * @example
     * ```ts
     * const pointerId = controller.getPointerId("primary");
     * if (pointerId !== undefined) {
     *     const isUsed = this.context.input.getPointerUsed(pointerId);
     *     console.log(controller.side, "used?", isUsed);
     * }
     * ```
     */
    getPointerId(button: number): number;
    getPointerId(button: NeedleXRControllerButtonName | XRGestureName): number | undefined;
    private readonly _needleGamepadButtons;
    /** combine the InputState information + the GamepadButton information (since GamepadButtons can not be extended) */
    private toNeedleGamepadButton;
    /**
     * Get the values of a controller joystick
     * @link https://github.com/immersive-web/webxr-gamepads-module/blob/main/gamepads-module-explainer.md
     * @returns the stick values where x is left/right, y is up/down and z is the button value
     */
    getStick(key: StickName | "primary"): Vec3;
    private readonly _buttonMap;
    private _motioncontroller?;
    private _layout;
    private getMotionController;
    private initialize;
    /**
     * When enabled the controller will automatically emit pointer down events to the Needle Engine Input System.
     * @default true
     */
    emitPointerDownEvent: boolean;
    /**
     * When enabled the controller will automatically emit pointer up events to the Needle Engine Input System.
     * @default true
     */
    emitPointerUpEvent: boolean;
    /**
     * When enabled the controller will automatically emit pointer move events to the Needle Engine Input System.
     * @default true
     */
    emitPointerMoveEvent: boolean;
    /**
     * The distance threshold for pointer move events. This value is in units in rig space
     * @default 0.03
     */
    pointerMoveDistanceThreshold: number;
    /**
     * The angle threshold for pointer move events. This value is in radians.
     * @default 0.05
     */
    pointerMoveAngleThreshold: number;
    private subscribeEvents;
    private unsubscribeEvents;
    private _selectButtonIndex;
    private _squeezeButtonIndex;
    private onSelectStart;
    private onSelectEnd;
    private onSequeezeStart;
    private onSequeezeEnd;
    /** Index = button index */
    private readonly states;
    private updateInputEvents;
    private _didMoveLastFrame;
    private readonly _lastPointerMovePosition;
    private readonly _lastPointerMoveQuaternion;
    private onUpdateMove;
    /** cached spatial pointer init object. We re-use it to not have */
    private readonly pointerInit;
    private emitPointerEvent;
}
/** Enhanced GamepadButton with `isDown` and `isUp` information */
declare class NeedleGamepadButton {
    /** The index of the button in the input gamepad */
    readonly index: number | undefined;
    readonly name: string;
    touched: boolean;
    pressed: boolean;
    value: number;
    /** was the button just pressed down the last update */
    isDown: boolean;
    /** was the button just released the last update */
    isUp: boolean;
    constructor(index: number | undefined, name: string);
}
export {};
