2022-01-25 18:13:11 +08:00
|
|
|
import 'dart:typed_data';
|
2022-01-26 12:48:16 +08:00
|
|
|
import 'dart:js' as js;
|
2022-02-05 04:29:10 +08:00
|
|
|
import 'package:flutter/cupertino.dart';
|
|
|
|
import 'dart:convert';
|
|
|
|
|
2022-02-28 18:29:25 +08:00
|
|
|
import '../common.dart';
|
2022-02-03 00:53:59 +08:00
|
|
|
import 'dart:html';
|
|
|
|
import 'dart:async';
|
|
|
|
|
2022-02-03 17:19:25 +08:00
|
|
|
final List<StreamSubscription<MouseEvent>> mouseListeners = [];
|
2022-02-05 04:29:10 +08:00
|
|
|
final List<StreamSubscription<KeyboardEvent>> keyListeners = [];
|
2022-02-03 17:19:25 +08:00
|
|
|
int lastMouseDownButtons = 0;
|
2022-02-05 04:29:10 +08:00
|
|
|
bool mouseIn = false;
|
2022-01-25 18:13:11 +08:00
|
|
|
|
2022-01-26 12:48:16 +08:00
|
|
|
class PlatformFFI {
|
2022-01-25 18:13:11 +08:00
|
|
|
static void clearRgbaFrame() {}
|
|
|
|
|
2022-01-26 12:48:16 +08:00
|
|
|
static Uint8List getRgba() {
|
2022-01-29 15:55:00 +08:00
|
|
|
return js.context.callMethod('getRgba');
|
2022-01-25 18:13:11 +08:00
|
|
|
}
|
|
|
|
|
2022-01-26 19:00:23 +08:00
|
|
|
static Future<String> getVersion() async {
|
2022-01-31 16:22:05 +08:00
|
|
|
return getByName('version');
|
2022-01-26 19:00:23 +08:00
|
|
|
}
|
|
|
|
|
2022-01-26 12:48:16 +08:00
|
|
|
static String getByName(String name, [String arg = '']) {
|
|
|
|
return js.context.callMethod('getByName', [name, arg]);
|
2022-01-25 18:13:11 +08:00
|
|
|
}
|
|
|
|
|
2022-01-26 12:48:16 +08:00
|
|
|
static void setByName(String name, [String value = '']) {
|
|
|
|
js.context.callMethod('setByName', [name, value]);
|
2022-01-25 18:13:11 +08:00
|
|
|
}
|
|
|
|
|
2022-01-26 12:48:16 +08:00
|
|
|
static Future<Null> init() async {
|
|
|
|
isWeb = true;
|
2022-01-31 16:22:05 +08:00
|
|
|
isDesktop = !js.context.callMethod('isMobile');
|
2022-01-26 19:00:23 +08:00
|
|
|
js.context.callMethod('init');
|
2022-01-25 18:13:11 +08:00
|
|
|
}
|
2022-02-03 00:53:59 +08:00
|
|
|
|
|
|
|
// MouseRegion onHover not work for mouse move when right button down
|
|
|
|
static void startDesktopWebListener(
|
|
|
|
Function(Map<String, dynamic>) handleMouse) {
|
2022-02-05 04:29:10 +08:00
|
|
|
mouseIn = true;
|
2022-02-03 17:19:25 +08:00
|
|
|
lastMouseDownButtons = 0;
|
2022-02-03 00:53:59 +08:00
|
|
|
// document.body.getElementsByTagName('flt-glass-pane')[0].style.cursor = 'none';
|
2022-02-05 04:29:10 +08:00
|
|
|
mouseListeners
|
|
|
|
.add(window.document.onMouseEnter.listen((evt) => mouseIn = true));
|
|
|
|
mouseListeners
|
|
|
|
.add(window.document.onMouseLeave.listen((evt) => mouseIn = false));
|
2022-02-03 17:19:25 +08:00
|
|
|
mouseListeners.add(window.document.onMouseMove
|
2022-02-03 00:53:59 +08:00
|
|
|
.listen((evt) => handleMouse(getEvent(evt))));
|
2022-02-03 17:19:25 +08:00
|
|
|
mouseListeners.add(window.document.onMouseDown
|
2022-02-03 00:53:59 +08:00
|
|
|
.listen((evt) => handleMouse(getEvent(evt))));
|
2022-02-03 17:19:25 +08:00
|
|
|
mouseListeners.add(
|
2022-02-03 00:53:59 +08:00
|
|
|
window.document.onMouseUp.listen((evt) => handleMouse(getEvent(evt))));
|
2022-02-03 17:19:25 +08:00
|
|
|
mouseListeners.add(window.document.onMouseWheel.listen((evt) {
|
|
|
|
var dx = evt.deltaX;
|
|
|
|
var dy = evt.deltaY;
|
|
|
|
if (dx > 0)
|
|
|
|
dx = -1;
|
|
|
|
else if (dx < 0) dx = 1;
|
|
|
|
if (dy > 0)
|
|
|
|
dy = -1;
|
|
|
|
else if (dy < 0) dy = 1;
|
|
|
|
setByName('send_mouse', '{"type": "wheel", "x": "$dx", "y": "$dy"}');
|
|
|
|
}));
|
|
|
|
mouseListeners.add(
|
|
|
|
window.document.onContextMenu.listen((evt) => evt.preventDefault()));
|
2022-02-05 04:29:10 +08:00
|
|
|
keyListeners
|
|
|
|
.add(window.document.onKeyDown.listen((evt) => handleKey(evt, true)));
|
|
|
|
keyListeners
|
|
|
|
.add(window.document.onKeyUp.listen((evt) => handleKey(evt, false)));
|
2022-02-03 00:53:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void stopDesktopWebListener() {
|
2022-02-05 04:29:10 +08:00
|
|
|
mouseIn = true;
|
2022-02-03 17:19:25 +08:00
|
|
|
mouseListeners.forEach((l) {
|
2022-02-03 00:53:59 +08:00
|
|
|
l.cancel();
|
|
|
|
});
|
2022-02-03 17:19:25 +08:00
|
|
|
mouseListeners.clear();
|
2022-02-05 04:29:10 +08:00
|
|
|
keyListeners.forEach((l) {
|
|
|
|
l.cancel();
|
|
|
|
});
|
|
|
|
keyListeners.clear();
|
2022-02-03 00:53:59 +08:00
|
|
|
}
|
2022-02-10 02:07:53 +08:00
|
|
|
|
|
|
|
static void setMethodCallHandler(FMethod callback) {}
|
|
|
|
|
|
|
|
static Future<bool> invokeMethod(String method) async {
|
|
|
|
return true;
|
|
|
|
}
|
2022-02-03 00:53:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Map<String, dynamic> getEvent(MouseEvent evt) {
|
|
|
|
// https://github.com/novnc/noVNC/blob/679b45fa3b453c7cf32f4b4455f4814818ecf161/core/rfb.js
|
|
|
|
// https://developer.mozilla.org/zh-CN/docs/Web/API/Element/mousedown_event
|
2022-02-03 17:19:25 +08:00
|
|
|
final Map<String, dynamic> out = {};
|
2022-02-03 00:53:59 +08:00
|
|
|
out['type'] = evt.type;
|
|
|
|
out['x'] = evt.client.x;
|
|
|
|
out['y'] = evt.client.y;
|
2022-02-05 04:29:10 +08:00
|
|
|
if (evt.altKey) out['alt'] = 'true';
|
|
|
|
if (evt.shiftKey) out['shift'] = 'true';
|
|
|
|
if (evt.ctrlKey) out['ctrl'] = 'true';
|
|
|
|
if (evt.metaKey) out['command'] = 'true';
|
2022-02-03 00:53:59 +08:00
|
|
|
out['buttons'] = evt
|
|
|
|
.buttons; // left button: 1, right button: 2, middle button: 4, 1 | 2 = 3 (left + right)
|
2022-02-03 17:19:25 +08:00
|
|
|
if (evt.buttons != 0) {
|
2022-02-17 15:22:14 +08:00
|
|
|
lastMouseDownButtons = evt.buttons!;
|
2022-02-03 17:19:25 +08:00
|
|
|
} else {
|
|
|
|
out['buttons'] = lastMouseDownButtons;
|
|
|
|
}
|
2022-02-03 00:53:59 +08:00
|
|
|
return out;
|
2022-01-25 18:13:11 +08:00
|
|
|
}
|
|
|
|
|
2022-02-05 04:29:10 +08:00
|
|
|
void handleKey(KeyboardEvent evt, bool down) {
|
|
|
|
if (!mouseIn) return;
|
|
|
|
evt.stopPropagation();
|
|
|
|
evt.preventDefault();
|
|
|
|
evt.stopImmediatePropagation();
|
|
|
|
print('${evt.code} ${evt.key} ${evt.location}');
|
|
|
|
final out = {};
|
|
|
|
var name = ctrlKeyMap[evt.code];
|
|
|
|
if (name == null) {
|
|
|
|
if (evt.code == evt.key) {
|
|
|
|
name = evt.code;
|
|
|
|
} else {
|
|
|
|
name = evt.key;
|
2022-02-17 15:22:14 +08:00
|
|
|
if (name!=null && name.toLowerCase() != name.toUpperCase() &&
|
2022-02-05 04:29:10 +08:00
|
|
|
name == name.toUpperCase()) {
|
|
|
|
if (!evt.shiftKey) out['shift'] = 'true';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out['name'] = name;
|
|
|
|
if (evt.altKey) out['alt'] = 'true';
|
|
|
|
if (evt.shiftKey) out['shift'] = 'true';
|
|
|
|
if (evt.ctrlKey) out['ctrl'] = 'true';
|
|
|
|
if (evt.metaKey) out['command'] = 'true';
|
|
|
|
if (down) out['down'] = 'true';
|
|
|
|
PlatformFFI.setByName('input_key', json.encode(out));
|
|
|
|
}
|
|
|
|
|
2022-02-03 00:53:59 +08:00
|
|
|
final localeName = window.navigator.language;
|
2022-02-05 04:29:10 +08:00
|
|
|
|
|
|
|
final ctrlKeyMap = {
|
|
|
|
'AltLeft': 'Alt',
|
|
|
|
'AltRight': 'RAlt',
|
|
|
|
'ShiftLeft': 'Shift',
|
|
|
|
'ShiftRight': 'RShift',
|
|
|
|
'ControlLeft': 'Control',
|
|
|
|
'ControlRight': 'RControl',
|
|
|
|
'MetaLeft': 'Meta',
|
|
|
|
'MetaRight': 'RWin',
|
|
|
|
'ContextMenu': 'Apps',
|
|
|
|
'ArrowUp': 'UpArrow',
|
|
|
|
'ArrowDown': 'DownArrow',
|
|
|
|
'ArrowLeft': 'LeftArrow',
|
|
|
|
'ArrowRight': 'RightArrow',
|
|
|
|
'NumpadDecimal': 'Decimal',
|
|
|
|
'NumpadDivide': 'Divide',
|
|
|
|
'NumpadMultiply': 'Multiply',
|
|
|
|
'NumpadSubtract': 'Subtract',
|
|
|
|
'NumpadAdd': 'Add',
|
|
|
|
'NumpadEnter': 'NumpadEnter',
|
|
|
|
'Enter': 'Return',
|
|
|
|
'Space': 'Space',
|
2022-02-06 16:29:56 +08:00
|
|
|
'NumpadClear': 'Clear',
|
|
|
|
'NumpadBackspace': 'Backspace',
|
|
|
|
'PrintScreen': 'Snapshot',
|
|
|
|
'HangulMode': 'Hangul',
|
|
|
|
'HanjaMode': 'Hanja',
|
|
|
|
'KanaMode': 'Kana',
|
|
|
|
'JunjaMode': 'Junja',
|
|
|
|
'KanjiMode': 'Hanja',
|
2022-02-05 04:29:10 +08:00
|
|
|
};
|