From patchwork Mon Sep 15 10:46:52 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 310 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1757933277; bh=JB+THQi2X43DmJPq1u8m96YfXSsUz4otxk3omklq7nI=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=dTj7z3N1AXYQmHNLoyXMGux0wM/ILwDuEurAmyNz4BLKqPTLpOWOoJparMBuCYdsj ml+6KWaKqhiS8BywJcNdWQgIDEvi06m0DD+4uUphoebP/HXsNYgM757tJ0uHiaLV8J vrhiSla2IphbY8oFa5i2FUNvjbzDn8X0+IYP2bvItIsZptv6+9YA7ILSBK2EvT3/sm WNgt+O4OXivMWbpXtg3GLhhSPaywv/CQvMqxlz7M0cfwqavcJhFdcwaci+YoX+GGHu Ct/go55oDuEpjsbXjKVGVJIawUjywEY2NqfhY7hCnSyhu568LBSxCEu5wLc6SfUPv5 K+nHocd/1ErLA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 6178E67BB5 for ; Mon, 15 Sep 2025 04:47:57 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id z1Wz7bvpViX5 for ; Mon, 15 Sep 2025 04:47:57 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1757933277; bh=JB+THQi2X43DmJPq1u8m96YfXSsUz4otxk3omklq7nI=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=dTj7z3N1AXYQmHNLoyXMGux0wM/ILwDuEurAmyNz4BLKqPTLpOWOoJparMBuCYdsj ml+6KWaKqhiS8BywJcNdWQgIDEvi06m0DD+4uUphoebP/HXsNYgM757tJ0uHiaLV8J vrhiSla2IphbY8oFa5i2FUNvjbzDn8X0+IYP2bvItIsZptv6+9YA7ILSBK2EvT3/sm WNgt+O4OXivMWbpXtg3GLhhSPaywv/CQvMqxlz7M0cfwqavcJhFdcwaci+YoX+GGHu Ct/go55oDuEpjsbXjKVGVJIawUjywEY2NqfhY7hCnSyhu568LBSxCEu5wLc6SfUPv5 K+nHocd/1ErLA== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 5182867BB0 for ; Mon, 15 Sep 2025 04:47:57 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1757933276; bh=vCOBfnrjNhJvczQj7qHZV2GOVbXelVqHmzEvge01Ri0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fdc1A4lyCHrus0lY5Z1CPvBAqqWUvdEF8G/v4w3M6PNi7a3WQ6VUf+B1O2ApIRzme gTHFXKPo0eX1HWOyGHIiHKWbX4t5Ae5sV3LhrNgxTCrajVrg+LumW1kO+qXk4xdE1k 47L8bPGLdRb3gH91qu8Sc6QN3usHdnXDxnlTAR27N/yKVmNuzio9sfSv/be72M3W01 Vz7TdwBo1hFPGLoVbcaYja3xUcoZVDvkjnmlKZgh5ZwRCxsCujgGk4RJyfao35xwp/ EkxCmiHzYsqTXDwjLcoJT2+uLmsl/5oxSCuYH474QTre7KIcVh1V6dFDuuUAijYS6J BpXwDjUsee1JA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 4FCF767B04; Mon, 15 Sep 2025 04:47:56 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id XxTqyF3r22Rw; Mon, 15 Sep 2025 04:47:56 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1757933270; bh=cQ4s4ez6//pgex1qDYzZ08PydqMNYN8brvyxeJZp5ww=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XlsNwMcF4CsCvq+1amNzD6K3ufFtgJyIfMhvvZ02E+wsYNgcOXl5Q3fXscmXPE6OO m4qKkCJlAr24KUioq+nGnFUwMMkPc82uzx7zW6DEs51VbMYp3QlzW3tWsdIJqPuK0L mv7uHjRxubDTigydJ12H6u/Ok+zGoOSH4nq1MJ5h6evltvUTLFFH2jF+B2B2oZEOCU AY/bVNpjDgApaoIKj1bGn6xMzpSTwa20j57Pleg7FxeC6R6Esv1Omi3fToj6XEFxPk +o1wEwY8kVb/0GJOuMyFwfR/+57nJLkt4OxwqIPRxYG/UcfehEx5ff8V7zmybL4cl9 eA7yYMNuJoFng== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 7DB2567B22; Mon, 15 Sep 2025 04:47:50 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Mon, 15 Sep 2025 04:46:52 -0600 Message-ID: <20250915104705.937780-10-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250915104705.937780-1-sjg@u-boot.org> References: <20250915104705.937780-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: HO5LOW4OQCY4KLIK4CNKF7PVAL6AZYXS X-Message-ID-Hash: HO5LOW4OQCY4KLIK4CNKF7PVAL6AZYXS X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Heinrich Schuchardt , Simon Glass X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 11/17] mouse: Provide a way to read clicks List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass A mouse click is defined as pressing the mouse and then releasing it over a given spot. Add a function the tracks the mouse state and returns the most recent mouse click, if any. Signed-off-by: Simon Glass --- drivers/input/mouse-uclass.c | 43 +++++++++++++ include/mouse.h | 25 ++++++++ test/dm/mouse.c | 121 +++++++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+) diff --git a/drivers/input/mouse-uclass.c b/drivers/input/mouse-uclass.c index f42ef346c5c..256642ef55e 100644 --- a/drivers/input/mouse-uclass.c +++ b/drivers/input/mouse-uclass.c @@ -23,7 +23,50 @@ int mouse_get_event(struct udevice *dev, struct mouse_event *evt) return 0; } +int mouse_get_click(struct udevice *dev, int *xp, int *yp) +{ + struct mouse_uc_priv *uc_priv = dev_get_uclass_priv(dev); + struct mouse_event event; + int ret; + + /* Get one mouse event */ + ret = mouse_get_event(dev, &event); + if (ret) + return -EAGAIN; /* No event available */ + + /* Only process button events for left button */ + if (event.type == MOUSE_EV_BUTTON && + event.button.button == BUTTON_LEFT) { + enum mouse_press_state_t new_state = event.button.press_state; + bool pending = false; + + /* Detect press->release transition (click) */ + if (uc_priv->left_button_state == BUTTON_PRESSED && + new_state == BUTTON_RELEASED) { + pending = true; + uc_priv->click_x = event.button.x; + uc_priv->click_y = event.button.y; + } + + /* Update button state */ + uc_priv->left_button_state = new_state; + + /* If we just detected a click, return it */ + if (pending) { + if (xp) + *xp = uc_priv->click_x; + if (yp) + *yp = uc_priv->click_y; + + return 0; + } + } + + return -EAGAIN; +} + UCLASS_DRIVER(mouse) = { .id = UCLASS_MOUSE, .name = "mouse", + .per_device_auto = sizeof(struct mouse_uc_priv), }; diff --git a/include/mouse.h b/include/mouse.h index c96c63918ea..0d20f8ffdbc 100644 --- a/include/mouse.h +++ b/include/mouse.h @@ -8,6 +8,8 @@ #ifndef _MOUSE_H #define _MOUSE_H +#include + struct udevice; enum mouse_ev_t { @@ -29,6 +31,19 @@ enum mouse_press_state_t { BUTTON_PRESSED, }; +/** + * struct mouse_uc_priv - private data for mouse uclass + * + * @left_button_state: Current state of left button (BUTTON_PRESSED/BUTTON_RELEASED) + * @click_x: X coordinate where the click occurred + * @click_y: Y coordinate where the click occurred + */ +struct mouse_uc_priv { + enum mouse_press_state_t left_button_state; + int click_x; + int click_y; +}; + /** * struct mouse_event - information about a mouse event * @@ -77,4 +92,14 @@ struct mouse_ops { int mouse_get_event(struct udevice *dev, struct mouse_event *event); +/** + * mouse_get_click() - Check if a left mouse button click has occurred + * + * @dev: Mouse device + * @xp: Returns X coordinate of click (can be NULL) + * @yp: Returns Y coordinate of click (can be NULL) + * Returns: 0 if a click has occurred, -EAGAIN if no click pending + */ +int mouse_get_click(struct udevice *dev, int *xp, int *py); + #endif diff --git a/test/dm/mouse.c b/test/dm/mouse.c index f9c2e88c43a..1b4c2b5f60f 100644 --- a/test/dm/mouse.c +++ b/test/dm/mouse.c @@ -94,3 +94,124 @@ static int dm_test_mouse_button(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_mouse_button, UTF_SCAN_PDATA | UTF_SCAN_FDT); + +static int dm_test_mouse_click(struct unit_test_state *uts) +{ + struct udevice *dev; + struct mouse_event inject; + int x, y; + + ut_assertok(uclass_first_device_err(UCLASS_MOUSE, &dev)); + + /* put mouse in test mode */ + sandbox_mouse_set_test_mode(dev, true); + + /* test that no click is detected initially */ + ut_asserteq(-EAGAIN, mouse_get_click(dev, &x, &y)); + + /* inject a left button press */ + inject.type = MOUSE_EV_BUTTON; + inject.button.button = BUTTON_LEFT; + inject.button.press_state = BUTTON_PRESSED; + inject.button.clicks = 1; + inject.button.x = 300; + inject.button.y = 400; + + sandbox_mouse_inject(dev, &inject); + + /* + * calling mouse_get_click() should not detect a click yet (press + * only) + */ + ut_asserteq(-EAGAIN, mouse_get_click(dev, &x, &y)); + + /* inject a left button release */ + inject.type = MOUSE_EV_BUTTON; + inject.button.button = BUTTON_LEFT; + inject.button.press_state = BUTTON_RELEASED; + inject.button.clicks = 1; + inject.button.x = 300; + inject.button.y = 400; + + sandbox_mouse_inject(dev, &inject); + + /* now mouse_get_click() should detect the click */ + ut_assertok(mouse_get_click(dev, &x, &y)); + ut_asserteq(300, x); + ut_asserteq(400, y); + + /* verify no more clicks are pending */ + ut_asserteq(-EAGAIN, mouse_get_click(dev, &x, &y)); + + return 0; +} +DM_TEST(dm_test_mouse_click, UTF_SCAN_PDATA | UTF_SCAN_FDT); + +static int dm_test_mouse_click_no_coordinates(struct unit_test_state *uts) +{ + struct udevice *dev; + struct mouse_event inject; + + ut_assertok(uclass_first_device_err(UCLASS_MOUSE, &dev)); + + /* put mouse in test mode */ + sandbox_mouse_set_test_mode(dev, true); + + /* inject press and release to create a click */ + inject.type = MOUSE_EV_BUTTON; + inject.button.button = BUTTON_LEFT; + inject.button.press_state = BUTTON_PRESSED; + inject.button.clicks = 1; + inject.button.x = 500; + inject.button.y = 600; + sandbox_mouse_inject(dev, &inject); + + /* process the press event */ + ut_asserteq(-EAGAIN, mouse_get_click(dev, NULL, NULL)); + + inject.button.press_state = BUTTON_RELEASED; + sandbox_mouse_inject(dev, &inject); + + /* + * now test that click is detected without coordinate return + */ + ut_assertok(mouse_get_click(dev, NULL, NULL)); + + return 0; +} +DM_TEST(dm_test_mouse_click_no_coordinates, UTF_SCAN_PDATA | UTF_SCAN_FDT); + +static int dm_test_mouse_right_button(struct unit_test_state *uts) +{ + struct udevice *dev; + struct mouse_event inject; + int x, y; + + ut_assertok(uclass_first_device_err(UCLASS_MOUSE, &dev)); + + /* put mouse in test mode */ + sandbox_mouse_set_test_mode(dev, true); + + /* + * right button events should not be detected as clicks by + * mouse_get_click() + */ + inject.type = MOUSE_EV_BUTTON; + inject.button.button = BUTTON_RIGHT; + inject.button.press_state = BUTTON_PRESSED; + inject.button.clicks = 1; + inject.button.x = 100; + inject.button.y = 200; + sandbox_mouse_inject(dev, &inject); + + ut_asserteq(-EAGAIN, mouse_get_click(dev, &x, &y)); + + inject.button.press_state = BUTTON_RELEASED; + sandbox_mouse_inject(dev, &inject); + + /* still no click detected since it was right button */ + ut_asserteq(-EAGAIN, mouse_get_click(dev, &x, &y)); + + return 0; +} +DM_TEST(dm_test_mouse_right_button, UTF_SCAN_PDATA | UTF_SCAN_FDT);