flat_navi: Handle focus chain end in drop-down menu 46/287146/1
authorArtur Świgoń <a.swigon@samsung.com>
Thu, 12 Jan 2023 11:07:28 +0000 (12:07 +0100)
committerArtur Świgoń <a.swigon@samsung.com>
Fri, 20 Jan 2023 11:13:09 +0000 (12:13 +0100)
This patch tries to detect the focus chain end scenario in a drop-down menu and
close the menu, before falling back to the default looping behaviour.

Change-Id: I0f9fb34825954349b6644a83e1c58e74ed3a3905

src/flat_navi.c

index 281f6073ed8a3bf228bf62e7333f7ae357b95ec9..fd815c4bc077be2f9c2fdaabfbe9806067b3923d 100644 (file)
@@ -330,6 +330,54 @@ AtspiAccessible *_last(FlatNaviContext *ctx)
        return _directional_depth_first_search(ctx->root, NULL, SEARCH_BACKWARD, _accept_object);
 }
 
+static void _on_chain_end_loop(FlatNaviContext *ctx, search_direction direction)
+{
+       AtspiAccessible *result = (direction == SEARCH_FORWARD) ? _first(ctx) : _last(ctx);
+       g_object_unref(ctx->current);
+       ctx->current = result;
+       ctx->last_entry = LAST_ENTRY_NONE;
+}
+
+static void _on_chain_end_escape(FlatNaviContext *ctx, search_direction direction)
+{
+       static const char action_name[] = "escape";
+
+       gboolean success = FALSE;
+
+       AtspiAction *action = atspi_accessible_get_action_iface(ctx->root);
+       if (!action) {
+               ERROR("Object does not have Action interface");
+               goto end;
+       }
+
+       GError *err = NULL;
+       success = atspi_action_do_action_name(action, action_name, &err);
+       GERROR_CHECK(err);
+       g_object_unref(action);
+
+end:
+       if (success) {
+               DEBUG("Action %s invoked successfully", action_name);
+       } else {
+               ERROR("Action %s failed, falling back to looping over", action_name);
+               _on_chain_end_loop(ctx, direction);
+       }
+}
+
+static void _on_chain_end(FlatNaviContext *ctx, search_direction direction)
+{
+       AtspiRole role = atspi_accessible_get_role(ctx->root, NULL);
+
+       // The default is to loop over when the user makes a flick gesture again
+       // after reaching the end of the focus chain, unless the current context
+       // is a drop-down menu, in which case we try to close it instead.
+
+       if (role == ATSPI_ROLE_COMBO_BOX)
+               _on_chain_end_escape(ctx, direction);
+       else
+               _on_chain_end_loop(ctx, direction);
+}
+
 static void _navigate_by_one(FlatNaviContext *ctx, search_direction direction)
 {
        if (direction != SEARCH_FORWARD && direction != SEARCH_BACKWARD) {
@@ -346,10 +394,7 @@ static void _navigate_by_one(FlatNaviContext *ctx, search_direction direction)
                                                                "first item reached or failed");
 
                if (ctx->last_entry == (direction == SEARCH_FORWARD ? LAST_ENTRY_LAST : LAST_ENTRY_FIRST)) {
-                       AtspiAccessible *result = (direction == SEARCH_FORWARD) ? _first(ctx) : _last(ctx);
-                       g_object_unref(ctx->current);
-                       ctx->current = result;
-                       ctx->last_entry = LAST_ENTRY_NONE;
+                       _on_chain_end(ctx, direction);
                }
                else {
                        /* TODO Is it a proper place for sound generation? */