Mouse and keyboard input
This commit is contained in:
parent
e5cd74926f
commit
fe89f4e0af
45
lib/input.dart
Normal file
45
lib/input.dart
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import 'package:dartterm/terminal.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
abstract class Input {
|
||||||
|
const Input();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Click extends Input {
|
||||||
|
final Button button;
|
||||||
|
final int x, y;
|
||||||
|
|
||||||
|
const Click(this.button, this.x, this.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Keystroke extends Input {
|
||||||
|
final Key? key;
|
||||||
|
final String? _text;
|
||||||
|
|
||||||
|
const Keystroke(this.key, this._text);
|
||||||
|
|
||||||
|
String? text() => _text;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Button { left, right }
|
||||||
|
|
||||||
|
enum Key { space }
|
||||||
|
|
||||||
|
void startListening() {
|
||||||
|
ServicesBinding.instance.keyboard.addHandler(_onKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _onKey(KeyEvent event) {
|
||||||
|
if (event is KeyDownEvent) {
|
||||||
|
final dartKey = event.logicalKey.keyLabel;
|
||||||
|
final realKey = _keys[dartKey];
|
||||||
|
|
||||||
|
notifyInput(Keystroke(realKey, event.character));
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final _keys = {
|
||||||
|
" ": Key.space,
|
||||||
|
};
|
@ -1,11 +1,11 @@
|
|||||||
import 'package:dartterm/colors.dart';
|
import 'package:dartterm/colors.dart';
|
||||||
|
import 'package:dartterm/input.dart' as input;
|
||||||
import 'package:dartterm/game.dart' as game;
|
import 'package:dartterm/game.dart' as game;
|
||||||
import 'package:dartterm/terminal.dart' as terminal;
|
import 'package:dartterm/terminal.dart' as terminal;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// terminal.at(0, 0).puts("Hello, world!");
|
|
||||||
runApp(const App());
|
runApp(const App());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,6 +43,7 @@ class _ViewerState extends State<Viewer> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
ticker = Ticker(tick);
|
ticker = Ticker(tick);
|
||||||
ticker!.start();
|
ticker!.start();
|
||||||
|
input.startListening();
|
||||||
game.main();
|
game.main();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:dartterm/colors.dart';
|
import 'package:dartterm/colors.dart';
|
||||||
import 'package:dartterm/cp437.dart';
|
import 'package:dartterm/cp437.dart';
|
||||||
import 'package:dartterm/fonts.dart';
|
import 'package:dartterm/fonts.dart';
|
||||||
|
import 'package:dartterm/input.dart';
|
||||||
import 'package:dartterm/terminal_painter.dart';
|
import 'package:dartterm/terminal_painter.dart';
|
||||||
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class Terminal {
|
class Terminal {
|
||||||
@ -10,14 +14,23 @@ class Terminal {
|
|||||||
static const int nTiles = width * height;
|
static const int nTiles = width * height;
|
||||||
|
|
||||||
late List<Tile> tiles;
|
late List<Tile> tiles;
|
||||||
|
(int, int)? lastSeenMouse;
|
||||||
|
ScreenDimensions? screenDimensions;
|
||||||
|
List<Input> inputEvents = [];
|
||||||
|
|
||||||
Terminal() {
|
Terminal() {
|
||||||
tiles = [for (var i = 0; i < nTiles; i += 1) Tile.empty()];
|
tiles = [for (var i = 0; i < nTiles; i += 1) Tile.empty()];
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomPaint toWidget(BuildContext context) {
|
Widget toWidget(BuildContext context) {
|
||||||
var scalingFactor = MediaQuery.devicePixelRatioOf(context);
|
var scalingFactor = MediaQuery.devicePixelRatioOf(context);
|
||||||
return CustomPaint(painter: TerminalCustomPainter(this, scalingFactor));
|
return MouseRegion(
|
||||||
|
onExit: _onPointerExit,
|
||||||
|
child: Listener(
|
||||||
|
onPointerDown: _onPointerDown,
|
||||||
|
onPointerHover: _onPointerHover,
|
||||||
|
child: CustomPaint(
|
||||||
|
painter: TerminalCustomPainter(this, scalingFactor))));
|
||||||
}
|
}
|
||||||
|
|
||||||
(int, int)? toXY(int i) {
|
(int, int)? toXY(int i) {
|
||||||
@ -37,6 +50,71 @@ class Terminal {
|
|||||||
|
|
||||||
return x + y * width;
|
return x + y * width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void notifyInput(Input i) {
|
||||||
|
// TODO: Handle it
|
||||||
|
log("Input: $i $lastSeenMouse");
|
||||||
|
inputEvents.add(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void notifyScreenDimensions(ScreenDimensions sd) {
|
||||||
|
screenDimensions = sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _onPointerDown(PointerDownEvent me) {
|
||||||
|
final button;
|
||||||
|
if (me.buttons & kPrimaryMouseButton != 0) {
|
||||||
|
button = Button.left;
|
||||||
|
} else if (me.buttons & kSecondaryMouseButton != 0) {
|
||||||
|
button = Button.right;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var localPosition = me.localPosition;
|
||||||
|
final xy = _relativizeMouse(localPosition.dx, localPosition.dy);
|
||||||
|
lastSeenMouse = xy;
|
||||||
|
if (xy != null) {
|
||||||
|
final (x, y) = xy;
|
||||||
|
notifyInput(Click(button, x, y));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _onPointerExit(PointerExitEvent me) {
|
||||||
|
lastSeenMouse = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _onPointerHover(PointerHoverEvent me) {
|
||||||
|
var localPosition = me.localPosition;
|
||||||
|
lastSeenMouse = _relativizeMouse(localPosition.dx, localPosition.dy);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
(int, int)? _relativizeMouse(double localX, double localY) {
|
||||||
|
final sd = screenDimensions;
|
||||||
|
if (sd == null) return null;
|
||||||
|
if (sd.xSz == 0 || sd.ySz == 0) return null;
|
||||||
|
|
||||||
|
final tx = ((localX - sd.x0) * width) ~/ sd.xSz;
|
||||||
|
final ty = ((localY - sd.y0) * height) ~/ sd.ySz;
|
||||||
|
|
||||||
|
if (tx < 0 || tx >= width) return null;
|
||||||
|
if (ty < 0 || ty >= height) return null;
|
||||||
|
|
||||||
|
return (tx, ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScreenDimensions {
|
||||||
|
final double x0, y0, xSz, ySz;
|
||||||
|
|
||||||
|
const ScreenDimensions(
|
||||||
|
{required this.x0,
|
||||||
|
required this.y0,
|
||||||
|
required this.xSz,
|
||||||
|
required this.ySz});
|
||||||
}
|
}
|
||||||
|
|
||||||
class Cursor {
|
class Cursor {
|
||||||
@ -154,6 +232,14 @@ Widget toWidget(BuildContext context) {
|
|||||||
return _terminal.toWidget(context);
|
return _terminal.toWidget(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void notifyInput(Input i) {
|
||||||
|
_terminal.notifyInput(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void notifyScreenDimensions(ScreenDimensions sd) {
|
||||||
|
_terminal.notifyScreenDimensions(sd);
|
||||||
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
at(0, 0).clear();
|
at(0, 0).clear();
|
||||||
}
|
}
|
||||||
|
@ -53,12 +53,15 @@ class TerminalCustomPainter extends CustomPainter {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log("$x0, $y0, $xSz, $ySz");
|
|
||||||
canvas.drawImageRect(
|
canvas.drawImageRect(
|
||||||
image,
|
image,
|
||||||
const Offset(0, 0) & smallSize,
|
const Offset(0, 0) & smallSize,
|
||||||
Offset(x0, y0) & Size(xSz, ySz),
|
Offset(x0, y0) & Size(xSz, ySz),
|
||||||
Paint()..filterQuality = FilterQuality.none);
|
Paint()..filterQuality = FilterQuality.none);
|
||||||
|
notifyScreenDimensions(
|
||||||
|
ScreenDimensions(x0: x0, y0: y0, xSz: xSz, ySz: ySz));
|
||||||
|
|
||||||
|
image.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void virtualPaint(Canvas canvas, Size size) {
|
void virtualPaint(Canvas canvas, Size size) {
|
||||||
|
Loading…
Reference in New Issue
Block a user