A game framework written with osu! in mind.
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2// See the LICENCE file in the repository root for full licence text.
3
4#if NET5_0
5using System;
6using System.Collections.Generic;
7using System.IO;
8using System.Linq;
9using System.Threading;
10using System.Threading.Tasks;
11using Newtonsoft.Json;
12using OpenTabletDriver;
13using OpenTabletDriver.Plugin;
14using OpenTabletDriver.Plugin.Tablet;
15using osu.Framework.Logging;
16using LogLevel = osu.Framework.Logging.LogLevel;
17
18namespace osu.Framework.Input.Handlers.Tablet
19{
20 public class TabletDriver : Driver
21 {
22 private static readonly IEnumerable<int> known_vendors = Enum.GetValues<DeviceVendor>().Cast<int>();
23
24 public TabletDriver()
25 {
26 Log.Output += (sender, logMessage) => Logger.Log($"{logMessage.Group}: {logMessage.Message}", level: (LogLevel)logMessage.Level);
27 DevicesChanged += (sender, args) =>
28 {
29 // it's worth noting that this event fires on *any* device change system-wide, including non-tablet devices.
30 if (Tablet == null && args.Additions.Any())
31 DetectTablet();
32 };
33 }
34
35 private readonly object detectLock = new object();
36
37 private CancellationTokenSource cancellationSource;
38
39 public void DetectTablet()
40 {
41 lock (detectLock)
42 {
43 cancellationSource?.Cancel();
44
45 var cancellationToken = (cancellationSource = new CancellationTokenSource()).Token;
46
47 Task.Run(async () =>
48 {
49 // wait a small delay as multiple devices may appear over a very short interval.
50 await Task.Delay(50, cancellationToken).ConfigureAwait(false);
51
52 var foundVendor = CurrentDevices.Select(d => d.VendorID).Intersect(known_vendors).FirstOrDefault();
53
54 if (foundVendor > 0)
55 {
56 Logger.Log($"Tablet detected (vid{foundVendor}), searching for usable configuration...");
57
58 foreach (var config in getConfigurations())
59 {
60 if (TryMatch(config))
61 break;
62 }
63 }
64 }, cancellationToken);
65 }
66 }
67
68 private IEnumerable<TabletConfiguration> getConfigurations()
69 {
70 // Retrieve all embedded configurations
71 var asm = typeof(Driver).Assembly;
72 return asm.GetManifestResourceNames()
73 .Where(path => path.Contains(".json"))
74 .Select(path => deserialize(asm.GetManifestResourceStream(path)));
75 }
76
77 private TabletConfiguration deserialize(Stream stream)
78 {
79 using (var reader = new StreamReader(stream))
80 using (var jsonReader = new JsonTextReader(reader))
81 return new JsonSerializer().Deserialize<TabletConfiguration>(jsonReader);
82 }
83 }
84}
85#endif