This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 17025085eadf33906ccb57ccbc95ba8b2c05b4ab Author: Alan Carvalho de Assis <[email protected]> AuthorDate: Wed Aug 12 10:44:07 2026 -0300 arch/sim: Add support to emulated Mouse This commit adds support for three buttons Mouse emulation on SIM. Signed-off-by: Alan C. Assis <[email protected]> Assisted-by: Claude Code --- arch/sim/Kconfig | 15 +++ arch/sim/src/Makefile | 3 + arch/sim/src/sim/CMakeLists.txt | 3 + arch/sim/src/sim/posix/sim_x11eventloop.c | 98 ++++++++++++++ arch/sim/src/sim/sim_initialize.c | 6 +- arch/sim/src/sim/sim_internal.h | 11 +- arch/sim/src/sim/sim_mouse.c | 206 ++++++++++++++++++++++++++++++ 7 files changed, 338 insertions(+), 4 deletions(-) diff --git a/arch/sim/Kconfig b/arch/sim/Kconfig index b1e78e1b60e..70b1f3c88ab 100644 --- a/arch/sim/Kconfig +++ b/arch/sim/Kconfig @@ -570,6 +570,21 @@ config SIM_TOUCHSCREEN ---help--- Support an X11 mouse-based touchscreen emulation. Also needs INPUT=y +config SIM_MOUSE + bool "X11 Mouse Emulation" + select INPUT_MOUSE + depends on SIM_X11FB + ---help--- + Support a full X11 mouse emulation, reporting left/right/middle + button identity and the scroll wheel via /dev/mouseN (struct + mouse_report_s). Unlike SIM_TOUCHSCREEN, which folds every X11 + mouse button into one undifferentiated "pen down" contact + (matching real touchscreen hardware, which has no concept of a + second or third button), this preserves which physical button + was pressed -- needed by any GUI that distinguishes a right-click + context menu or middle-click from an ordinary left click. + Also needs INPUT=y + config SIM_AJOYSTICK bool "X11 mouse-based analog joystick emulation" depends on SIM_X11FB diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile index cc6ad23c184..9a567e5b6c3 100644 --- a/arch/sim/src/Makefile +++ b/arch/sim/src/Makefile @@ -208,6 +208,9 @@ endif ifeq ($(CONFIG_SIM_TOUCHSCREEN),y) CSRCS += sim_touchscreen.c HOSTSRCS += sim_x11eventloop.c +else ifeq ($(CONFIG_SIM_MOUSE),y) + CSRCS += sim_mouse.c + HOSTSRCS += sim_x11eventloop.c else ifeq ($(CONFIG_SIM_AJOYSTICK),y) CSRCS += sim_ajoystick.c HOSTSRCS += sim_x11eventloop.c diff --git a/arch/sim/src/sim/CMakeLists.txt b/arch/sim/src/sim/CMakeLists.txt index cc5f4845e4e..529c978269a 100644 --- a/arch/sim/src/sim/CMakeLists.txt +++ b/arch/sim/src/sim/CMakeLists.txt @@ -220,6 +220,9 @@ if(CONFIG_SIM_X11FB) if(CONFIG_SIM_TOUCHSCREEN) list(APPEND SRCS sim_touchscreen.c) list(APPEND HOSTSRCS sim_x11eventloop.c) + elseif(CONFIG_SIM_MOUSE) + list(APPEND SRCS sim_mouse.c) + list(APPEND HOSTSRCS sim_x11eventloop.c) elseif(CONFIG_SIM_AJOYSTICK) list(APPEND SRCS sim_ajoystick.c) list(APPEND HOSTSRCS sim_x11eventloop.c) diff --git a/arch/sim/src/sim/posix/sim_x11eventloop.c b/arch/sim/src/sim/posix/sim_x11eventloop.c index 15d8cd0ddcf..94553a42a61 100644 --- a/arch/sim/src/sim/posix/sim_x11eventloop.c +++ b/arch/sim/src/sim/posix/sim_x11eventloop.c @@ -91,6 +91,64 @@ static int sim_buttonmap(int state, int button) } #endif +/**************************************************************************** + * Name: sim_mousebuttonmap + * + * Description: + * Same idea as sim_buttonmap() above, but producing a bitmap in + * struct mouse_report_s's MOUSE_BUTTON_1/2/3 numbering (see + * include/nuttx/input/mouse.h) instead of touch_sample_s's single + * undifferentiated "pen down" bit -- the whole point of + * CONFIG_SIM_MOUSE over CONFIG_SIM_TOUCHSCREEN is to keep which + * physical button was pressed. Not including that header here since + * it's the only thing that would pull NuttX input headers into this + * host-compiled (HOSTSRCS) file; the three bit values are hand-rolled + * instead, matching MOUSE_BUTTON_1=1, MOUSE_BUTTON_2=2, MOUSE_BUTTON_3=4. + * + * Note X11's own button numbering has Button2 as the *middle* button + * and Button3 as the *right* button (Button1 is left, same as + * everywhere else) -- MOUSE_BUTTON_2/3 need the opposite assignment + * (right, then middle) to match, so this cannot just reuse + * sim_buttonmap()'s bit positions. + ****************************************************************************/ + +#ifdef CONFIG_SIM_MOUSE +static int sim_mousebuttonmap(int state, int button) +{ + int buttons = 0; + + if ((state & Button1Mask) != 0) + { + buttons |= 1; /* MOUSE_BUTTON_1: left */ + } + + if ((state & Button2Mask) != 0) + { + buttons |= 4; /* MOUSE_BUTTON_3: middle */ + } + + if ((state & Button3Mask) != 0) + { + buttons |= 2; /* MOUSE_BUTTON_2: right */ + } + + switch (button) + { + case Button1: + buttons ^= 1; + break; + case Button2: + buttons ^= 4; + break; + case Button3: + buttons ^= 2; + break; + } + + return buttons; +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -148,6 +206,46 @@ void sim_x11events(void) break; #endif + #ifdef CONFIG_SIM_MOUSE + case MotionNotify : /* Enabled by PointerMotionMask */ + { + sim_mouseevent(event.xmotion.x, event.xmotion.y, + sim_mousebuttonmap(event.xmotion.state, 0), 0); + } + break; + + case ButtonPress : /* Enabled by ButtonPressMask */ + case ButtonRelease: /* Enabled by ButtonReleaseMask */ + { + /* Buttons 4/5 are the traditional X11 scroll-wheel + * encoding: a Press/Release pair fires on every "click" + * of the wheel, with no held state of its own -- report + * the wheel delta on Press only (matching how a real + * mouse_report_s sample is consumed once, not polled as + * persistent state), and pass through the *other* + * buttons' current state unchanged either way. + */ + + int wheel = 0; + + if (event.type == ButtonPress && event.xbutton.button == 4) + { + wheel = 1; + } + else if (event.type == ButtonPress && + event.xbutton.button == 5) + { + wheel = -1; + } + + sim_mouseevent(event.xbutton.x, event.xbutton.y, + sim_mousebuttonmap(event.xbutton.state, + event.xbutton.button), + wheel); + } + break; + #endif + default: break; } diff --git a/arch/sim/src/sim/sim_initialize.c b/arch/sim/src/sim/sim_initialize.c index 94a7aedc794..4b5d7d6cfa9 100644 --- a/arch/sim/src/sim/sim_initialize.c +++ b/arch/sim/src/sim/sim_initialize.c @@ -51,7 +51,7 @@ ****************************************************************************/ #if defined(CONFIG_SIM_TOUCHSCREEN) || defined(CONFIG_SIM_AJOYSTICK) || \ - defined(CONFIG_SIM_BUTTONS) + defined(CONFIG_SIM_BUTTONS) || defined(CONFIG_SIM_MOUSE) static struct work_s g_x11event_work; /* Watchdog for event loop */ #endif @@ -94,7 +94,7 @@ static void sim_init_cmdline(void) ****************************************************************************/ #if defined(CONFIG_SIM_TOUCHSCREEN) || defined(CONFIG_SIM_AJOYSTICK) || \ - defined(CONFIG_SIM_BUTTONS) + defined(CONFIG_SIM_BUTTONS) || defined(CONFIG_SIM_MOUSE) static void sim_x11event_work(void *arg) { sim_x11events(); @@ -331,7 +331,7 @@ void up_initialize(void) #endif #if defined(CONFIG_SIM_TOUCHSCREEN) || defined(CONFIG_SIM_AJOYSTICK) || \ - defined(CONFIG_SIM_BUTTONS) + defined(CONFIG_SIM_BUTTONS) || defined(CONFIG_SIM_MOUSE) work_queue_wq(g_work_queue, &g_x11event_work, sim_x11event_work, NULL, SIM_X11EVENT_PERIOD); #endif diff --git a/arch/sim/src/sim/sim_internal.h b/arch/sim/src/sim/sim_internal.h index 40aa562c18f..9f256838cd6 100644 --- a/arch/sim/src/sim/sim_internal.h +++ b/arch/sim/src/sim/sim_internal.h @@ -329,6 +329,14 @@ int sim_tsc_initialize(int minor); int sim_tsc_uninitialize(void); #endif +/* sim_mouse.c **************************************************************/ + +#ifdef CONFIG_SIM_MOUSE +int sim_mouse_initialize(int minor); +int sim_mouse_uninitialize(void); +void sim_mouseevent(int x, int y, int buttons, int wheel); +#endif + /* sim_keyboard.c ***********************************************************/ #ifdef CONFIG_SIM_KEYBOARD @@ -339,7 +347,8 @@ void sim_kbdevent(uint32_t key, bool is_press); /* sim_eventloop.c **********************************************************/ #if defined(CONFIG_SIM_TOUCHSCREEN) || defined(CONFIG_SIM_AJOYSTICK) || \ - defined(CONFIG_ARCH_BUTTONS) || defined(CONFING_SIM_KEYBOARD) + defined(CONFIG_ARCH_BUTTONS) || defined(CONFIG_SIM_KEYBOARD) || \ + defined(CONFIG_SIM_MOUSE) void sim_x11events(void); void sim_buttonevent(int x, int y, int buttons); #endif diff --git a/arch/sim/src/sim/sim_mouse.c b/arch/sim/src/sim/sim_mouse.c new file mode 100644 index 00000000000..851c59f8fa0 --- /dev/null +++ b/arch/sim/src/sim/sim_mouse.c @@ -0,0 +1,206 @@ +/**************************************************************************** + * arch/sim/src/sim/sim_mouse.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* A full X11 mouse emulation for the sim architecture, registering + * /dev/mouseN via the standard mouse_lowerhalf_s interface (see + * include/nuttx/input/mouse.h). Modeled closely on sim_touchscreen.c + * (same registration shape, same X11-button-event source via + * sim_x11eventloop.c), but reports which physical button changed + * instead of folding every button into one "pen down" contact -- + * sim_touchscreen.c exists to emulate real touchscreen hardware, which + * has no second or third button to report in the first place. Any + * consumer that needs to tell a right-click from a left-click (e.g. a + * GUI toolkit's context-menu handling) needs this driver, not the + * touchscreen one. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> + +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <nuttx/debug.h> + +#include <nuttx/input/mouse.h> + +#include "sim_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define DEV_FORMAT "/dev/mouse%d" +#define DEV_NAMELEN 16 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes the state of one simulated mouse driver + * instance. + */ + +struct sim_dev_s +{ + int eventloop; + uint8_t minor; /* Minor device number */ + struct mouse_lowerhalf_s lower; /* Mouse lowerhalf */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Only one simulated mouse is supported so the driver state structure + * may as well be pre-allocated. + */ + +static struct sim_dev_s g_simmouse; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sim_mouse_initialize + * + * Description: + * Configure the simulated mouse. This will register the driver as + * /dev/mouseN where N is the minor device number + * + * Input Parameters: + * minor - The input device minor number + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int sim_mouse_initialize(int minor) +{ + struct sim_dev_s *priv = (struct sim_dev_s *)&g_simmouse; + char devname[DEV_NAMELEN]; + int ret; + + iinfo("minor: %d\n", minor); + + /* Debug-only sanity checks */ + + DEBUGASSERT(minor >= 0 && minor < 100); + + /* Initialize the mouse device driver instance */ + + memset(priv, 0, sizeof(struct sim_dev_s)); + + priv->minor = minor; + + /* Register the device as an input device */ + + snprintf(devname, sizeof(devname), DEV_FORMAT, minor); + iinfo("Registering %s\n", devname); + + ret = mouse_register(&priv->lower, devname, 1); + if (ret < 0) + { + ierr("ERROR: mouse_register() failed: %d\n", ret); + return ret; + } + + /* Enable X11 event processing from the IDLE loop */ + + priv->eventloop = 1; + + /* And return success */ + + return OK; +} + +/**************************************************************************** + * Name: sim_mouse_uninitialize + * + * Description: + * Uninitialized the simulated mouse + * + * Input Parameters: + * None + * + * Returned Value: + * Return OK if success or negative value of the error. + * + ****************************************************************************/ + +int sim_mouse_uninitialize(void) +{ + struct sim_dev_s *priv = (struct sim_dev_s *)&g_simmouse; + char devname[DEV_NAMELEN]; + + /* Stop the event loop (Hmm.. the caller must be sure that there are no + * open references to the mouse driver. This might better be done in + * close() using a reference count). + */ + + priv->eventloop = 0; + + /* Un-register the device */ + + snprintf(devname, sizeof(devname), DEV_FORMAT, priv->minor); + iinfo("Un-registering %s\n", devname); + + mouse_unregister(&priv->lower, devname); + + return OK; +} + +/**************************************************************************** + * Name: sim_mouseevent + ****************************************************************************/ + +void sim_mouseevent(int x, int y, int buttons, int wheel) +{ + struct sim_dev_s *priv = (struct sim_dev_s *)&g_simmouse; + struct mouse_report_s sample; + + if (priv->eventloop == 0) + { + return; + } + + iinfo("x=%d y=%d buttons=%02x wheel=%d\n", x, y, buttons, wheel); + + memset(&sample, 0, sizeof(sample)); + sample.buttons = (uint8_t)buttons; + sample.x = (int16_t)x; + sample.y = (int16_t)y; + sample.wheel = (int16_t)wheel; + + /* Report data changes */ + + mouse_event(priv->lower.priv, &sample); +}
