stopCapture method

  1. @override
Future<void> stopCapture()
override

Stop input capture.

Implementation

@override
Future<void> stopCapture() async {
  if (_isDestroyed || _contextHandle == null) {
    await _cleanupCallbacks();
    return;
  }

  if (_keyboardCallbackHandle == null &&
      _mouseCallbackHandle == null &&
      _gamepadCallbackHandle == null) {
    return; // Already stopped
  }

  final res = bindings.MiniAV_Input_StopCapture(_contextHandle!);

  // A non-success code means a native thread did not join
  // (MINIAV_ERROR_TIMEOUT on the hook thread or the gamepad thread). The
  // hook-thread timeout returns BEFORE the process-wide active-platform
  // slot is cleared, so the still-installed low-level hook keeps reading
  // these callback pointers. Closing the callables then is a
  // use-after-free that aborts the VM; leak them instead.
  if (res == bindings.MiniAVResultCode.MINIAV_SUCCESS ||
      res == bindings.MiniAVResultCode.MINIAV_ERROR_NOT_RUNNING) {
    await _cleanupCallbacks();
  } else {
    _keyboardCallbackHandle = null; // dropped, deliberately not closed
    _mouseCallbackHandle = null;
    _gamepadCallbackHandle = null;
    print(
      'Warning: MiniAV_Input_StopCapture failed: ${res.name} — a capture '
      'thread may still be running, so its callbacks are leaked rather '
      'than closed.',
    );
  }
}