mirror of
https://github.com/jonasbark/swiftcontrol.git
synced 2026-02-18 00:17:40 +01:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0dcb666bbd | ||
|
|
00ebca7a01 | ||
|
|
f9c8820303 | ||
|
|
3d414edda9 | ||
|
|
0e3f6f1d5e | ||
|
|
c4b0ef38c0 | ||
|
|
2e800bb2de | ||
|
|
505b970497 | ||
|
|
986bfd481c | ||
|
|
ab8d480a01 | ||
|
|
7e19b76403 | ||
|
|
cbc2f103ac |
@@ -1,3 +1,8 @@
|
||||
### 1.1.7 (2025-04-01)
|
||||
- Zwift Ride: fix connection issues by connecting only to the left controller
|
||||
- Windows: connect sequentially to fix (finally?) fix connection issues
|
||||
- Windows: change the way keyboard is simulated, should fix glitches
|
||||
|
||||
### 1.1.6 (2025-03-31)
|
||||
- Zwift Ride: add buttonPowerDown to shift gears
|
||||
- Zwift Play: Fix buttonShift assignment
|
||||
|
||||
@@ -30,7 +30,7 @@ Get the latest version here: https://github.com/jonasbark/swiftcontrol/releases
|
||||
## Supported Platforms
|
||||
- Android
|
||||
- macOS
|
||||
- Windows
|
||||
- Windows (make sure you have installed the "[Microsoft Visual C++ Runtime libraries](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170)")
|
||||
- [Web](https://jonasbark.github.io/swiftcontrol/) (you won't be able to do much)
|
||||
|
||||
## How does it work?
|
||||
|
||||
12
keypress_simulator/.clang-format
Normal file
12
keypress_simulator/.clang-format
Normal file
@@ -0,0 +1,12 @@
|
||||
# Defines the Chromium style for automatic reformatting.
|
||||
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
BasedOnStyle: Chromium
|
||||
# This defaults to 'Auto'. Explicitly set it for a while, so that
|
||||
# 'vector<vector<int> >' in existing files gets formatted to
|
||||
# 'vector<vector<int>>'. ('Auto' means that clang-format will only use
|
||||
# 'int>>' if the file already contains at least one such instance.)
|
||||
Standard: Cpp11
|
||||
SortIncludes: true
|
||||
---
|
||||
Language: ObjC
|
||||
ColumnLimit: 100
|
||||
1
keypress_simulator/.github/FUNDING.yml
vendored
Normal file
1
keypress_simulator/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
liberapay: lijy91
|
||||
50
keypress_simulator/.github/workflows/build.yml
vendored
Normal file
50
keypress_simulator/.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: "3.16.8"
|
||||
channel: "stable"
|
||||
- uses: bluefireteam/melos-action@v2
|
||||
- working-directory: ./packages/keypress_simulator/example
|
||||
run: |
|
||||
melos bs
|
||||
flutter build macos --release
|
||||
|
||||
build-web:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: "3.16.8"
|
||||
channel: "stable"
|
||||
- uses: bluefireteam/melos-action@v2
|
||||
- working-directory: ./packages/keypress_simulator/example
|
||||
run: |
|
||||
melos bs
|
||||
flutter build web --release
|
||||
|
||||
build-windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: "3.16.8"
|
||||
channel: "stable"
|
||||
- uses: bluefireteam/melos-action@v2
|
||||
- working-directory: ./packages/keypress_simulator/example
|
||||
run: |
|
||||
melos bs
|
||||
flutter build windows --release
|
||||
31
keypress_simulator/.github/workflows/lint.yml
vendored
Normal file
31
keypress_simulator/.github/workflows/lint.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: lint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: "3.16.8"
|
||||
channel: "stable"
|
||||
- uses: bluefireteam/melos-action@v2
|
||||
- run: melos run analyze
|
||||
|
||||
format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: "3.16.8"
|
||||
channel: "stable"
|
||||
cache: true
|
||||
- uses: bluefireteam/melos-action@v2
|
||||
- run: melos run format-check
|
||||
20
keypress_simulator/.github/workflows/test.yml
vendored
Normal file
20
keypress_simulator/.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: "3.16.8"
|
||||
channel: "stable"
|
||||
cache: true
|
||||
- uses: bluefireteam/melos-action@v2
|
||||
- run: melos run test --no-select
|
||||
6
keypress_simulator/.gitignore
vendored
Normal file
6
keypress_simulator/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
.dart_tool/
|
||||
.idea/
|
||||
|
||||
*.iml
|
||||
pubspec_overrides.yaml
|
||||
pubspec.lock
|
||||
21
keypress_simulator/LICENSE
Normal file
21
keypress_simulator/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022-2024 LiJianying <lijy91@foxmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
93
keypress_simulator/README-ZH.md
Normal file
93
keypress_simulator/README-ZH.md
Normal file
@@ -0,0 +1,93 @@
|
||||
> **🚀 快速发布您的应用**: 试试 [Fastforge](https://fastforge.dev) - 构建、打包和分发您的 Flutter 应用最简单的方式。
|
||||
|
||||
# keypress_simulator
|
||||
|
||||
[![pub version][pub-image]][pub-url] [![][discord-image]][discord-url]
|
||||
|
||||
[pub-image]: https://img.shields.io/pub/v/keypress_simulator.svg
|
||||
[pub-url]: https://pub.dev/packages/keypress_simulator
|
||||
[discord-image]: https://img.shields.io/discord/884679008049037342.svg
|
||||
[discord-url]: https://discord.gg/zPa6EZ2jqb
|
||||
|
||||
这个插件允许 Flutter 桌面应用模拟按键操作。
|
||||
|
||||
---
|
||||
|
||||
[English](./README.md) | 简体中文
|
||||
|
||||
---
|
||||
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
|
||||
- [平台支持](#%E5%B9%B3%E5%8F%B0%E6%94%AF%E6%8C%81)
|
||||
- [快速开始](#%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B)
|
||||
- [安装](#%E5%AE%89%E8%A3%85)
|
||||
- [用法](#%E7%94%A8%E6%B3%95)
|
||||
- [谁在用使用它?](#%E8%B0%81%E5%9C%A8%E7%94%A8%E4%BD%BF%E7%94%A8%E5%AE%83)
|
||||
- [许可证](#%E8%AE%B8%E5%8F%AF%E8%AF%81)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
## 平台支持
|
||||
|
||||
| Linux | macOS | Windows |
|
||||
| :---: | :---: | :-----: |
|
||||
| ➖ | ✔️ | ✔️ |
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装
|
||||
|
||||
将此添加到你的软件包的 pubspec.yaml 文件:
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
keypress_simulator: ^0.2.0
|
||||
```
|
||||
|
||||
### 用法
|
||||
|
||||
```dart
|
||||
import 'package:keypress_simulator/keypress_simulator.dart';
|
||||
|
||||
// 1. Simulate pressing ⌘ + C
|
||||
|
||||
// 1.1 Simulate key down
|
||||
await keyPressSimulator.simulateKeyDown(
|
||||
PhysicalKeyboardKey.keyC,
|
||||
[ModifierKey.metaModifier],
|
||||
);
|
||||
|
||||
// 1.2 Simulate key up
|
||||
await keyPressSimulator.simulateKeyUp(
|
||||
PhysicalKeyboardKey.keyC,
|
||||
[ModifierKey.metaModifier],
|
||||
);
|
||||
|
||||
// 2. Simulate long pressing ⌘ + space
|
||||
|
||||
// 2.1. Simulate key down
|
||||
await keyPressSimulator.simulateKeyDown(
|
||||
PhysicalKeyboardKey.space,
|
||||
[ModifierKey.metaModifier],
|
||||
);
|
||||
|
||||
await Future.delayed(const Duration(seconds: 5));
|
||||
|
||||
// 2.2. Simulate key up
|
||||
await keyPressSimulator.simulateKeyUp(
|
||||
PhysicalKeyboardKey.space,
|
||||
[ModifierKey.metaModifier],
|
||||
);
|
||||
```
|
||||
|
||||
> 请看这个插件的示例应用,以了解完整的例子。
|
||||
|
||||
## 谁在用使用它?
|
||||
|
||||
- [Biyi (比译)](https://biyidev.com/) - 一个便捷的翻译和词典应用程序。
|
||||
|
||||
## 许可证
|
||||
|
||||
[MIT](./LICENSE)
|
||||
93
keypress_simulator/README.md
Normal file
93
keypress_simulator/README.md
Normal file
@@ -0,0 +1,93 @@
|
||||
> **🚀 Ship Your App Faster**: Try [Fastforge](https://fastforge.dev) - The simplest way to build, package and distribute your Flutter apps.
|
||||
|
||||
# keypress_simulator
|
||||
|
||||
[![pub version][pub-image]][pub-url] [![][discord-image]][discord-url]
|
||||
|
||||
[pub-image]: https://img.shields.io/pub/v/keypress_simulator.svg
|
||||
[pub-url]: https://pub.dev/packages/keypress_simulator
|
||||
[discord-image]: https://img.shields.io/discord/884679008049037342.svg
|
||||
[discord-url]: https://discord.gg/zPa6EZ2jqb
|
||||
|
||||
This plugin allows Flutter desktop apps to simulate key presses.
|
||||
|
||||
---
|
||||
|
||||
English | [简体中文](./README-ZH.md)
|
||||
|
||||
---
|
||||
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
|
||||
- [Platform Support](#platform-support)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Installation](#installation)
|
||||
- [Usage](#usage)
|
||||
- [Who's using it?](#whos-using-it)
|
||||
- [License](#license)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
## Platform Support
|
||||
|
||||
| Linux | macOS | Windows |
|
||||
| :---: | :---: | :-----: |
|
||||
| ➖ | ✔️ | ✔️ |
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Installation
|
||||
|
||||
Add this to your package's pubspec.yaml file:
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
keypress_simulator: ^0.2.0
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```dart
|
||||
import 'package:keypress_simulator/keypress_simulator.dart';
|
||||
|
||||
// 1. Simulate pressing ⌘ + C
|
||||
|
||||
// 1.1 Simulate key down
|
||||
await keyPressSimulator.simulateKeyDown(
|
||||
PhysicalKeyboardKey.keyC,
|
||||
[ModifierKey.metaModifier],
|
||||
);
|
||||
|
||||
// 1.2 Simulate key up
|
||||
await keyPressSimulator.simulateKeyUp(
|
||||
PhysicalKeyboardKey.keyC,
|
||||
[ModifierKey.metaModifier],
|
||||
);
|
||||
|
||||
// 2. Simulate long pressing ⌘ + space
|
||||
|
||||
// 2.1. Simulate key down
|
||||
await keyPressSimulator.simulateKeyDown(
|
||||
PhysicalKeyboardKey.space,
|
||||
[ModifierKey.metaModifier],
|
||||
);
|
||||
|
||||
await Future.delayed(const Duration(seconds: 5));
|
||||
|
||||
// 2.2. Simulate key up
|
||||
await keyPressSimulator.simulateKeyUp(
|
||||
PhysicalKeyboardKey.space,
|
||||
[ModifierKey.metaModifier],
|
||||
);
|
||||
```
|
||||
|
||||
> Please see the example app of this plugin for a full example.
|
||||
|
||||
## Who's using it?
|
||||
|
||||
- [Biyi (比译)](https://biyidev.com/) - A convenient translation and dictionary app.
|
||||
|
||||
## License
|
||||
|
||||
[MIT](./LICENSE)
|
||||
35
keypress_simulator/melos.yaml
Normal file
35
keypress_simulator/melos.yaml
Normal file
@@ -0,0 +1,35 @@
|
||||
name: keypress_simulator_workspace
|
||||
repository: https://github.com/leanflutter/keypress_simulator
|
||||
|
||||
packages:
|
||||
- examples/**
|
||||
- packages/**
|
||||
|
||||
command:
|
||||
bootstrap:
|
||||
# Uses the pubspec_overrides.yaml instead of having Melos modifying the lock file.
|
||||
usePubspecOverrides: true
|
||||
|
||||
scripts:
|
||||
analyze:
|
||||
exec: flutter analyze --fatal-infos
|
||||
description: Run `flutter analyze` for all packages.
|
||||
|
||||
test:
|
||||
exec: flutter test
|
||||
description: Run `flutter test` for a specific package.
|
||||
packageFilters:
|
||||
dirExists:
|
||||
- test
|
||||
|
||||
format:
|
||||
exec: dart format . --fix
|
||||
description: Run `dart format` for all packages.
|
||||
|
||||
format-check:
|
||||
exec: dart format . --fix --set-exit-if-changed
|
||||
description: Run `dart format` checks for all packages.
|
||||
|
||||
fix:
|
||||
exec: dart fix . --apply
|
||||
description: Run `dart fix` for all packages.
|
||||
29
keypress_simulator/packages/keypress_simulator_windows/.gitignore
vendored
Normal file
29
keypress_simulator/packages/keypress_simulator_windows/.gitignore
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||
/pubspec.lock
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
build/
|
||||
@@ -0,0 +1,30 @@
|
||||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: "67457e669f79e9f8d13d7a68fe09775fefbb79f4"
|
||||
channel: "stable"
|
||||
|
||||
project_type: plugin
|
||||
|
||||
# Tracks metadata for the flutter migrate command
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: 67457e669f79e9f8d13d7a68fe09775fefbb79f4
|
||||
base_revision: 67457e669f79e9f8d13d7a68fe09775fefbb79f4
|
||||
- platform: windows
|
||||
create_revision: 67457e669f79e9f8d13d7a68fe09775fefbb79f4
|
||||
base_revision: 67457e669f79e9f8d13d7a68fe09775fefbb79f4
|
||||
|
||||
# User provided section
|
||||
|
||||
# List of Local paths (relative to this file) that should be
|
||||
# ignored by the migrate tool.
|
||||
#
|
||||
# Files that are not part of the templates will be ignored by default.
|
||||
unmanaged_files:
|
||||
- 'lib/main.dart'
|
||||
- 'ios/Runner.xcodeproj/project.pbxproj'
|
||||
@@ -0,0 +1,3 @@
|
||||
## 0.2.0
|
||||
|
||||
* First release.
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022-2024 LiJianying <lijy91@foxmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,12 @@
|
||||
# keypress_simulator_windows
|
||||
|
||||
[![pub version][pub-image]][pub-url]
|
||||
|
||||
[pub-image]: https://img.shields.io/pub/v/keypress_simulator_windows.svg
|
||||
[pub-url]: https://pub.dev/packages/keypress_simulator_windows
|
||||
|
||||
The Windows implementation of [keypress_simulator](https://pub.dev/packages/keypress_simulator).
|
||||
|
||||
## License
|
||||
|
||||
[MIT](./LICENSE)
|
||||
@@ -0,0 +1 @@
|
||||
include: package:mostly_reasonable_lints/flutter.yaml
|
||||
@@ -0,0 +1,25 @@
|
||||
name: keypress_simulator_windows
|
||||
description: Windows implementation of the keypress_simulator plugin.
|
||||
version: 0.2.0
|
||||
repository: https://github.com/leanflutter/keypress_simulator/tree/main/packages/keypress_simulator_windows
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0 <4.0.0'
|
||||
flutter: '>=3.3.0'
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
keypress_simulator_platform_interface: ^0.2.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
mostly_reasonable_lints: ^0.1.1
|
||||
|
||||
flutter:
|
||||
plugin:
|
||||
implements: keypress_simulator
|
||||
platforms:
|
||||
windows:
|
||||
pluginClass: KeypressSimulatorWindowsPluginCApi
|
||||
17
keypress_simulator/packages/keypress_simulator_windows/windows/.gitignore
vendored
Normal file
17
keypress_simulator/packages/keypress_simulator_windows/windows/.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
flutter/
|
||||
|
||||
# Visual Studio user-specific files.
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# Visual Studio build-related files.
|
||||
x64/
|
||||
x86/
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
@@ -0,0 +1,100 @@
|
||||
# The Flutter tooling requires that developers have a version of Visual Studio
|
||||
# installed that includes CMake 3.14 or later. You should not increase this
|
||||
# version, as doing so will cause the plugin to fail to compile for some
|
||||
# customers of the plugin.
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
# Project-level configuration.
|
||||
set(PROJECT_NAME "keypress_simulator_windows")
|
||||
project(${PROJECT_NAME} LANGUAGES CXX)
|
||||
|
||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
||||
# versions of CMake.
|
||||
cmake_policy(VERSION 3.14...3.25)
|
||||
|
||||
# This value is used when generating builds using this plugin, so it must
|
||||
# not be changed
|
||||
set(PLUGIN_NAME "keypress_simulator_windows_plugin")
|
||||
|
||||
# Any new source files that you add to the plugin should be added here.
|
||||
list(APPEND PLUGIN_SOURCES
|
||||
"keypress_simulator_windows_plugin.cpp"
|
||||
"keypress_simulator_windows_plugin.h"
|
||||
)
|
||||
|
||||
# Define the plugin library target. Its name must not be changed (see comment
|
||||
# on PLUGIN_NAME above).
|
||||
add_library(${PLUGIN_NAME} SHARED
|
||||
"include/keypress_simulator_windows/keypress_simulator_windows_plugin_c_api.h"
|
||||
"keypress_simulator_windows_plugin_c_api.cpp"
|
||||
${PLUGIN_SOURCES}
|
||||
)
|
||||
|
||||
# Apply a standard set of build settings that are configured in the
|
||||
# application-level CMakeLists.txt. This can be removed for plugins that want
|
||||
# full control over build settings.
|
||||
apply_standard_settings(${PLUGIN_NAME})
|
||||
|
||||
# Symbols are hidden by default to reduce the chance of accidental conflicts
|
||||
# between plugins. This should not be removed; any symbols that should be
|
||||
# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro.
|
||||
set_target_properties(${PLUGIN_NAME} PROPERTIES
|
||||
CXX_VISIBILITY_PRESET hidden)
|
||||
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
|
||||
|
||||
# Source include directories and library dependencies. Add any plugin-specific
|
||||
# dependencies here.
|
||||
target_include_directories(${PLUGIN_NAME} INTERFACE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin)
|
||||
|
||||
# List of absolute paths to libraries that should be bundled with the plugin.
|
||||
# This list could contain prebuilt libraries, or libraries created by an
|
||||
# external build triggered from this build file.
|
||||
set(keypress_simulator_windows_bundled_libraries
|
||||
""
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
# === Tests ===
|
||||
# These unit tests can be run from a terminal after building the example, or
|
||||
# from Visual Studio after opening the generated solution file.
|
||||
|
||||
# Only enable test builds when building the example (which sets this variable)
|
||||
# so that plugin clients aren't building the tests.
|
||||
if (${include_${PROJECT_NAME}_tests})
|
||||
set(TEST_RUNNER "${PROJECT_NAME}_test")
|
||||
enable_testing()
|
||||
|
||||
# Add the Google Test dependency.
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
URL https://github.com/google/googletest/archive/release-1.11.0.zip
|
||||
)
|
||||
# Prevent overriding the parent project's compiler/linker settings
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
# Disable install commands for gtest so it doesn't end up in the bundle.
|
||||
set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE)
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
|
||||
# The plugin's C API is not very useful for unit testing, so build the sources
|
||||
# directly into the test binary rather than using the DLL.
|
||||
add_executable(${TEST_RUNNER}
|
||||
test/keypress_simulator_windows_plugin_test.cpp
|
||||
${PLUGIN_SOURCES}
|
||||
)
|
||||
apply_standard_settings(${TEST_RUNNER})
|
||||
target_include_directories(${TEST_RUNNER} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
target_link_libraries(${TEST_RUNNER} PRIVATE flutter_wrapper_plugin)
|
||||
target_link_libraries(${TEST_RUNNER} PRIVATE gtest_main gmock)
|
||||
# flutter_wrapper_plugin has link dependencies on the Flutter DLL.
|
||||
add_custom_command(TARGET ${TEST_RUNNER} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${FLUTTER_LIBRARY}" $<TARGET_FILE_DIR:${TEST_RUNNER}>
|
||||
)
|
||||
|
||||
# Enable automatic test discovery.
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(${TEST_RUNNER})
|
||||
endif()
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef FLUTTER_PLUGIN_KEYPRESS_SIMULATOR_WINDOWS_PLUGIN_C_API_H_
|
||||
#define FLUTTER_PLUGIN_KEYPRESS_SIMULATOR_WINDOWS_PLUGIN_C_API_H_
|
||||
|
||||
#include <flutter_plugin_registrar.h>
|
||||
|
||||
#ifdef FLUTTER_PLUGIN_IMPL
|
||||
#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void KeypressSimulatorWindowsPluginCApiRegisterWithRegistrar(
|
||||
FlutterDesktopPluginRegistrarRef registrar);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // FLUTTER_PLUGIN_KEYPRESS_SIMULATOR_WINDOWS_PLUGIN_C_API_H_
|
||||
@@ -0,0 +1,98 @@
|
||||
#include "keypress_simulator_windows_plugin.h"
|
||||
|
||||
// This must be included before many other Windows headers.
|
||||
#include <windows.h>
|
||||
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
#include <flutter/standard_method_codec.h>
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
using flutter::EncodableList;
|
||||
using flutter::EncodableMap;
|
||||
using flutter::EncodableValue;
|
||||
|
||||
namespace keypress_simulator_windows {
|
||||
|
||||
// static
|
||||
void KeypressSimulatorWindowsPlugin::RegisterWithRegistrar(
|
||||
flutter::PluginRegistrarWindows* registrar) {
|
||||
auto channel =
|
||||
std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
|
||||
registrar->messenger(), "dev.leanflutter.plugins/keypress_simulator",
|
||||
&flutter::StandardMethodCodec::GetInstance());
|
||||
|
||||
auto plugin = std::make_unique<KeypressSimulatorWindowsPlugin>();
|
||||
|
||||
channel->SetMethodCallHandler(
|
||||
[plugin_pointer = plugin.get()](const auto& call, auto result) {
|
||||
plugin_pointer->HandleMethodCall(call, std::move(result));
|
||||
});
|
||||
|
||||
registrar->AddPlugin(std::move(plugin));
|
||||
}
|
||||
|
||||
KeypressSimulatorWindowsPlugin::KeypressSimulatorWindowsPlugin() {}
|
||||
|
||||
KeypressSimulatorWindowsPlugin::~KeypressSimulatorWindowsPlugin() {}
|
||||
|
||||
void KeypressSimulatorWindowsPlugin::SimulateKeyPress(
|
||||
const flutter::MethodCall<flutter::EncodableValue>& method_call,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
|
||||
const EncodableMap& args = std::get<EncodableMap>(*method_call.arguments());
|
||||
|
||||
UINT keyCode = std::get<int>(args.at(EncodableValue("keyCode")));
|
||||
std::vector<std::string> modifiers;
|
||||
bool keyDown = std::get<bool>(args.at(EncodableValue("keyDown")));
|
||||
|
||||
EncodableList key_modifier_list =
|
||||
std::get<EncodableList>(args.at(EncodableValue("modifiers")));
|
||||
for (flutter::EncodableValue key_modifier_value : key_modifier_list) {
|
||||
std::string key_modifier = std::get<std::string>(key_modifier_value);
|
||||
modifiers.push_back(key_modifier);
|
||||
}
|
||||
|
||||
INPUT input[6];
|
||||
|
||||
for (int32_t i = 0; i < modifiers.size(); i++) {
|
||||
if (modifiers[i].compare("shiftModifier") == 0) {
|
||||
input[i].ki.wVk = VK_SHIFT;
|
||||
} else if (modifiers[i].compare("controlModifier") == 0) {
|
||||
input[i].ki.wVk = VK_CONTROL;
|
||||
} else if (modifiers[i].compare("altModifier") == 0) {
|
||||
input[i].ki.wVk = VK_MENU;
|
||||
} else if (modifiers[i].compare("metaModifier") == 0) {
|
||||
input[i].ki.wVk = VK_LWIN;
|
||||
}
|
||||
|
||||
input[i].ki.dwFlags = keyDown ? 0 : KEYEVENTF_KEYUP;
|
||||
input[i].type = INPUT_KEYBOARD;
|
||||
}
|
||||
|
||||
/*int keyIndex = static_cast<int>(modifiers.size());
|
||||
input[keyIndex].ki.wVk = static_cast<WORD>(keyCode);
|
||||
input[keyIndex].ki.dwFlags = keyDown ? 0 : KEYEVENTF_KEYUP;
|
||||
input[keyIndex].type = INPUT_KEYBOARD;*/
|
||||
|
||||
// Send key sequence to system
|
||||
//SendInput(static_cast<UINT>(std::size(input)), input, sizeof(INPUT));
|
||||
|
||||
BYTE byteValue = static_cast<BYTE>(keyCode);
|
||||
keybd_event(byteValue, 0x45, keyDown ? 0 : KEYEVENTF_KEYUP, 0);
|
||||
|
||||
result->Success(flutter::EncodableValue(true));
|
||||
}
|
||||
|
||||
void KeypressSimulatorWindowsPlugin::HandleMethodCall(
|
||||
const flutter::MethodCall<flutter::EncodableValue>& method_call,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
|
||||
if (method_call.method_name().compare("simulateKeyPress") == 0) {
|
||||
SimulateKeyPress(method_call, std::move(result));
|
||||
} else {
|
||||
result->NotImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace keypress_simulator_windows
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef FLUTTER_PLUGIN_KEYPRESS_SIMULATOR_WINDOWS_PLUGIN_H_
|
||||
#define FLUTTER_PLUGIN_KEYPRESS_SIMULATOR_WINDOWS_PLUGIN_H_
|
||||
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace keypress_simulator_windows {
|
||||
|
||||
class KeypressSimulatorWindowsPlugin : public flutter::Plugin {
|
||||
public:
|
||||
static void RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar);
|
||||
|
||||
KeypressSimulatorWindowsPlugin();
|
||||
|
||||
virtual ~KeypressSimulatorWindowsPlugin();
|
||||
|
||||
// Disallow copy and assign.
|
||||
KeypressSimulatorWindowsPlugin(const KeypressSimulatorWindowsPlugin&) =
|
||||
delete;
|
||||
KeypressSimulatorWindowsPlugin& operator=(
|
||||
const KeypressSimulatorWindowsPlugin&) = delete;
|
||||
|
||||
void KeypressSimulatorWindowsPlugin::SimulateKeyPress(
|
||||
const flutter::MethodCall<flutter::EncodableValue>& method_call,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
|
||||
|
||||
// Called when a method is called on this plugin's channel from Dart.
|
||||
void HandleMethodCall(
|
||||
const flutter::MethodCall<flutter::EncodableValue>& method_call,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
|
||||
};
|
||||
|
||||
} // namespace keypress_simulator_windows
|
||||
|
||||
#endif // FLUTTER_PLUGIN_KEYPRESS_SIMULATOR_WINDOWS_PLUGIN_H_
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "include/keypress_simulator_windows/keypress_simulator_windows_plugin_c_api.h"
|
||||
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
|
||||
#include "keypress_simulator_windows_plugin.h"
|
||||
|
||||
void KeypressSimulatorWindowsPluginCApiRegisterWithRegistrar(
|
||||
FlutterDesktopPluginRegistrarRef registrar) {
|
||||
keypress_simulator_windows::KeypressSimulatorWindowsPlugin::RegisterWithRegistrar(
|
||||
flutter::PluginRegistrarManager::GetInstance()
|
||||
->GetRegistrar<flutter::PluginRegistrarWindows>(registrar));
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#include <flutter/method_call.h>
|
||||
#include <flutter/method_result_functions.h>
|
||||
#include <flutter/standard_method_codec.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include "keypress_simulator_windows_plugin.h"
|
||||
|
||||
namespace keypress_simulator_windows {
|
||||
namespace test {
|
||||
|
||||
namespace {
|
||||
|
||||
using flutter::EncodableMap;
|
||||
using flutter::EncodableValue;
|
||||
using flutter::MethodCall;
|
||||
using flutter::MethodResultFunctions;
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(KeypressSimulatorWindowsPlugin, GetPlatformVersion) {
|
||||
KeypressSimulatorWindowsPlugin plugin;
|
||||
// Save the reply value from the success callback.
|
||||
std::string result_string;
|
||||
plugin.HandleMethodCall(
|
||||
MethodCall("getPlatformVersion", std::make_unique<EncodableValue>()),
|
||||
std::make_unique<MethodResultFunctions<>>(
|
||||
[&result_string](const EncodableValue* result) {
|
||||
result_string = std::get<std::string>(*result);
|
||||
},
|
||||
nullptr, nullptr));
|
||||
|
||||
// Since the exact string varies by host, just ensure that it's a string
|
||||
// with the expected format.
|
||||
EXPECT_TRUE(result_string.rfind("Windows ", 0) == 0);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace keypress_simulator_windows
|
||||
9
keypress_simulator/pubspec.yaml
Normal file
9
keypress_simulator/pubspec.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
name: keypress_simulator_workspace
|
||||
homepage: https://github.com/leanflutter/keypress_simulator
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
|
||||
dev_dependencies:
|
||||
melos: ^3.1.0
|
||||
@@ -15,6 +15,9 @@ class Connection {
|
||||
final devices = <BaseDevice>[];
|
||||
var androidNotificationsSetup = false;
|
||||
|
||||
final _connectionQueue = <BaseDevice>[];
|
||||
var _handlingConnectionQueue = false;
|
||||
|
||||
final Map<BaseDevice, StreamSubscription<BaseNotification>> _streamSubscriptions = {};
|
||||
final StreamController<BaseNotification> _actionStreams = StreamController<BaseNotification>.broadcast();
|
||||
Stream<BaseNotification> get actionStream => _actionStreams.stream;
|
||||
@@ -31,7 +34,7 @@ class Connection {
|
||||
UniversalBle.onScanResult = (result) {
|
||||
if (_lastScanResult.none((e) => e.deviceId == result.deviceId)) {
|
||||
_lastScanResult.add(result);
|
||||
_actionStreams.add(LogNotification('Found new devices: ${result.name}'));
|
||||
_actionStreams.add(LogNotification('Found new device: ${result.name}'));
|
||||
final scanResult = BaseDevice.fromScanResult(result);
|
||||
if (scanResult != null) {
|
||||
_addDevices([scanResult]);
|
||||
@@ -57,7 +60,7 @@ class Connection {
|
||||
if (!kIsWeb && !Platform.isWindows) {
|
||||
UniversalBle.getSystemDevices(
|
||||
withServices: [BleUuid.ZWIFT_CUSTOM_SERVICE_UUID, BleUuid.ZWIFT_RIDE_CUSTOM_SERVICE_UUID],
|
||||
).then((devices) {
|
||||
).then((devices) async {
|
||||
final baseDevices = devices.mapNotNull(BaseDevice.fromScanResult).toList();
|
||||
if (baseDevices.isNotEmpty) {
|
||||
_addDevices(baseDevices);
|
||||
@@ -81,9 +84,8 @@ class Connection {
|
||||
final newDevices = dev.where((device) => !devices.contains(device)).toList();
|
||||
devices.addAll(newDevices);
|
||||
|
||||
for (final device in newDevices) {
|
||||
_connect(device).then((_) {});
|
||||
}
|
||||
_connectionQueue.addAll(newDevices);
|
||||
_handleConnectionQueue();
|
||||
|
||||
hasDevices.value = devices.isNotEmpty;
|
||||
if (devices.isNotEmpty && !androidNotificationsSetup && !kIsWeb && Platform.isAndroid) {
|
||||
@@ -95,6 +97,30 @@ class Connection {
|
||||
}
|
||||
}
|
||||
|
||||
void _handleConnectionQueue() {
|
||||
// windows apparently has issues when connecting to multiple devices at once, so don't
|
||||
if (_connectionQueue.isNotEmpty && !_handlingConnectionQueue) {
|
||||
_handlingConnectionQueue = true;
|
||||
final device = _connectionQueue.removeAt(0);
|
||||
_actionStreams.add(LogNotification('Connecting to: ${device.device.name ?? device.runtimeType}'));
|
||||
_connect(device)
|
||||
.then((_) {
|
||||
_handlingConnectionQueue = false;
|
||||
_actionStreams.add(LogNotification('Connection finished: ${device.device.name ?? device.runtimeType}'));
|
||||
if (_connectionQueue.isNotEmpty) {
|
||||
_handleConnectionQueue();
|
||||
}
|
||||
})
|
||||
.catchError((e) {
|
||||
_handlingConnectionQueue = false;
|
||||
_actionStreams.add(LogNotification('Connection failed: ${device.device.name ?? device.runtimeType} - $e'));
|
||||
if (_connectionQueue.isNotEmpty) {
|
||||
_handleConnectionQueue();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _connect(BaseDevice bleDevice) async {
|
||||
try {
|
||||
final actionSubscription = bleDevice.actionStream.listen((data) {
|
||||
|
||||
@@ -30,7 +30,8 @@ abstract class BaseDevice {
|
||||
static BaseDevice? fromScanResult(BleDevice scanResult) {
|
||||
// Use the name first as the "System Devices" and Web (android sometimes Windows) don't have manufacturer data
|
||||
final device = switch (scanResult.name) {
|
||||
'Zwift Ride' => ZwiftRide(scanResult),
|
||||
//'Zwift Ride' => ZwiftRide(scanResult), special case for Zwift Ride: we must only connect to the left controller
|
||||
// https://www.makinolo.com/blog/2024/07/26/zwift-ride-protocol/
|
||||
'Zwift Play' => ZwiftPlay(scanResult),
|
||||
'Zwift Click' => ZwiftClick(scanResult),
|
||||
_ => null,
|
||||
@@ -52,7 +53,7 @@ abstract class BaseDevice {
|
||||
DeviceType.click => ZwiftClick(scanResult),
|
||||
DeviceType.playRight => ZwiftPlay(scanResult),
|
||||
DeviceType.playLeft => ZwiftPlay(scanResult),
|
||||
DeviceType.rideRight => ZwiftRide(scanResult),
|
||||
//DeviceType.rideRight => ZwiftRide(scanResult), // see comment above
|
||||
DeviceType.rideLeft => ZwiftRide(scanResult),
|
||||
_ => null,
|
||||
};
|
||||
|
||||
@@ -27,12 +27,12 @@ class ZwiftRide extends BaseDevice {
|
||||
if (clickNotification.buttonShiftDownLeft ||
|
||||
clickNotification.buttonShiftUpLeft ||
|
||||
clickNotification.buttonOnOffLeft ||
|
||||
clickNotification.buttonPowerDownLeft) {
|
||||
clickNotification.buttonPowerUpLeft) {
|
||||
actionHandler.decreaseGear();
|
||||
} else if (clickNotification.buttonShiftUpRight ||
|
||||
clickNotification.buttonShiftDownRight ||
|
||||
clickNotification.buttonOnOffRight ||
|
||||
clickNotification.buttonPowerUpLeft) {
|
||||
clickNotification.buttonPowerUpRight) {
|
||||
actionHandler.increaseGear();
|
||||
}
|
||||
/*if (clickNotification.buttonA) {
|
||||
|
||||
@@ -36,7 +36,7 @@ class RideNotification extends BaseNotification {
|
||||
late bool buttonA, buttonB, buttonY, buttonZ;
|
||||
late bool buttonShiftUpLeft, buttonShiftDownLeft;
|
||||
late bool buttonShiftUpRight, buttonShiftDownRight;
|
||||
late bool buttonPowerUpLeft, buttonPowerDownLeft;
|
||||
late bool buttonPowerUpLeft, buttonPowerUpRight;
|
||||
late bool buttonOnOffLeft, buttonOnOffRight;
|
||||
|
||||
int analogLR = 0, analogUD = 0;
|
||||
@@ -57,7 +57,7 @@ class RideNotification extends BaseNotification {
|
||||
buttonShiftUpRight = status.buttonMap & _RideButtonMask.SHFT_UP_R_BTN.mask == BTN_PRESSED;
|
||||
buttonShiftDownRight = status.buttonMap & _RideButtonMask.SHFT_DN_R_BTN.mask == BTN_PRESSED;
|
||||
buttonPowerUpLeft = status.buttonMap & _RideButtonMask.POWERUP_L_BTN.mask == BTN_PRESSED;
|
||||
buttonPowerDownLeft = status.buttonMap & _RideButtonMask.POWERUP_R_BTN.mask == BTN_PRESSED;
|
||||
buttonPowerUpRight = status.buttonMap & _RideButtonMask.POWERUP_R_BTN.mask == BTN_PRESSED;
|
||||
buttonOnOffLeft = status.buttonMap & _RideButtonMask.ONOFF_L_BTN.mask == BTN_PRESSED;
|
||||
buttonOnOffRight = status.buttonMap & _RideButtonMask.ONOFF_R_BTN.mask == BTN_PRESSED;
|
||||
|
||||
@@ -86,7 +86,7 @@ class RideNotification extends BaseNotification {
|
||||
if (buttonShiftUpRight) 'buttonShiftUpRight',
|
||||
if (buttonShiftDownRight) 'buttonShiftDownRight',
|
||||
if (buttonPowerUpLeft) 'buttonPowerUpLeft',
|
||||
if (buttonPowerDownLeft) 'buttonPowerDownLeft',
|
||||
if (buttonPowerUpRight) 'buttonPowerUpRight',
|
||||
if (buttonOnOffLeft) 'buttonOnOffLeft',
|
||||
if (buttonOnOffRight) 'buttonOnOffRight',
|
||||
];
|
||||
@@ -111,7 +111,7 @@ class RideNotification extends BaseNotification {
|
||||
buttonShiftUpRight == other.buttonShiftUpRight &&
|
||||
buttonShiftDownRight == other.buttonShiftDownRight &&
|
||||
buttonPowerUpLeft == other.buttonPowerUpLeft &&
|
||||
buttonPowerDownLeft == other.buttonPowerDownLeft &&
|
||||
buttonPowerUpRight == other.buttonPowerUpRight &&
|
||||
buttonOnOffLeft == other.buttonOnOffLeft &&
|
||||
buttonOnOffRight == other.buttonOnOffRight &&
|
||||
analogLR == other.analogLR &&
|
||||
@@ -132,7 +132,7 @@ class RideNotification extends BaseNotification {
|
||||
buttonShiftUpRight.hashCode ^
|
||||
buttonShiftDownRight.hashCode ^
|
||||
buttonPowerUpLeft.hashCode ^
|
||||
buttonPowerDownLeft.hashCode ^
|
||||
buttonPowerUpRight.hashCode ^
|
||||
buttonOnOffLeft.hashCode ^
|
||||
buttonOnOffRight.hashCode ^
|
||||
analogLR.hashCode ^
|
||||
|
||||
@@ -61,7 +61,7 @@ class _DevicePageState extends State<DevicePage> {
|
||||
children: [
|
||||
Text(
|
||||
'Devices:\n${connection.devices.joinToString(separator: '\n', transform: (it) {
|
||||
return "${it.device.name}: ${it.isConnected ? 'Connected' : 'Not connected'}";
|
||||
return "${it.device.name ?? it.runtimeType}: ${it.isConnected ? 'Connected' : 'Not connected'}";
|
||||
})}',
|
||||
),
|
||||
Divider(color: Theme.of(context).colorScheme.primary, height: 30),
|
||||
|
||||
@@ -30,7 +30,9 @@ class _ScanWidgetState extends State<ScanWidget> {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
// must be called from a button
|
||||
if (!kIsWeb) {
|
||||
connection.performScanning();
|
||||
Future.delayed(Duration(seconds: 1)).then((_) {
|
||||
connection.performScanning();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -408,12 +408,11 @@ packages:
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
keypress_simulator_windows:
|
||||
dependency: transitive
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
name: keypress_simulator_windows
|
||||
sha256: b4ff055131a2e5ea920eb3b6a185e1889fe00749b027df3b83aa726ed590a9b5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
path: "keypress_simulator/packages/keypress_simulator_windows"
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.2.0"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: swift_control
|
||||
description: "SwiftControl - Control your virtual riding"
|
||||
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
version: 1.1.6+0
|
||||
version: 1.1.7+0
|
||||
|
||||
environment:
|
||||
sdk: ^3.7.0
|
||||
@@ -18,7 +18,7 @@ dependencies:
|
||||
dartx: any
|
||||
image_picker: ^1.1.2
|
||||
pointycastle: any
|
||||
keypress_simulator: ^0.2.0
|
||||
keypress_simulator: any
|
||||
shared_preferences: ^2.5.3
|
||||
flex_color_scheme: ^8.2.0
|
||||
package_info_plus: ^8.3.0
|
||||
@@ -26,6 +26,10 @@ dependencies:
|
||||
path: accessibility
|
||||
http: ^1.3.0
|
||||
|
||||
dependency_overrides:
|
||||
keypress_simulator_windows:
|
||||
path: keypress_simulator/packages/keypress_simulator_windows
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
Reference in New Issue
Block a user