libx52/vkm/vkm.h

384 lines
11 KiB
C

/*
* Virtual keyboard/mouse interface
*
* Copyright (C) 2026 Nirenjan Krishnan (nirenjan@nirenjan.org)
*
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
*/
/**
* @file vkm.h
* @brief Functions, structures and enumerations for the virtual
* keyboard/mouse interface library (VKM).
*
* This file contains the type, enum and function prototypes for VKM.
* These functions allow an application to inject keyboard/mouse events
* into the host OS, as long as it has the necessary permissions.
*
* @author Nirenjan Krishnan (nirenjan@nirenjan.org)
*/
#ifndef VKM_H
#define VKM_H
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Opaque structure used by the VKM framework
*/
struct vkm_context;
/**
* @brief Virtual device context structure used by the VKM framework
*
* All VKM API functions require the application to pass in a pointer to
* a valid context structure. A pointer can be obtained by calling
* \ref vkm_init
*/
typedef struct vkm_context vkm_context;
/**
* @brief Return type used by VKM API functions
*/
typedef int32_t vkm_result;
/**
* @brief Feature identifiers
*
* These are used to check for platform support of the relevant feature.
*/
typedef enum {
/** Check if mouse is supported on this platform */
VKM_FEAT_MOUSE = (1 << 0),
/** Check if US keyboard is supported on this platform */
VKM_FEAT_KEYBOARD_US = (1 << 1),
/* Additional flags may be added in the future */
} vkm_feature;
/**
* @brief Error code list
*/
typedef enum {
/** No error, indicates success */
VKM_SUCCESS = 0,
/** Unknown error, used as a catch-all error state */
VKM_ERROR_UNKNOWN,
/** Not started, must call vkm_start first */
VKM_ERROR_NOT_READY,
/** Out of memory */
VKM_ERROR_OUT_OF_MEMORY,
/** Invalid parameter(s) */
VKM_ERROR_INVALID_PARAM,
/** Not supported */
VKM_ERROR_NOT_SUPPORTED,
/** Unable to create virtual devices */
VKM_ERROR_DEV_FAILURE,
/** Unable to write event */
VKM_ERROR_EVENT,
/** No state change in the event, please retry */
VKM_ERROR_NO_CHANGE,
/* Maximum error states, do not use in external code*/
VKM_ERROR_MAX,
} vkm_error_code;
/**
* @brief Return a short description for a \ref vkm_result / \ref vkm_error_code value
*
* The returned pointer refers to static storage and must not be freed. For
* unrecognized codes, the same static buffer may be overwritten by a later call.
*
* When native language support (NLS) is enabled at build time, these messages
* are translated like \ref libx52_strerror. Bind the \c libx52 text domain and
* set \c LC_MESSAGES as for other libx52 components.
*
* @param[in] code Value returned from a VKM API function
*
* @returns Pointer to a NUL-terminated description string
*/
const char *vkm_strerror(vkm_result code);
/**
* @brief Option list
*/
typedef enum {
/**
* @brief Set the high resolution scrolling behavior of the mouse
*
* This option must be passed a boolean which lets VKM know whether to
* enable or disable high resolution scrolling.
*
* Defaults to false. When enabled together with \ref vkm_start,
* \ref vkm_mouse_scroll emits high-resolution REL_*_HI_RES events (120 units
* per step) in addition to discrete REL_WHEEL / REL_HWHEEL ticks.
*/
VKM_OPT_HI_RES_SCROLL,
/**
* @brief Enable or disable horizontal scrolling of the mouse
*
* This option must be passed in a boolean which lets VKM know whether to
* enable or disable horizontal scrolling. If horizontal scrolling is
* disabled, then any requests to \ref vkm_mouse_scroll with
* \ref VKM_MOUSE_SCROLL_LEFT or \ref VKM_MOUSE_SCROLL_RIGHT will return
* \ref VKM_ERROR_INVALID_PARAM.
*
* Defaults to false.
*/
VKM_OPT_HORIZONTAL_SCROLL,
/**
* @brief Set the virtual device name in the system.
*
* This option sets the name of the virtual input device in the system.
* If not set, the virtual device will have a name determined by the
* timestamp at which it was initialized.
*
* Only applicable on Linux.
*/
VKM_OPT_DEVICE_NAME,
/* Max number of options, do not use in external code */
VKM_OPT_MAX
} vkm_option;
/**
* @brief Button state
*/
typedef enum {
/** Button is released */
VKM_BUTTON_RELEASED,
/** Button is pressed */
VKM_BUTTON_PRESSED,
/* Max number of button states, do not use in external code */
VKM_BUTTON_STATE_MAX
} vkm_button_state;
/**
* @brief Mouse button identifiers
*/
typedef enum {
/** Mouse left button */
VKM_MOUSE_BTN_LEFT,
/** Mouse right button */
VKM_MOUSE_BTN_RIGHT,
/** Mouse middle button */
VKM_MOUSE_BTN_MIDDLE,
/* Max number of mouse buttons, do not use in external code */
VKM_MOUSE_BTN_MAX
} vkm_mouse_button;
/**
* @brief Scroll directions
*/
typedef enum {
/** Scroll up */
VKM_MOUSE_SCROLL_UP,
/** Scroll down */
VKM_MOUSE_SCROLL_DOWN,
/** Scroll left (horizontal scrolling) */
VKM_MOUSE_SCROLL_LEFT,
/** Scroll right (horizontal scrolling) */
VKM_MOUSE_SCROLL_RIGHT,
/* Maximum number of scroll states, do not use in external code */
VKM_MOUSE_SCROLL_MAX
} vkm_mouse_scroll_direction;
/**
* @brief Initialize the VKM library
*
* This function initializes the VKM library, sets up any internal data
* structures to send input events, and returns a \ref vkm_context pointer
* in the output parameter. All calls to VKM use the returned pointer to
* inject keyboard/mouse events.
*
* @par Example
* @code
* vkm_result rc;
* vkm_context *ctx;
* rc = vkm_init(&ctx);
* if (rc != LIBX52_SUCCESS) {
* // Error handling omitted for brevity
* }
* // Save ctx for use later
* @endcode
*
* @param[out] ctx Pointer to a \ref vkm_context *. This function will
* allocate a context and return the pointer to the context in this variable.
*
* @returns \ref vkm_error_code indicating status
*/
vkm_result vkm_init(vkm_context **ctx);
/**
* @brief Exit the VKM library and free up any resources used
*
* This function releases any resources allocated by \ref vkm_init and
* terminates the library. Using the freed context now is invalid and can
* cause errors
*
* @param[in] ctx Context pointer
*/
void vkm_exit(vkm_context *ctx);
/**
* @brief Start any virtual keyboard/mouse devices on the platform
*
* This must be done before injecting any events, and after setting all
* options through \ref vkm_set_option.
*
* @param[in] ctx Context pointer
*
* @returns
* - \ref VKM_SUCCESS on successful start
* - \ref VKM_ERROR_INVALID_PARAM on bad pointer
* - \ref VKM_ERROR_UNKNOWN on other errors
*/
vkm_result vkm_start(vkm_context *ctx);
/**
* @brief check if VKM is started and ready
*
* @param[in] ctx Context pointer
*
* @returns boolean indicating if ready or not.
*/
bool vkm_is_ready(vkm_context *ctx);
/**
* @brief Check if VKM is supported on this platform
*
* On some platforms, there is no support yet for the virtual keyboard/mouse.
* This function will return a boolean indicating if it is supported or not.
*
* @returns boolean indicating support.
*/
bool vkm_platform_supported(void);
/**
* @brief Check if a particular feature is enabled on this platform
*
* Features may be limited on a per-platform basis.
*
* @param[in] feat Feature identifier
*
* @returns boolean indicating if feature is supported or not.
*/
bool vkm_feature_supported(vkm_feature feat);
/**
* @brief Set an option flag for VKM.
*
* Option flags control the behavior of VKM. All options must be set before
* calling \ref vkm_start.
*
* @param[in] ctx Context pointer
* @param[in] option Which option to set
* @param[in] ... Any required arguments for the specified option
*
* @returns
* - \ref VKM_SUCCESS on success
* - \ref VKM_ERROR_INVALID_PARAM if the option or arguments are invalid
* - \ref VKM_ERROR_NOT_SUPPORTED if the option is valid but not supported on this platform
*/
vkm_result vkm_set_option(vkm_context *ctx, vkm_option option, ...);
/**
* @brief Move the mouse by the specified amount
*
* The move mouse takes in a delta of x and y coordinates that tell the system
* to move the mouse by those relative numbers.
*
* @param[in] ctx Context pointer
* @param[in] dx Delta by which to move the mouse in the horizontal axis
* @param[in] dy Delta by which to move the mouse in the vertical axis
*
* @returns
* - \ref VKM_SUCCESS on successful move
* - \ref VKM_ERROR_UNKNOWN on a generic error
* - \ref VKM_ERROR_NOT_SUPPORTED if the mouse move is not supported on this platform
*/
vkm_result vkm_mouse_move(vkm_context *ctx, int dx, int dy);
/**
* @brief Click the mouse button
*
* Send a mouse button event, this may be either a button down or button up event.
*
* @param[in] ctx Context pointer
* @param[in] button Button identifier
* @param[in] state Button state (press or release)
*
* @returns
* - \ref VKM_SUCCESS on successful move
* - \ref VKM_ERROR_UNKNOWN on a generic error
* - \ref VKM_ERROR_NOT_SUPPORTED if the mouse button click is not supported on this platform
*/
vkm_result vkm_mouse_click(vkm_context *ctx, vkm_mouse_button button, vkm_button_state state);
/**
* @brief Scroll the mouse wheel
*
* Send a single scroll event to the mouse wheel (one detent in the chosen
* direction). If \ref VKM_OPT_HI_RES_SCROLL was enabled before \ref vkm_start,
* also emits REL_WHEEL_HI_RES / REL_HWHEEL_HI_RES using the standard 120
* units per detent scale before the corresponding discrete REL_WHEEL /
* REL_HWHEEL event.
*
* @param[in] ctx Context pointer
* @param[in] dir Scroll direction
*
* @returns
* - \ref VKM_SUCCESS on successful move
* - \ref VKM_ERROR_UNKNOWN on a generic error
* - \ref VKM_ERROR_INVALID_PARAM if horizontal scrolling is not enabled
* and \p dir is \ref VKM_MOUSE_SCROLL_LEFT or \ref VKM_MOUSE_SCROLL_RIGHT
* - \ref VKM_ERROR_NOT_SUPPORTED if the mouse scrolling is not supported on this platform
*/
vkm_result vkm_mouse_scroll(vkm_context *ctx, vkm_mouse_scroll_direction dir);
/**
* @brief Send a sync packet to the OS
*
* On some platforms, a sync packet is necessary for the previously injected
* events to actually get reflected in the system. For platforms where this
* is not needed, this is a noop.
*
* @param[in] ctx Context pointer
*
* @returns
* - \ref VKM_SUCCESS on successful move
* - \ref VKM_ERROR_UNKNOWN on a generic error
* - \ref VKM_ERROR_INVALID_PARAM if parameters are invalid
*/
vkm_result vkm_sync(vkm_context *ctx);
#ifdef __cplusplus
}
#endif
#endif // !defined VKM_H