feat: implement gamepad keybinds
This commit is contained in:
parent
4b612030bd
commit
c2001fca1c
136
Command.cs
136
Command.cs
|
@ -1,11 +1,4 @@
|
|||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using Blake3;
|
||||
using Dalamud.Game.Command;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using Newtonsoft.Json;
|
||||
using WebP.Net;
|
||||
|
||||
namespace Screenie;
|
||||
|
||||
|
@ -23,12 +16,6 @@ internal class Command : IDisposable {
|
|||
this.Plugin.CommandManager.RemoveHandler(CommandName);
|
||||
}
|
||||
|
||||
private static ImageCodecInfo? GetEncoder(ImageFormat format) {
|
||||
var codecs = ImageCodecInfo.GetImageEncoders();
|
||||
return codecs.FirstOrDefault(codec => codec.FormatID == format.Guid);
|
||||
}
|
||||
|
||||
|
||||
private void OnCommand(string command, string arguments) {
|
||||
// TODO: eventually be able to do like /screenie --no-ui --format png
|
||||
// etc.
|
||||
|
@ -37,127 +24,6 @@ internal class Command : IDisposable {
|
|||
return;
|
||||
}
|
||||
|
||||
var meta = ScreenshotMetadata.Capture(this.Plugin);
|
||||
var bitmapOuter = Photographer.Capture();
|
||||
if (bitmapOuter == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Task.Factory.StartNew(async () => {
|
||||
using var bitmap = bitmapOuter;
|
||||
|
||||
var saveAs = this.Plugin.Config.SaveFormat;
|
||||
byte[] imageData;
|
||||
string ext;
|
||||
if (saveAs.ToImageFormat() is { } format) {
|
||||
var data = this.SaveNative(format, bitmap);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
(imageData, ext) = data.Value;
|
||||
} else if (saveAs is Format.WebpLossless or Format.WebpLossy) {
|
||||
using var webp = new WebPObject(bitmap);
|
||||
imageData = saveAs == Format.WebpLossless
|
||||
? webp.GetWebPLossless()
|
||||
: webp.GetWebPLossy(this.Plugin.Config.SaveFormatData);
|
||||
ext = "webp";
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: use TagLib-Sharp to embed metadata into the image
|
||||
string hash;
|
||||
var (inner, path) = this.OpenFile(ext, meta);
|
||||
await using (var stream = new Blake3Stream(inner)) {
|
||||
await stream.WriteAsync(imageData);
|
||||
hash = Convert.ToHexString(stream.ComputeHash().AsSpan());
|
||||
}
|
||||
|
||||
var saved = new SavedMetadata {
|
||||
Path = path,
|
||||
Blake3Hash = hash,
|
||||
Metadata = meta,
|
||||
};
|
||||
|
||||
this.Plugin.Database.Execute(
|
||||
"""
|
||||
insert into screenshots
|
||||
(hash, path, active_character, location, location_sub, area, area_sub, territory_type, world, world_id, captured_at_local, captured_at_utc, eorzea_time, weather, ward, plot, visible_characters, mods_in_use)
|
||||
values ($hash, $path, json($active_character), $location, $location_sub, $area, $area_sub, $territory_type, $world, $world_id, $captured_at_local, $captured_at_utc, $eorzea_time, $weather, $ward, $plot, json($visible_characters), json($mods_in_use))
|
||||
""",
|
||||
new Dictionary<string, object?> {
|
||||
["$hash"] = saved.Blake3Hash,
|
||||
["$path"] = saved.Path,
|
||||
["$active_character"] = JsonConvert.SerializeObject(saved.Metadata.ActiveCharacter),
|
||||
["$location"] = saved.Metadata.Location,
|
||||
["$location_sub"] = saved.Metadata.LocationSub,
|
||||
["$area"] = saved.Metadata.Area,
|
||||
["$area_sub"] = saved.Metadata.AreaSub,
|
||||
["$territory_type"] = saved.Metadata.TerritoryType,
|
||||
["$world"] = saved.Metadata.World,
|
||||
["$world_id"] = saved.Metadata.WorldId,
|
||||
["$captured_at_local"] = saved.Metadata.CapturedAtLocal,
|
||||
["$captured_at_utc"] = saved.Metadata.CapturedAtUtc,
|
||||
["$eorzea_time"] = saved.Metadata.EorzeaTime,
|
||||
["$weather"] = saved.Metadata.Weather,
|
||||
["$ward"] = saved.Metadata.Ward,
|
||||
["$plot"] = saved.Metadata.Plot,
|
||||
["$visible_characters"] = JsonConvert.SerializeObject(saved.Metadata.VisibleCharacters),
|
||||
["$mods_in_use"] = JsonConvert.SerializeObject(saved.Metadata.ModsInUse),
|
||||
}
|
||||
);
|
||||
|
||||
var message = new SeStringBuilder()
|
||||
.AddText("Screenshot saved. [")
|
||||
.AddUiForeground(12)
|
||||
.Add(this.Plugin.LinkHandlers.OpenFolder)
|
||||
.AddText("Open folder")
|
||||
.Add(RawPayload.LinkTerminator)
|
||||
.AddUiForegroundOff()
|
||||
.AddText("]")
|
||||
.Build();
|
||||
this.Plugin.ChatGui.Print(message);
|
||||
});
|
||||
}
|
||||
|
||||
private (byte[], string)? SaveNative(ImageFormat format, Image bitmap) {
|
||||
var encoder = GetEncoder(format);
|
||||
if (encoder == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault
|
||||
var (param, ext) = this.Plugin.Config.SaveFormat switch {
|
||||
Format.Jpg => (Encoder.Quality, "jpg"),
|
||||
Format.Png => (Encoder.Compression, "png"),
|
||||
_ => throw new ArgumentException("not a native-save format", nameof(format)),
|
||||
};
|
||||
|
||||
var parameters = new EncoderParameters(1) {
|
||||
Param = [
|
||||
new EncoderParameter(param, this.Plugin.Config.SaveFormatData),
|
||||
],
|
||||
};
|
||||
|
||||
using var stream = new MemoryStream();
|
||||
bitmap.Save(stream, encoder, parameters);
|
||||
return (stream.ToArray(), ext);
|
||||
}
|
||||
|
||||
private (FileStream, string) OpenFile(string ext, ScreenshotMetadata meta) {
|
||||
Directory.CreateDirectory(this.Plugin.Config.SaveDirectory);
|
||||
|
||||
var fileName = this.Plugin.Config.SaveFileNameTemplate.Render(meta).ReplaceLineEndings(" ");
|
||||
|
||||
var path = Path.Join(this.Plugin.Config.SaveDirectory, fileName);
|
||||
path += $".{ext}";
|
||||
|
||||
path = Path.GetFullPath(path);
|
||||
|
||||
var parent = Path.Join(path, "..");
|
||||
Directory.CreateDirectory(parent);
|
||||
|
||||
return (new FileStream(path, FileMode.Create, FileAccess.Write), path);
|
||||
this.Plugin.SaveScreenshot();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ public class Configuration : IPluginConfiguration {
|
|||
{{- if plot -}} P{{ plot }} {{- end -}}
|
||||
""";
|
||||
|
||||
public GamepadButtons GamepadKeybind = GamepadButtons.L1 | GamepadButtons.Select;
|
||||
public GamepadButtons GamepadKeybind = GamepadButtons.L1 | GamepadButtons.Start;
|
||||
|
||||
private int _templateHashCode;
|
||||
private Template? _template;
|
||||
|
|
148
Plugin.cs
148
Plugin.cs
|
@ -1,9 +1,16 @@
|
|||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using Blake3;
|
||||
using Dalamud.Game.ClientState.GamePad;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Newtonsoft.Json;
|
||||
using Screenie.Ui;
|
||||
using WebP.Net;
|
||||
|
||||
namespace Screenie;
|
||||
|
||||
|
@ -80,6 +87,7 @@ public sealed class Plugin : IDalamudPlugin {
|
|||
|
||||
internal Stopwatch GamepadKeybindTimer = new();
|
||||
private GamepadButtons _buttons;
|
||||
private bool _pressAck;
|
||||
private unsafe void FrameworkUpdate(IFramework framework) {
|
||||
var gamepadInput = (GamepadInput*) this.GamepadState.GamepadInputAddress;
|
||||
|
||||
|
@ -92,7 +100,7 @@ public sealed class Plugin : IDalamudPlugin {
|
|||
|
||||
this._buttons |= (GamepadButtons) gamepadInput->ButtonsRaw;
|
||||
|
||||
if (gamepadInput->ButtonsRaw == 0) {
|
||||
if (gamepadInput->ButtonsRaw == 0 && this._buttons != 0) {
|
||||
this.Config.GamepadKeybind = this._buttons;
|
||||
this.SaveConfig();
|
||||
this._buttons = 0;
|
||||
|
@ -104,9 +112,147 @@ public sealed class Plugin : IDalamudPlugin {
|
|||
}
|
||||
|
||||
if (((GamepadButtons) gamepadInput->ButtonsRaw & this.Config.GamepadKeybind) != this.Config.GamepadKeybind) {
|
||||
this._pressAck = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._pressAck) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._pressAck = true;
|
||||
|
||||
Log.Info("pressed");
|
||||
this.SaveScreenshot();
|
||||
}
|
||||
|
||||
internal void SaveScreenshot() {
|
||||
var meta = ScreenshotMetadata.Capture(this);
|
||||
var bitmapOuter = Photographer.Capture();
|
||||
if (bitmapOuter == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Task.Factory.StartNew(async () => {
|
||||
using var bitmap = bitmapOuter;
|
||||
|
||||
var saveAs = this.Config.SaveFormat;
|
||||
byte[] imageData;
|
||||
string ext;
|
||||
if (saveAs.ToImageFormat() is { } format) {
|
||||
var data = this.SaveNative(format, bitmap);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
(imageData, ext) = data.Value;
|
||||
} else if (saveAs is Format.WebpLossless or Format.WebpLossy) {
|
||||
using var webp = new WebPObject(bitmap);
|
||||
imageData = saveAs == Format.WebpLossless
|
||||
? webp.GetWebPLossless()
|
||||
: webp.GetWebPLossy(this.Config.SaveFormatData);
|
||||
ext = "webp";
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: use TagLib-Sharp to embed metadata into the image
|
||||
string hash;
|
||||
var (inner, path) = this.OpenFile(ext, meta);
|
||||
await using (var stream = new Blake3Stream(inner)) {
|
||||
await stream.WriteAsync(imageData);
|
||||
hash = Convert.ToHexString(stream.ComputeHash().AsSpan());
|
||||
}
|
||||
|
||||
var saved = new SavedMetadata {
|
||||
Path = path,
|
||||
Blake3Hash = hash,
|
||||
Metadata = meta,
|
||||
};
|
||||
|
||||
this.Database.Execute(
|
||||
"""
|
||||
insert into screenshots
|
||||
(hash, path, active_character, location, location_sub, area, area_sub, territory_type, world, world_id, captured_at_local, captured_at_utc, eorzea_time, weather, ward, plot, visible_characters, mods_in_use)
|
||||
values ($hash, $path, json($active_character), $location, $location_sub, $area, $area_sub, $territory_type, $world, $world_id, $captured_at_local, $captured_at_utc, $eorzea_time, $weather, $ward, $plot, json($visible_characters), json($mods_in_use))
|
||||
""",
|
||||
new Dictionary<string, object?> {
|
||||
["$hash"] = saved.Blake3Hash,
|
||||
["$path"] = saved.Path,
|
||||
["$active_character"] = JsonConvert.SerializeObject(saved.Metadata.ActiveCharacter),
|
||||
["$location"] = saved.Metadata.Location,
|
||||
["$location_sub"] = saved.Metadata.LocationSub,
|
||||
["$area"] = saved.Metadata.Area,
|
||||
["$area_sub"] = saved.Metadata.AreaSub,
|
||||
["$territory_type"] = saved.Metadata.TerritoryType,
|
||||
["$world"] = saved.Metadata.World,
|
||||
["$world_id"] = saved.Metadata.WorldId,
|
||||
["$captured_at_local"] = saved.Metadata.CapturedAtLocal,
|
||||
["$captured_at_utc"] = saved.Metadata.CapturedAtUtc,
|
||||
["$eorzea_time"] = saved.Metadata.EorzeaTime,
|
||||
["$weather"] = saved.Metadata.Weather,
|
||||
["$ward"] = saved.Metadata.Ward,
|
||||
["$plot"] = saved.Metadata.Plot,
|
||||
["$visible_characters"] = JsonConvert.SerializeObject(saved.Metadata.VisibleCharacters),
|
||||
["$mods_in_use"] = JsonConvert.SerializeObject(saved.Metadata.ModsInUse),
|
||||
}
|
||||
);
|
||||
|
||||
var message = new SeStringBuilder()
|
||||
.AddText("Screenshot saved. [")
|
||||
.AddUiForeground(12)
|
||||
.Add(this.LinkHandlers.OpenFolder)
|
||||
.AddText("Open folder")
|
||||
.Add(RawPayload.LinkTerminator)
|
||||
.AddUiForegroundOff()
|
||||
.AddText("]")
|
||||
.Build();
|
||||
this.ChatGui.Print(message);
|
||||
});
|
||||
}
|
||||
|
||||
private static ImageCodecInfo? GetEncoder(ImageFormat format) {
|
||||
var codecs = ImageCodecInfo.GetImageEncoders();
|
||||
return codecs.FirstOrDefault(codec => codec.FormatID == format.Guid);
|
||||
}
|
||||
|
||||
private (byte[], string)? SaveNative(ImageFormat format, Image bitmap) {
|
||||
var encoder = GetEncoder(format);
|
||||
if (encoder == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault
|
||||
var (param, ext) = this.Config.SaveFormat switch {
|
||||
Format.Jpg => (Encoder.Quality, "jpg"),
|
||||
Format.Png => (Encoder.Compression, "png"),
|
||||
_ => throw new ArgumentException("not a native-save format", nameof(format)),
|
||||
};
|
||||
|
||||
var parameters = new EncoderParameters(1) {
|
||||
Param = [
|
||||
new EncoderParameter(param, this.Config.SaveFormatData),
|
||||
],
|
||||
};
|
||||
|
||||
using var stream = new MemoryStream();
|
||||
bitmap.Save(stream, encoder, parameters);
|
||||
return (stream.ToArray(), ext);
|
||||
}
|
||||
|
||||
private (FileStream, string) OpenFile(string ext, ScreenshotMetadata meta) {
|
||||
Directory.CreateDirectory(this.Config.SaveDirectory);
|
||||
|
||||
var fileName = this.Config.SaveFileNameTemplate.Render(meta).ReplaceLineEndings(" ");
|
||||
|
||||
var path = Path.Join(this.Config.SaveDirectory, fileName);
|
||||
path += $".{ext}";
|
||||
|
||||
path = Path.GetFullPath(path);
|
||||
|
||||
var parent = Path.Join(path, "..");
|
||||
Directory.CreateDirectory(parent);
|
||||
|
||||
return (new FileStream(path, FileMode.Create, FileAccess.Write), path);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue