C++ GRX SDK · Cursor & Tooltip Engine

Building Real-Time Cursor Monitors & Dynamic BIM Tooltips with AcEdInputPointMonitor (dev-cookbook-18)

Implement AcEdInputPointMonitor and AcEdInputPointFilter in GstarCAD 2027 C++ GRX to display real-time XDATA/dictionary tooltips and custom cursor aperture graphics.

1. Cursor Input Pipeline: `AcEdInputPointMonitor` vs. `AcEdInputPointFilter`

Every mouse movement inside a GstarCAD 2027 viewport passes through `AcEdInputPointManager` (`curDoc()->inputPointManager()`). The SDK exposes two distinct hooks into this 60–144 Hz cursor pipeline:

  • AcEdInputPointMonitor (Read-Only Observer): Receives the computed 3D point (`computedPoint`), active OSNAP modes, aperture entities (`apertureEntities`), and key-state flags (`MK_CONTROL`, `MK_SHIFT`). A monitor can draw temporary transient graphics via `AcGiViewportDraw` and append custom formatted text to the cursor tooltip (`appendToTooltipStr`), but it cannot alter the coordinate returned to the active command.
  • AcEdInputPointFilter (Coordinate Mutator): Executes after monitors and is permitted to override `changedPoint`—ideal for magnetic grid snapping, custom 3D surface elevation locking, or orthogonal pipe routing constraints.

2. C++ Implementation: Live Equipment XDATA & Pressure-Drop Cursor Tooltip

In MEP and process plant engineering (`P&ID`), engineers want to hover over any valve, pump, or duct segment and immediately read its ERP part number, nominal diameter (`DN`), and calculated flow rate in the cursor rollover tooltip without opening the Properties palette. Below is a production `AcEdInputPointMonitor` subclass for GstarCAD 2027:

#include "grxHeaders.h"
#include "acedinpt.h"

class GcMepTooltipMonitor : public AcEdInputPointMonitor {
public:
    virtual Acad::ErrorStatus monitorInputPoint(
        const AcEdInputPoint& input,
        AcEdInputPointMonitorResult& output) override
    {
        if (!input.pointComputed()) return Acad::eOk;

        const AcDbObjectIdArray& pickedIds = input.pickedEntities();
        if (pickedIds.isEmpty()) return Acad::eOk;

        // Open top-most hovered entity for lightweight read
        AcDbObjectPointer<AcDbEntity> pEnt(pickedIds[0], AcDb::kForRead);
        if (pEnt.openStatus() != Acad::eOk) return Acad::eOk;

        // Query registered application XDATA ("GSTAR_MEP_SPEC")
        struct resbuf* pRb = pEnt->xData(L"GSTAR_MEP_SPEC");
        if (pRb != nullptr) {
            AcString tooltipText = L"
--- GstarCAD MEP Telemetry ---";
            for (struct resbuf* pCur = pRb->rbnext; pCur != nullptr; pCur = pCur->rbnext) {
                if (pCur->restype == AcDb::kDxfXdAsciiString) {
                    tooltipText.appendFormat(L"
Spec: %s", pCur->resval.rstring);
                } else if (pCur->restype == AcDb::kDxfXdReal) {
                    tooltipText.appendFormat(L"
Flow Rate: %.2f L/s", pCur->resval.rreal);
                }
            }
            acutRelRb(pRb);
            output.setAdditionalTooltipString(tooltipText.kwszPtr());

            // Highlight bounding circle in viewport context
            if (input.drawContext() != nullptr) {
                input.drawContext()->subEntityTraits().setColor(3); // Green highlight
                input.drawContext()->geometry().circle(
                    input.computedPoint(), 150.0, AcGeVector3d::kZAxis);
            }
        }
        return Acad::eOk;
    }
};

3. Per-Document Registration Lifecycle & Latency Budgeting

Because `AcEdInputPointManager` is owned by each individual `AcApDocument` instance rather than the global application singleton, you must attach and detach your `GcMepTooltipMonitor` inside an `AcApDocManagerReactor` (`documentCreated` and `documentToBeDestroyed`). Furthermore, because `monitorInputPoint()` fires up to 120 times per second during mouse movement, keep execution time strictly under **0.5 milliseconds**:

Performance Anti-Pattern Symptom in Viewport Recommended GRX Best Practice
Querying SQL/REST API inside `monitorInputPoint()` Severe cursor stuttering and dropped mouse frames Cache external PLM/ERP attributes into an in-memory `std::unordered_map<AcDbHandle, SpecData>` indexed by entity handle.
Iterating entire Model Space Block Table Record 100% single-core CPU spike on 50,000+ entity drawings Inspect only `input.pickedEntities()[0]` (already spatially indexed by GstarCAD's pickbox aperture tree).
Forgetting `removePointMonitor()` on unload Access violation (`0xC0000005`) on next mouse move Iterate `acDocManager->newAcApDocumentIterator()` inside `On_kUnloadAppMsg` and detach monitors from all open documents.

4. Filtering Sub-Entities Inside Nested Blocks (`fullSubentPath`)

In architectural and plant layouts where equipment symbols are nested two or three levels deep inside floor-plan Xrefs (`AcDbBlockReference` chains), `input.pickedEntities()` returns only the top-level leaf entity. To inspect the parent block hierarchy or identify which specific Xref instance is under the cursor, query `input.gsSelectionMark()` alongside `acdbGetObjectId()` or traverse the owner chain via `pEnt->ownerId()`.

If your tooltip monitor also renders transient 3D clearance spheres or flow vectors via `input.drawContext()->geometry()`, always save and restore `subEntityTraits().color()`, `lineWeight()`, and `fillType()` before returning `Acad::eOk` so subsequent monitors in the chain inherit a clean graphics state.

Validate This Workflow in GstarCAD 2027

Engineered by Suzhou Gstarsoft Co., Ltd. (SSE: 688657), GstarCAD 2027 delivers 100% native AC1032 DWG binary fidelity, perpetual licensing sovereignty, and zero-day AutoCAD command parity.

Download Free 30-Day Evaluation → Explore AutoCAD Migration Hub Take Skill Certification Quiz