|
1 | | -<!-- |
2 | | -This README describes the package. If you publish this package to pub.dev, |
3 | | -this README's contents appear on the landing page for your package. |
| 1 | +Control |
| 2 | +[`virtual-display-rs`](https://github.com/MolotovCherry/virtual-display-rs) |
| 3 | +using Dart, to create and manage virtual monitors on Windows. |
4 | 4 |
|
5 | | -For information about how to write a good package README, see the guide for |
6 | | -[writing package pages](https://dart.dev/guides/libraries/writing-package-pages). |
| 5 | +`virtual-display-rs` uses windows named pipes to connect to the driver. |
7 | 6 |
|
8 | | -For general information about developing packages, see the Dart guide for |
9 | | -[creating packages](https://dart.dev/guides/libraries/create-library-packages) |
10 | | -and the Flutter guide for |
11 | | -[developing packages and plugins](https://flutter.dev/developing-packages). |
12 | | ---> |
13 | | - |
14 | | -TODO: Put a short description of the package here that helps potential users |
15 | | -know whether this package might be useful for them. |
| 7 | +> Note: This package uses [native |
| 8 | +> assets](https://github.com/dart-lang/sdk/issues/50565), which are not yet |
| 9 | +> stable. To use this package, you must enable it using the |
| 10 | +> `--enable-experiment=native-assets` as the first flag on every dart command, |
| 11 | +> or, when using flutter, enable it in the flutter config using `flutter config |
| 12 | +> --enable-native-assets`. |
16 | 13 |
|
17 | 14 | ## Features |
18 | 15 |
|
19 | | -TODO: List what your package can do. Maybe include images, gifs, or videos. |
| 16 | +- Add/Remove/Change virtual monitors |
| 17 | +- Add/Remove/Change monitor resolutions and framerate |
| 18 | +- Persist driver state across restarts |
| 19 | +- Get continues state updates from the driver, no matter why it changed |
20 | 20 |
|
21 | 21 | ## Getting started |
22 | 22 |
|
23 | | -TODO: List prerequisites and provide or point to information on how to |
24 | | -start using the package. |
| 23 | +1. [Install the driver](https://github.com/MolotovCherry/virtual-display-rs?tab=readme-ov-file#how-to-install) |
| 24 | +2. Install Rust using [rustup](https://www.rust-lang.org/learn/get-started) |
| 25 | +3. Add dependency to `pubspec.yaml`: |
| 26 | + |
| 27 | +```yaml |
| 28 | +dependencies: |
| 29 | + vdd: |
| 30 | + git: |
| 31 | + url: https://github.com/MolotovCherry/virtual-display-rs.git |
| 32 | + ref: master |
| 33 | + path: rust/bindings/dart |
| 34 | +``` |
25 | 35 |
|
26 | 36 | ## Usage |
27 | 37 |
|
28 | | -TODO: Include short and useful examples for package users. Add longer examples |
29 | | -to `/example` folder. |
| 38 | +Import the relevant packages: |
| 39 | +
|
| 40 | +```dart |
| 41 | +import 'package:vdd/vdd.dart' as vdd; |
| 42 | + |
| 43 | +// Imports all errors, that might be thrown by dart_vdd |
| 44 | +import 'package:vdd/errors.dart' as vdd; |
| 45 | +``` |
| 46 | + |
| 47 | +### Initialization |
| 48 | + |
| 49 | +Before using the driver, `vdd` must be initialized: |
| 50 | + |
| 51 | +```dart |
| 52 | +await vdd.init(); |
| 53 | +``` |
| 54 | + |
| 55 | +There are two clients with a different level of abstraction. |
| 56 | + |
| 57 | +### `Client` |
| 58 | + |
| 59 | +This client does not manage its own state. |
30 | 60 |
|
31 | 61 | ```dart |
32 | | -const like = 'sample'; |
| 62 | +// Connect to driver using the default named pipe |
| 63 | +final client = await vdd.Client.connect(); |
| 64 | +
|
| 65 | +// Listen to all state changes |
| 66 | +client.receiveEvents().listen((monitors) { |
| 67 | + print("Driver state changed: $monitors"); |
| 68 | +}); |
| 69 | +
|
| 70 | +final monitors = [ |
| 71 | + vdd.Monitor( |
| 72 | + id: 0, |
| 73 | + enabled: true, |
| 74 | + modes: [ |
| 75 | + vdd.Mode( |
| 76 | + width: 1920, |
| 77 | + height: 1080, |
| 78 | + refreshRates: Uint32List.fromList([60, 120]), |
| 79 | + ), |
| 80 | + ], |
| 81 | + ), |
| 82 | +]; |
| 83 | +
|
| 84 | +// Override driver state with new monitor |
| 85 | +await client.notify(monitors: monitors); |
| 86 | +
|
| 87 | +// Make this state persistent across restarts |
| 88 | +await vdd.Client.persist(monitors: monitors); |
| 89 | +``` |
| 90 | + |
| 91 | +### `DriverClient` |
| 92 | + |
| 93 | +This client manages its own state, separate from the driver. This state might |
| 94 | +become stale. To refresh it, call `DriverClient.refreshState`. To apply state |
| 95 | +changes to the driver, call `DriverClient.notify`. |
| 96 | + |
| 97 | +```dart |
| 98 | +// Connect to the driver, using the default pipe name |
| 99 | +final client = await vdd.DriverClient.connect(); |
| 100 | +
|
| 101 | +// Listen to all state changes |
| 102 | +client.receiveEvents().listen((monitors) async { |
| 103 | + print("Driver state changed: $monitors"); |
| 104 | +
|
| 105 | + // Refresh local state when driver state changes |
| 106 | + await client.refreshState(); |
| 107 | +}); |
| 108 | +
|
| 109 | +print("Current driver state: ${client.state}"); |
| 110 | +
|
| 111 | +// Get a free id for a new monitor |
| 112 | +final monitorId = client.newId()!; |
| 113 | +
|
| 114 | +// Add a new monitor |
| 115 | +client.add( |
| 116 | + monitor: vdd.Monitor( |
| 117 | + id: monitorId, |
| 118 | + enabled: true, |
| 119 | + modes: [ |
| 120 | + vdd.Mode( |
| 121 | + width: 1920, |
| 122 | + height: 1080, |
| 123 | + refreshRates: Uint32List.fromList([60, 120]), |
| 124 | + ), |
| 125 | + ], |
| 126 | + ), |
| 127 | +); |
| 128 | +
|
| 129 | +// Apply changes to the driver |
| 130 | +await client.notify(); |
| 131 | +
|
| 132 | +// Make changes persistent across restarts |
| 133 | +await client.persist(); |
| 134 | +``` |
| 135 | + |
| 136 | +## Testing |
| 137 | + |
| 138 | +`vdd` provides a mock server, simulating the driver on the other end of the |
| 139 | +named pipe. |
| 140 | + |
| 141 | +Additionally, import `package:vdd/test.dart` to get access to the mock server. |
| 142 | + |
| 143 | +```dart |
| 144 | +import 'package:vdd/vdd.dart' as vdd; |
| 145 | +import 'package:vdd/test.dart' as vdd; |
| 146 | +``` |
| 147 | + |
| 148 | +```dart |
| 149 | +setUpAll(() async { |
| 150 | + await vdd.init(); |
| 151 | +}); |
| 152 | +
|
| 153 | +test('test', () async { |
| 154 | + // Pass in a unique pipe name |
| 155 | + final server = await vdd.MockServer.create(pipeName: "my_pipe_name"); |
| 156 | + final client = await vdd.Client.connect(server.pipeName); |
| 157 | +
|
| 158 | + // Use the client |
| 159 | + await client.notify(...); |
| 160 | +
|
| 161 | + // Pump the server, to handle exactly one request |
| 162 | + await server.pump(); |
| 163 | +
|
| 164 | + expect(server.state, ...); |
| 165 | +
|
| 166 | + await server.setState(...); |
| 167 | +
|
| 168 | + expect(client.requestState(), ...); |
| 169 | +}); |
| 170 | +``` |
| 171 | + |
| 172 | +For more examples, see the |
| 173 | +[tests](https://github.com/MolotovCherry/virtual-display-rs/tree/master/rust/bindings/dart/test/vdd_test.dart) |
| 174 | +in `test/`. |
| 175 | + |
| 176 | +## Maintaining |
| 177 | + |
| 178 | +To regenerate bindings, run: |
| 179 | + |
| 180 | +```bash |
| 181 | +cargo make generate |
| 182 | +``` |
| 183 | + |
| 184 | +or |
| 185 | + |
| 186 | +```bash |
| 187 | +cargo make generate-watch |
| 188 | +``` |
| 189 | + |
| 190 | +To run unit tests, run: |
| 191 | + |
| 192 | +```bash |
| 193 | +cargo make test |
33 | 194 | ``` |
34 | 195 |
|
35 | | -## Additional information |
| 196 | +To run examples, run: |
36 | 197 |
|
37 | | -TODO: Tell users more about the package: where to find more information, how to |
38 | | -contribute to the package, how to file issues, what response they can expect |
39 | | -from the package authors, and more. |
| 198 | +```bash |
| 199 | +dart --enable-experiment=native-assets run example/<example>.dart |
| 200 | +``` |
0 commit comments