@@ -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),
};
@@ -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
@@ -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);