Commit 50ebcd1d authored by Adam Barth's avatar Adam Barth Committed by GitHub

Migrate RawKeyboard to platform events (#6366)

This patch moves RawKeyboard from mojom over to platform messages. In
the process, I've also cleaned up the interface substantially.

Currently raw key events are supported only on Android, but the
interfaces defined in this patch should scale up to multiple platforms.
parent 67a29844
......@@ -3,8 +3,7 @@
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter_services/input_event.dart' as mojom;
import 'package:flutter/services.dart';
GlobalKey _key = new GlobalKey();
......@@ -32,9 +31,9 @@ class RawKeyboardDemo extends StatefulWidget {
}
class _HardwareKeyDemoState extends State<RawKeyboardDemo> {
mojom.InputEvent _event;
RawKeyEvent _event;
void _handleKey(mojom.InputEvent event) {
void _handleKeyEvent(RawKeyEvent event) {
setState(() {
_event = event;
});
......@@ -50,26 +49,34 @@ class _HardwareKeyDemoState extends State<RawKeyboardDemo> {
Focus.moveTo(config.key);
},
child: new Center(
child: new Text('Tap to focus', style: Typography.black.display1)
)
child: new Text('Tap to focus', style: Typography.black.display1),
),
);
} else if (_event == null) {
child = new Center(
child: new Text('Press a key', style: Typography.black.display1)
child: new Text('Press a key', style: Typography.black.display1),
);
} else {
int codePoint;
int keyCode;
final RawKeyEventData data = _event.data;
if (data is RawKeyEventDataAndroid) {
codePoint = data.codePoint;
keyCode = data.keyCode;
}
child = new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text('${_event.type}', style: Typography.black.body2),
new Text('${_event.keyData.keyCode}', style: Typography.black.display4)
new Text('${_event.runtimeType}', style: Typography.black.body2),
new Text('codePoint: $codePoint', style: Typography.black.display4),
new Text('keyCode: $keyCode', style: Typography.black.display4),
],
mainAxisAlignment: MainAxisAlignment.center
);
}
return new RawKeyboardListener(
focused: focused,
onKey: _handleKey,
child: child
onKey: _handleKeyEvent,
child: child,
);
}
}
......@@ -27,6 +27,7 @@ export 'src/services/image_stream.dart';
export 'src/services/keyboard.dart';
export 'src/services/path_provider.dart';
export 'src/services/platform_messages.dart';
export 'src/services/raw_keyboard.dart';
export 'src/services/shell.dart';
export 'src/services/system_chrome.dart';
export 'src/services/system_navigator.dart';
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:meta/meta.dart';
import 'platform_messages.dart';
/// Base class for platform specific key event data.
///
/// This base class exists to have a common type to use for each of the
/// target platform's key event data structures.
///
/// See also:
///
/// * [RawKeyEventDataAndroid]
/// * [RawKeyEvent]
/// * [RawKeyDownEvent]
/// * [RawKeyUpEvent]
abstract class RawKeyEventData {
/// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
const RawKeyEventData();
}
/// Platform-specific key event data for Android.
///
/// This object contains information about key events obtained from Android's
/// KeyEvent interface.
class RawKeyEventDataAndroid extends RawKeyEventData {
/// Creates a key event data structure specific for Android.
///
/// The [flags], [codePoint], [keyCode], [scanCode], and [metaState] arguments
/// must not be null.
const RawKeyEventDataAndroid({
this.flags: 0,
this.codePoint: 0,
this.keyCode: 0,
this.scanCode: 0,
this.metaState: 0,
});
/// See <https://developer.android.com/reference/android/view/KeyEvent.html#getFlags()>
final int flags;
/// See <https://developer.android.com/reference/android/view/KeyEvent.html#getUnicodeChar()>
final int codePoint;
/// See <https://developer.android.com/reference/android/view/KeyEvent.html#getKeyCode()>
final int keyCode;
/// See <https://developer.android.com/reference/android/view/KeyEvent.html#getScanCode()>
final int scanCode;
/// See <https://developer.android.com/reference/android/view/KeyEvent.html#getMetaState()>
final int metaState;
}
/// Base class for raw key events.
///
/// Raw key events pass through as much information as possible from the
/// underlying platform's key events, which makes they provide a high level of
/// fidelity but a low level of portability.
///
/// See also:
///
/// * [RawKeyDownEvent]
/// * [RawKeyUpEvent]
/// * [RawKeyboardListener], a widget that listens for raw key events.
abstract class RawKeyEvent {
/// Initializes fields for subclasses.
const RawKeyEvent({
@required this.data,
});
/// Platform-specific information about the key event.
final RawKeyEventData data;
}
/// The user has pressed a key on the keyboard.
class RawKeyDownEvent extends RawKeyEvent {
/// Creates a key event that represents the user pressing a key.
const RawKeyDownEvent({
@required RawKeyEventData data,
}) : super(data: data);
}
/// The user has released a key on the keyboard.
class RawKeyUpEvent extends RawKeyEvent {
/// Creates a key event that represents the user releasing a key.
const RawKeyUpEvent({
@required RawKeyEventData data,
}) : super(data: data);
}
RawKeyEvent _toRawKeyEvent(dynamic message) {
RawKeyEventData data;
String keymap = message['keymap'];
switch (keymap) {
case 'android':
data = new RawKeyEventDataAndroid(
flags: message['flags'] ?? 0,
codePoint: message['codePoint'] ?? 0,
keyCode: message['keyCode'] ?? 0,
scanCode: message['scanCode'] ?? 0,
metaState: message['metaState'] ?? 0,
);
break;
default:
throw new FlutterError('Unknown keymap for key events: $keymap');
}
String type = message['type'];
switch (type) {
case 'keydown':
return new RawKeyDownEvent(data: data);
case 'keyup':
return new RawKeyUpEvent(data: data);
}
throw new FlutterError('Unknown key event type: $type');
}
/// An interface for listening to raw key events.
///
/// Raw key events pass through as much information as possible from the
/// underlying platform's key events, which makes they provide a high level of
/// fidelity but a low level of portability.
///
/// A [RawKeyboard] is useful for listening to raw key events and hardware
/// buttons that are represented as keys. Typically used by games and other apps
/// that use keyboards for purposes other than text entry.
///
/// See also:
///
/// * [RawKeyEvent]
/// * [RawKeyDownEvent]
/// * [RawKeyUpEvent]
class RawKeyboard {
RawKeyboard._() {
PlatformMessages.setJSONMessageHandler('flutter/keyevent', _handleKeyEvent);
}
/// The shared instance of [RawKeyboard].
static final RawKeyboard instance = new RawKeyboard._();
final List<ValueChanged<RawKeyEvent>> _listeners = <ValueChanged<RawKeyEvent>>[];
/// Calls the listener every time the user presses or releases a key.
///
/// Listeners can be removed with [removeListener].
void addListener(ValueChanged<RawKeyEvent> listener) {
_listeners.add(listener);
}
/// Stop calling the listener every time the user presses or releases a key.
///
/// Listeners can be added with [addListener].
void removeListener(ValueChanged<RawKeyEvent> listener) {
_listeners.remove(listener);
}
Future<dynamic> _handleKeyEvent(dynamic message) async {
if (_listeners.isEmpty)
return;
RawKeyEvent event = _toRawKeyEvent(message);
if (event == null)
return;
for (ValueChanged<RawKeyEvent> listener in new List<ValueChanged<RawKeyEvent>>.from(_listeners))
if (_listeners.contains(listener))
listener(event);
}
}
......@@ -3,13 +3,12 @@
// found in the LICENSE file.
import 'package:flutter/services.dart';
import 'package:flutter_services/raw_keyboard.dart' as mojom;
import 'package:flutter_services/input_event.dart' as mojom;
import 'basic.dart';
import 'framework.dart';
/// A widget that calls a callback whenever the user presses a key on a keyboard.
/// A widget that calls a callback whenever the user presses or releases a key
/// on a keyboard.
///
/// A [RawKeyboardListener] is useful for listening to raw key events and
/// hardware buttons that are represented as keys. Typically used by games and
......@@ -43,7 +42,7 @@ class RawKeyboardListener extends StatefulWidget {
final bool focused;
/// Called whenever this widget receives a raw keyboard event.
final ValueChanged<mojom.InputEvent> onKey;
final ValueChanged<RawKeyEvent> onKey;
/// The widget below this widget in the tree.
final Widget child;
......@@ -52,15 +51,13 @@ class RawKeyboardListener extends StatefulWidget {
_RawKeyboardListenerState createState() => new _RawKeyboardListenerState();
}
class _RawKeyboardListenerState extends State<RawKeyboardListener> implements mojom.RawKeyboardListener {
class _RawKeyboardListenerState extends State<RawKeyboardListener> {
@override
void initState() {
super.initState();
_attachOrDetachKeyboard();
}
mojom.RawKeyboardListenerStub _stub;
@override
void didUpdateConfig(RawKeyboardListener oldConfig) {
_attachOrDetachKeyboard();
......@@ -79,22 +76,21 @@ class _RawKeyboardListenerState extends State<RawKeyboardListener> implements mo
_detachKeyboardIfAttached();
}
bool _listening = false;
void _attachKeyboardIfDetached() {
if (_stub != null)
if (_listening)
return;
_stub = new mojom.RawKeyboardListenerStub.unbound()..impl = this;
mojom.RawKeyboardServiceProxy keyboard = shell.connectToViewAssociatedService(mojom.RawKeyboardService.connectToService);
keyboard.addListener(_stub);
keyboard.close();
RawKeyboard.instance.addListener(_handleRawKeyEvent);
}
void _detachKeyboardIfAttached() {
_stub?.close();
_stub = null;
if (!_listening)
return;
RawKeyboard.instance.removeListener(_handleRawKeyEvent);
}
@override
void onKey(mojom.InputEvent event) {
void _handleRawKeyEvent(RawKeyEvent event) {
if (config.onKey != null)
config.onKey(event);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment