
From: Simon Glass <sjg@chromium.org> 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 <sjg@chromium.org> --- 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 <stdbool.h> + 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); -- 2.43.0