Proper way have multi select with ability add/remove to preselected list?

Hello.
I’m trying find a proper way have the following:

  1. Prompt user to pick multiple objects.
  2. If any objects were already preselected, ability to add/remove in that selection.
  3. Have command line options that can be changed during object picking without losing previous selection.

I’ve been over this for hours and can only make it satisfy any 2 out of 3 items but not all 3.

using Rhino;
using Rhino.Commands;
using Rhino.DocObjects;
using Rhino.Input;
using Rhino.Input.Custom;
using System;
using System.Collections.Generic;
using System.Linq;

public class SelectWithOptionsCommand : Command
{
    public override string EnglishName => "MRE_SelectWithOptions";

    protected override Result RunCommand(RhinoDoc doc, RunMode mode)
    {
        // ── Option state ─────────────────────────────────────────────────
        var toggle = new OptionToggle(false, "No", "Yes");

        // ── Phase A: capture any pre-selected objects ─────────────────────
        var goPre = new GetObject();
        goPre.GeometryFilter = ObjectType.Curve;
        goPre.EnablePreSelect(true, false);
        goPre.EnablePostSelect(false);
        goPre.EnableUnselectObjectsOnExit(false);
        goPre.AcceptNothing(true);
        goPre.GetMultiple(0, 0);

        var collectedIds = new HashSet<Guid>();
        var collectedRefs = new Dictionary<Guid, ObjRef>();
        for (int i = 0; i < goPre.ObjectCount; i++)
        {
            var r = goPre.Object(i);
            if (collectedIds.Add(r.ObjectId))
                collectedRefs[r.ObjectId] = r;
        }

        // Keep pre-selected objects visually highlighted
        foreach (var id in collectedIds)
            doc.Objects.Select(id, true);

        // ── Phase B: interactive add / remove ─────────────────────────────
        // We want:
        //   - Click unselected object  → add to collection (highlight it)
        //   - Click selected object    → remove from collection (unhighlight it)
        //   - Toggle option            → update option, keep selection intact
        //   - Press Enter              → confirm and exit loop
        //
        // PROBLEM: no approach we've tried reliably detects the "click to
        // deselect" case. See notes at top of file.

        int iteration = 0;
        while (true)
        {
            var go = new GetObject();
            go.SetCommandPrompt("Select curves. Press Enter when done");
            go.GeometryFilter = ObjectType.Curve;
            go.SubObjectSelect = false;
            go.EnablePreSelect(false, false);       // don't auto-accept
            go.DeselectAllBeforePostSelect = false; // keep highlights
            go.AcceptNothing(true);
            go.EnableUnselectObjectsOnExit(false);
            go.AddOptionToggle("MyOption", ref toggle);

            var res = go.Get();
            RhinoApp.WriteLine($"iter {++iteration}: result={res}  ObjectCount={go.ObjectCount}");

            if (res == GetResult.Cancel)
            {
                foreach (var id in collectedIds) doc.Objects.Select(id, false);
                doc.Views.Redraw();
                return Result.Cancel;
            }

            if (res == GetResult.Nothing)
            {
                // ── PROBLEM: if user clicked an already-selected object,
                // Rhino silently deselects it and returns Nothing here.
                // We cannot distinguish that from a genuine Enter press.
                // Checking IsSelected below sometimes catches it, sometimes not.

                var silentDeselects = collectedIds
                    .Where(id => (doc.Objects.FindId(id)?.IsSelected(false) ?? 0) == 0)
                    .ToList();

                if (silentDeselects.Count > 0)
                {
                    // Treat as deselect click, not Enter — but is this reliable?
                    foreach (var id in silentDeselects)
                    {
                        collectedIds.Remove(id);
                        collectedRefs.Remove(id);
                        RhinoApp.WriteLine($"  silent-deselect: {id.ToString()[..8]}");
                    }
                    doc.Views.Redraw();
                    continue; // keep loop going
                }

                break; // genuine Enter
            }

            if (res == GetResult.Option)
            {
                RhinoApp.WriteLine($"  option: MyOption={toggle.CurrentValue}");
                continue;
            }

            if (res == GetResult.Object)
            {
                var r   = go.Object(0);
                var pid = r.ObjectId;
                if (collectedIds.Contains(pid))
                {
                    // ── This branch is never reached in practice ──
                    // Clicking an already-highlighted object never returns
                    // GetResult.Object with that object; it goes through
                    // the silent-deselect path above (or does nothing).
                    collectedIds.Remove(pid);
                    collectedRefs.Remove(pid);
                    doc.Objects.Select(pid, false);
                    RhinoApp.WriteLine($"  toggle-off: {pid.ToString()[..8]}");
                }
                else
                {
                    collectedIds.Add(pid);
                    collectedRefs[pid] = r;
                    doc.Objects.Select(pid, true);
                    RhinoApp.WriteLine($"  toggle-on: {pid.ToString()[..8]}");
                }
                doc.Views.Redraw();
            }
        }

        RhinoApp.WriteLine($"Final selection: {collectedIds.Count} object(s)");
        doc.Views.Redraw();
        return Result.Success;
    }
}

It seems to be quiet trivial requirements but I must be missing something here.

Any help?

Thank you!

The AI machine is telling me this:

With GetObject, you can reliably support preselection, post-selection, and command-line options, but not a fully custom “click selected object to remove from my maintained set” workflow in the same selection loop. Rhino handles deselection internally, and clicking an already-selected object does not reliably come back as GetResult.Object; it often falls through as Nothing, which is indistinguishable from Enter in a robust way.

The practical solution is to use a two-step interaction: preserve/collect preselected objects, allow adding with options in one GetObject phase, then provide a second removal phase or a separate Remove option loop. If exact toggle-style selection is required, it likely needs a lower-level custom input pipeline rather than plain GetObject.