flutter_input_sdl 1.0.1
flutter_input_sdl: ^1.0.1 copied to clipboard
SDL2 FFI plugin for joystick, gamepad, keyboard, and arcade controller input handling.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_input_sdl/flutter_input_sdl.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final SdlInput _sdlInput = SdlInput.instance;
bool _isInitialized = false;
List<SdlJoystickInfo> _joysticks = [];
List<String> _eventLog = [];
Timer? _updateTimer;
@override
void initState() {
super.initState();
_initSdl();
}
Future<void> _initSdl() async {
final success = await _sdlInput.init();
if (success) {
// Start polling for events
_updateTimer = Timer.periodic(const Duration(milliseconds: 16), (_) {
_pollEvents();
});
// Listen to joystick events
_sdlInput.joystickEvents.listen((event) {
_addEventLog('Joystick: $event');
if (event.isConnected || event.isDisconnected) {
_refreshJoysticks();
}
});
// Listen to keyboard events
_sdlInput.keyboardEvents.listen((event) {
_addEventLog('Keyboard: $event');
});
}
setState(() {
_isInitialized = success;
});
if (success) {
_refreshJoysticks();
}
}
void _refreshJoysticks() {
setState(() {
_joysticks = _sdlInput.getJoysticks();
});
}
void _pollEvents() {
_sdlInput.update();
}
void _addEventLog(String message) {
setState(() {
_eventLog.insert(0, message);
if (_eventLog.length > 50) {
_eventLog.removeLast();
}
});
}
void _openJoystick(int deviceIndex) {
final instanceId = _sdlInput.openJoystick(deviceIndex);
if (instanceId >= 0) {
_addEventLog('Opened joystick $deviceIndex (instance=$instanceId)');
} else {
_addEventLog('Failed to open joystick $deviceIndex');
}
}
@override
void dispose() {
_updateTimer?.cancel();
_sdlInput.shutdown();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Flutter SDL Input Demo')),
body: Column(
children: [
// Status
Container(
padding: const EdgeInsets.all(16),
color: _isInitialized
? Colors.green.shade100
: Colors.red.shade100,
child: Row(
children: [
Icon(
_isInitialized ? Icons.check_circle : Icons.error,
color: _isInitialized ? Colors.green : Colors.red,
),
const SizedBox(width: 8),
Text(
_isInitialized
? 'SDL Input Initialized'
: 'SDL Input Not Initialized',
),
const Spacer(),
Text('Joysticks: ${_joysticks.length}'),
],
),
),
// Joystick list
if (_joysticks.isNotEmpty)
Container(
height: 120,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: _joysticks.length,
itemBuilder: (context, index) {
final js = _joysticks[index];
return Card(
margin: const EdgeInsets.all(8),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
js.name,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
Text(
js.isGameController
? 'Game Controller'
: 'Joystick',
style: TextStyle(color: Colors.grey.shade600),
),
const Spacer(),
ElevatedButton(
onPressed: () => _openJoystick(js.deviceIndex),
child: const Text('Open'),
),
],
),
),
);
},
),
),
// Event log
Expanded(
child: Container(
color: Colors.grey.shade900,
child: ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: _eventLog.length,
itemBuilder: (context, index) {
return Text(
_eventLog[index],
style: const TextStyle(
color: Colors.green,
fontFamily: 'monospace',
fontSize: 12,
),
);
},
),
),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: _refreshJoysticks,
child: const Icon(Icons.refresh),
),
),
);
}
}