1// Copyright 2013 The Flutter Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5part of engine; 6 7/// Provides keyboard bindings, such as the `flutter/keyevent` channel. 8class Keyboard { 9 /// Initializes the [Keyboard] singleton. 10 /// 11 /// Use the [instance] getter to get the singleton after calling this method. 12 static void initialize() { 13 _instance ??= Keyboard._(); 14 } 15 16 /// The [Keyboard] singleton. 17 static Keyboard get instance => _instance; 18 static Keyboard _instance; 19 20 html.EventListener _keydownListener; 21 html.EventListener _keyupListener; 22 23 Keyboard._() { 24 _keydownListener = (html.Event event) { 25 _handleHtmlEvent(event); 26 }; 27 html.window.addEventListener('keydown', _keydownListener); 28 29 _keyupListener = (html.Event event) { 30 _handleHtmlEvent(event); 31 }; 32 html.window.addEventListener('keyup', _keyupListener); 33 registerHotRestartListener(() { 34 dispose(); 35 }); 36 } 37 38 /// Uninitializes the [Keyboard] singleton. 39 /// 40 /// After calling this method this object becomes unusable and [instance] 41 /// becomes `null`. Call [initialize] again to initialize a new singleton. 42 void dispose() { 43 html.window.removeEventListener('keydown', _keydownListener); 44 html.window.removeEventListener('keyup', _keyupListener); 45 _keydownListener = null; 46 _keyupListener = null; 47 _instance = null; 48 } 49 50 static const JSONMessageCodec _messageCodec = JSONMessageCodec(); 51 52 void _handleHtmlEvent(html.KeyboardEvent event) { 53 final Map<String, dynamic> eventData = <String, dynamic>{ 54 'type': event.type, 55 // TODO(yjbanov): this emulates Android because that the only reasonable 56 // thing to map to right now (the other choice is fuchsia). 57 // However, eventually we need to have something that maps 58 // better to Web. 59 'keymap': 'android', 60 'keyCode': event.keyCode, 61 }; 62 63 // TODO(yjbanov): The browser does not report `charCode` for 'keydown' and 64 // 'keyup', only for 'keypress'. This restores the value 65 // from the 'key' field. However, we need to verify how 66 // many code units a single key can have. Right now it 67 // assumes exactly one unit (that's what Flutter framework 68 // expects). But we'll need a different strategy if other 69 // code unit counts are possible. 70 if (event.key.codeUnits.length == 1) { 71 eventData['codePoint'] = event.key.codeUnits.first; 72 } 73 74 ui.window.onPlatformMessage('flutter/keyevent', 75 _messageCodec.encodeMessage(eventData), _noopCallback); 76 } 77} 78 79void _noopCallback(ByteData data) {} 80