Skip to main content

android_hid_gamepad 0.0.1 copy "android_hid_gamepad: ^0.0.1" to clipboard
android_hid_gamepad: ^0.0.1 copied to clipboard

PlatformAndroid

A Flutter plugin for Android HID Gamepad using Bluetooth

example/lib/main.dart

import 'package:android_hid_gamepad_example/cubits/paired_devices_cubit.dart';
// import 'package:android_hid_gamepad_example/cubits/paired_devices_state.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:android_hid_gamepad/android_hid_gamepad.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_joystick/flutter_joystick.dart';
import 'package:flutter/cupertino.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.landscapeLeft,
    DeviceOrientation.landscapeRight,
  ]).then((_) {
    runApp(
      BlocProvider(
        create: (context) => PairedDevicesCubit(AndroidHidGamepad()),
        child: const MyApp(),
      ),
    );
  });
}
// States ill have:     deviceList

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: MainPage(), debugShowCheckedModeBanner: false);
  }
}

class MainPage extends StatefulWidget {
  const MainPage({super.key});
  @override
  State<StatefulWidget> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  final _androidHidGamepad = AndroidHidGamepad();
  String? _connectedDeviceName;
  String? _lastConnAddress;

  List<int> inputByte = [0, 0, 0]; // Button, JoyX, JoyY

  void updateInputData(int inputBit, bool isPressed) {
    // setState(() {
    if (isPressed) {
      inputByte[0] = inputByte[0] | inputBit;
    } else {
      inputByte[0] = inputByte[0] & ~inputBit;
    }
    // });

    _androidHidGamepad.sendInputData(inputByte);
    debugPrint("Current Mask Sent: $inputByte");
  }

  void updateJoystick(double x, double y) {
    // flutter_joystick gives -1.0 to 1.0. We multiply by 127 for our HID limits.
    inputByte[1] = (x * 127).toInt();
    inputByte[2] = (y * 127).toInt();
    _androidHidGamepad.sendInputData(inputByte);
    debugPrint("Current Mask Sent: $inputByte");
  }

  @override
  void initState() {
    super.initState();

    context.read<PairedDevicesCubit>().initSetup();
  }

  Future<void> connectToPCwithAdd(String? add) async {
    if (add == null) return;

    try {
      await _androidHidGamepad.connectToPC(add);

      setState(() {
        _connectedDeviceName = add;
      });

      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('Connected: $add'),
            backgroundColor: Colors.green,
          ),
        );
      }
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('Nope No Connected'),
            backgroundColor: Colors.red,
          ),
        );
      }
    }
  }

  Future<void> verifyConnection() async {
    List<String>? pcInfo = await _androidHidGamepad.getConnectedDevice();

    if (pcInfo != null && pcInfo.length >= 2) {
      setState(() {
        _connectedDeviceName = pcInfo[0];
      });
      _lastConnAddress = pcInfo[1];

      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text("Connected: $_connectedDeviceName"),
            backgroundColor: Colors.green,
          ),
        );
      }
    } else {
      try {
        connectToPCwithAdd(_lastConnAddress);
      } catch (e) {
        debugPrint("error in old conn");
      }
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('Nope Not Connected'),
            backgroundColor: Colors.red,
          ),
        );
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Stack(
          children: [
            Positioned(
              top: 10,
              left: 10,
              child: Text(
                _connectedDeviceName != null
                    ? "Connected: $_connectedDeviceName"
                    : "NotConnected",
                style: TextStyle(
                  color: _connectedDeviceName != null
                      ? Colors.green
                      : Colors.red,
                  fontSize: 18,
                ),
              ),
            ),

            if (_connectedDeviceName == null)
              Center(
                child: Container(
                  padding: const EdgeInsets.all(20),
                  decoration: BoxDecoration(
                    color: Colors.grey.shade200,
                    borderRadius: BorderRadius.circular(12),
                  ),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      const Text(
                        "Instructions",
                        style: TextStyle(
                          fontSize: 20,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      const SizedBox(height: 15),
                      const Text(
                        "1. Turn on BT in this phone and make it discoverable.\n"
                        "2. Open the app on phone and turn on BT on your laptop and pair the phone.\n"
                        "3. Press verify to connect. Enjoy!\n"
                        "If any problem occurs, forget the device from PC and pair again.",
                      ),
                      const SizedBox(height: 20),
                      ElevatedButton(
                        onPressed: verifyConnection,
                        style: ElevatedButton.styleFrom(
                          padding: const EdgeInsets.symmetric(
                            horizontal: 40,
                            vertical: 15,
                          ),
                        ),
                        child: const Text(
                          "Verify & Connect",
                          style: TextStyle(fontSize: 16),
                        ),
                      ),
                    ],
                  ),
                ),
              ),

            if (_connectedDeviceName != null) ...[
              Positioned(
                top: 10,
                right: 10,
                child: Row(
                  children: [
                    OutlinedButton(
                      onPressed: () {
                        _androidHidGamepad.disconnect();
                        setState(() {
                          _connectedDeviceName = null;
                        });
                      },
                      style: OutlinedButton.styleFrom(
                        side: const BorderSide(
                          color: CupertinoColors.systemRed,
                          width: 1.5,
                        ),
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(12),
                        ),
                      ),
                      child: const Icon(
                        CupertinoIcons.power,
                        color: CupertinoColors.systemRed,
                      ),
                    ),
                  ],
                ),
              ),
              Positioned(
                bottom: 80,
                right: 80,
                child: SizedBox(
                  width: 180,
                  height: 180,
                  child: Stack(
                    children: [
                      Positioned(
                        top: 0,
                        left: 60,
                        child: gamePadButtonXYAB(
                          'Y',
                          Colors.yellow.shade700,
                          8,
                          updateInputData,
                        ),
                      ),
                      Positioned(
                        top: 60,
                        left: 0,
                        child: gamePadButtonXYAB(
                          'X',
                          Colors.blue,
                          4,
                          updateInputData,
                        ),
                      ),
                      Positioned(
                        top: 60,
                        right: 0,
                        child: gamePadButtonXYAB(
                          'B',
                          Colors.red,
                          2,
                          updateInputData,
                        ),
                      ),
                      Positioned(
                        bottom: 0,
                        left: 60,
                        child: gamePadButtonXYAB(
                          'A',
                          Colors.green,
                          1,
                          updateInputData,
                        ),
                      ),
                    ],
                  ),
                ),
              ),
              Positioned(
                bottom: 80,
                left: 80,
                child: Joystick(
                  mode: JoystickMode.all,
                  base: Container(
                    width: 180,
                    height: 180,
                    decoration: BoxDecoration(
                      color: Colors.grey.shade400,
                      shape: BoxShape.circle,
                    ),
                  ),
                  stick: Container(
                    width: 50,
                    height: 50,
                    decoration: BoxDecoration(
                      color: Colors.grey,
                      shape: BoxShape.circle,
                    ),
                  ),
                  listener: (details) {
                    updateJoystick(details.x, details.y);
                  },
                ),
              ),
            ],
          ],
        ),
      ),
    );
  }
}

Widget gamePadButtonXYAB(
  String name,
  Color color,
  int bitValue,
  Function updateBit,
) {
  return SizedBox(
    width: 60,
    height: 60,
    child: Listener(
      onPointerDown: (event) {
        updateBit(bitValue, true);
      },
      onPointerUp: (event) {
        updateBit(bitValue, false);
      },
      child: ElevatedButton(
        onPressed: () {
          debugPrint("PRESS: $name");
        },
        style: ElevatedButton.styleFrom(
          shape: CircleBorder(),
          padding: EdgeInsets.zero,
          backgroundColor: color,
          foregroundColor: Colors.white,
        ),
        child: Text(
          name,
          style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
        ),
      ),
    ),
  );
}
0
likes
150
points
43
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Flutter plugin for Android HID Gamepad using Bluetooth

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on android_hid_gamepad

Packages that implement android_hid_gamepad