mirror of
https://github.com/HolographicHat/Yae.git
synced 2026-03-15 16:43:17 +08:00
fix #138
This commit is contained in:
@@ -18,4 +18,6 @@ TerminateProcess
|
||||
VirtualAllocEx
|
||||
VirtualFreeEx
|
||||
WaitForSingleObject
|
||||
WriteProcessMemory
|
||||
WriteProcessMemory
|
||||
|
||||
GetCurrentConsoleFontEx
|
||||
|
||||
36
YaeAchievement/res/App.Designer.cs
generated
36
YaeAchievement/res/App.Designer.cs
generated
@@ -374,6 +374,42 @@ namespace YaeAchievement.res {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Use the keyboard arrow keys to move the cursor and the Enter key to select.
|
||||
/// </summary>
|
||||
internal static string SelectionPromptCompatAnsiTip {
|
||||
get {
|
||||
return ResourceManager.GetString("SelectionPromptCompatAnsiTip", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Choose an option:.
|
||||
/// </summary>
|
||||
internal static string SelectionPromptCompatChooseOne {
|
||||
get {
|
||||
return ResourceManager.GetString("SelectionPromptCompatChooseOne", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please enter a number between 0 and {0}.
|
||||
/// </summary>
|
||||
internal static string SelectionPromptCompatInvalidChoice {
|
||||
get {
|
||||
return ResourceManager.GetString("SelectionPromptCompatInvalidChoice", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Type a number and press Enter to select.
|
||||
/// </summary>
|
||||
internal static string SelectionPromptCompatNonAnsiTip {
|
||||
get {
|
||||
return ResourceManager.GetString("SelectionPromptCompatNonAnsiTip", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Reward not taken.
|
||||
/// </summary>
|
||||
|
||||
@@ -163,4 +163,16 @@
|
||||
<data name="ExportTargetWxApp1" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SelectionPromptCompatChooseOne" xml:space="preserve">
|
||||
<value>Choose an option:</value>
|
||||
</data>
|
||||
<data name="SelectionPromptCompatAnsiTip" xml:space="preserve">
|
||||
<value>Use the keyboard arrow keys to move the cursor and the Enter key to select</value>
|
||||
</data>
|
||||
<data name="SelectionPromptCompatNonAnsiTip" xml:space="preserve">
|
||||
<value>Type a number and press Enter to select</value>
|
||||
</data>
|
||||
<data name="SelectionPromptCompatInvalidChoice" xml:space="preserve">
|
||||
<value>Please enter a number between 0 and {0}</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -18,7 +18,7 @@
|
||||
<value>全部成就</value>
|
||||
</data>
|
||||
<data name="ExportChoose" xml:space="preserve">
|
||||
<value>要导出到哪里?(键盘上下键移动光标,键盘回车键选择)</value>
|
||||
<value>要导出到哪里?</value>
|
||||
</data>
|
||||
<data name="ExportToCocogoatSuccess" xml:space="preserve">
|
||||
<value>在浏览器内进行下一步操作</value>
|
||||
@@ -91,7 +91,7 @@
|
||||
<value>YaeAchievement - 原神成就导出工具 ({0})</value>
|
||||
</data>
|
||||
<data name="UsePreviousData" xml:space="preserve">
|
||||
<value>要使用上一次获取到的成就数据吗?(键盘上下键移动光标,键盘回车键选择)</value>
|
||||
<value>要使用上一次获取到的成就数据吗?</value>
|
||||
</data>
|
||||
<data name="NetworkError" xml:space="preserve">
|
||||
<value>网络错误: {0}</value>
|
||||
@@ -156,4 +156,16 @@
|
||||
<data name="ExportTargetWxApp1" xml:space="preserve">
|
||||
<value>原魔工具箱</value>
|
||||
</data>
|
||||
<data name="SelectionPromptCompatChooseOne" xml:space="preserve">
|
||||
<value>选择一个选项:</value>
|
||||
</data>
|
||||
<data name="SelectionPromptCompatAnsiTip" xml:space="preserve">
|
||||
<value>键盘上下键移动光标,键盘回车键选择</value>
|
||||
</data>
|
||||
<data name="SelectionPromptCompatNonAnsiTip" xml:space="preserve">
|
||||
<value>输入数字并回车以选择选项</value>
|
||||
</data>
|
||||
<data name="SelectionPromptCompatInvalidChoice" xml:space="preserve">
|
||||
<value>请输入 0 到 {0} 之间的数字</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -9,6 +9,7 @@ using Spectre.Console;
|
||||
using YaeAchievement.Outputs;
|
||||
using YaeAchievement.Parsers;
|
||||
using YaeAchievement.res;
|
||||
using YaeAchievement.Utilities;
|
||||
|
||||
// ReSharper disable UnusedMember.Local
|
||||
|
||||
@@ -33,8 +34,8 @@ public static class Export {
|
||||
};
|
||||
Action<AchievementAllDataNotify> action;
|
||||
if (ExportTo == 114514) {
|
||||
var prompt = new SelectionPrompt<string>().Title(App.ExportChoose).AddChoices(targets.Keys);
|
||||
action = targets[AnsiConsole.Prompt(prompt)];
|
||||
var prompt = new SelectionPromptCompat<string>().Title(App.ExportChoose).AddChoices(targets.Keys);
|
||||
action = targets[prompt.Prompt()];
|
||||
} else {
|
||||
action = targets.ElementAtOrDefault(ExportTo).Value ?? ToCocogoat;
|
||||
}
|
||||
@@ -210,7 +211,7 @@ public static class Export {
|
||||
}
|
||||
}
|
||||
|
||||
public class WxApp1Root {
|
||||
public sealed class WxApp1Root {
|
||||
|
||||
public string Key { get; init; } = null!;
|
||||
|
||||
@@ -223,7 +224,7 @@ public class WxApp1Root {
|
||||
GenerationMode = JsonSourceGenerationMode.Serialization,
|
||||
PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower
|
||||
)]
|
||||
public partial class WxApp1Serializer : JsonSerializerContext {
|
||||
public sealed partial class WxApp1Serializer : JsonSerializerContext {
|
||||
|
||||
public static string Serialize(AchievementAllDataNotify ntf, string key) => JsonSerializer.Serialize(new WxApp1Root {
|
||||
Key = key,
|
||||
@@ -231,8 +232,8 @@ public partial class WxApp1Serializer : JsonSerializerContext {
|
||||
}, Default.WxApp1Root);
|
||||
}
|
||||
|
||||
public record CocogoatResponse(string Key);
|
||||
public sealed record CocogoatResponse(string Key);
|
||||
|
||||
[JsonSerializable(typeof(CocogoatResponse))]
|
||||
[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
|
||||
public partial class CocogoatResponseContext : JsonSerializerContext;
|
||||
public sealed partial class CocogoatResponseContext : JsonSerializerContext;
|
||||
@@ -8,7 +8,7 @@ namespace YaeAchievement.Outputs;
|
||||
// ReSharper disable PropertyCanBeMadeInitOnly.Global
|
||||
#pragma warning disable CA1822 // ReSharper disable MemberCanBeMadeStatic.Global
|
||||
|
||||
public class PaimonRoot {
|
||||
public sealed class PaimonRoot {
|
||||
|
||||
public Dictionary<uint, Dictionary<uint, bool>> Achievement { get; set; } = null!;
|
||||
|
||||
@@ -29,7 +29,7 @@ public class PaimonRoot {
|
||||
GenerationMode = JsonSourceGenerationMode.Serialization,
|
||||
PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower
|
||||
)]
|
||||
public partial class PaimonSerializer : JsonSerializerContext {
|
||||
public sealed partial class PaimonSerializer : JsonSerializerContext {
|
||||
|
||||
public static string Serialize(AchievementAllDataNotify ntf) {
|
||||
return JsonSerializer.Serialize(Outputs.PaimonRoot.FromNotify(ntf), Default.PaimonRoot);
|
||||
|
||||
@@ -8,9 +8,9 @@ namespace YaeAchievement.Outputs;
|
||||
// ReSharper disable PropertyCanBeMadeInitOnly.Global
|
||||
#pragma warning disable CA1822 // ReSharper disable MemberCanBeMadeStatic.Global
|
||||
|
||||
public class SeelieRoot {
|
||||
public sealed class SeelieRoot {
|
||||
|
||||
public class AchievementFinishStatus {
|
||||
public sealed class AchievementFinishStatus {
|
||||
|
||||
public bool Done => true;
|
||||
|
||||
@@ -31,7 +31,7 @@ public class SeelieRoot {
|
||||
GenerationMode = JsonSourceGenerationMode.Serialization,
|
||||
PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower
|
||||
)]
|
||||
public partial class SeelieSerializer : JsonSerializerContext {
|
||||
public sealed partial class SeelieSerializer : JsonSerializerContext {
|
||||
|
||||
public static string Serialize(AchievementAllDataNotify ntf) {
|
||||
return JsonSerializer.Serialize(Outputs.SeelieRoot.FromNotify(ntf), Default.SeelieRoot);
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace YaeAchievement.Outputs;
|
||||
// ReSharper disable PropertyCanBeMadeInitOnly.Global
|
||||
#pragma warning disable CA1822 // ReSharper disable MemberCanBeMadeStatic.Global
|
||||
|
||||
public class UApplicationInfo {
|
||||
public sealed class UApplicationInfo {
|
||||
|
||||
public string ExportApp => "YaeAchievement";
|
||||
|
||||
@@ -21,7 +21,7 @@ public class UApplicationInfo {
|
||||
|
||||
}
|
||||
|
||||
public class UAchievementInfo {
|
||||
public sealed class UAchievementInfo {
|
||||
|
||||
public uint Id { get; set; }
|
||||
|
||||
@@ -33,7 +33,7 @@ public class UAchievementInfo {
|
||||
|
||||
}
|
||||
|
||||
public class UIAFRoot {
|
||||
public sealed class UIAFRoot {
|
||||
|
||||
public UApplicationInfo Info => new ();
|
||||
|
||||
@@ -57,7 +57,7 @@ public class UIAFRoot {
|
||||
GenerationMode = JsonSourceGenerationMode.Serialization,
|
||||
PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower
|
||||
)]
|
||||
public partial class UIAFSerializer : JsonSerializerContext {
|
||||
public sealed partial class UIAFSerializer : JsonSerializerContext {
|
||||
|
||||
public static string Serialize(AchievementAllDataNotify ntf) {
|
||||
return JsonSerializer.Serialize(Outputs.UIAFRoot.FromNotify(ntf), Default.UIAFRoot);
|
||||
|
||||
@@ -14,7 +14,7 @@ public enum AchievementStatus {
|
||||
RewardTaken,
|
||||
}
|
||||
|
||||
public class AchievementItem {
|
||||
public sealed class AchievementItem {
|
||||
|
||||
public uint Id { get; init; }
|
||||
public uint TotalProgress { get; init; }
|
||||
@@ -24,7 +24,7 @@ public class AchievementItem {
|
||||
|
||||
}
|
||||
|
||||
public class AchievementAllDataNotify {
|
||||
public sealed class AchievementAllDataNotify {
|
||||
|
||||
public List<AchievementItem> AchievementList { get; private init; } = [];
|
||||
|
||||
@@ -144,7 +144,7 @@ public class AchievementAllDataNotify {
|
||||
GenerationMode = JsonSourceGenerationMode.Serialization,
|
||||
PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower
|
||||
)]
|
||||
public partial class AchievementRawDataSerializer : JsonSerializerContext {
|
||||
public sealed partial class AchievementRawDataSerializer : JsonSerializerContext {
|
||||
|
||||
public static string Serialize(AchievementAllDataNotify ntf) {
|
||||
return JsonSerializer.Serialize(ntf, Default.AchievementAllDataNotify);
|
||||
|
||||
@@ -9,7 +9,7 @@ using Spectre.Console;
|
||||
|
||||
namespace YaeAchievement.Parsers;
|
||||
|
||||
public class PlayerStoreNotify {
|
||||
public sealed class PlayerStoreNotify {
|
||||
|
||||
public uint WeightLimit { get; set; }
|
||||
|
||||
|
||||
@@ -58,10 +58,10 @@ internal static class Program {
|
||||
} catch (Exception) { /* ignored */ }
|
||||
|
||||
if (CacheFile.GetLastWriteTime("achievement_data").AddMinutes(60) > DateTime.UtcNow && data != null) {
|
||||
var prompt = new SelectionPrompt<string>()
|
||||
var prompt = new SelectionPromptCompat<string>()
|
||||
.Title(App.UsePreviousData)
|
||||
.AddChoices(App.CommonYes, App.CommonNo);
|
||||
if (AnsiConsole.Prompt(prompt) == App.CommonYes) {
|
||||
if (prompt.Prompt() == App.CommonYes) {
|
||||
Export.Choose(data);
|
||||
return;
|
||||
}
|
||||
@@ -89,6 +89,7 @@ internal static class Program {
|
||||
internal static void SetupConsole() {
|
||||
SetQuickEditMode(false);
|
||||
Console.InputEncoding = Console.OutputEncoding = Encoding.UTF8;
|
||||
FixTerminalFont();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ using static Windows.Win32.System.Memory.VIRTUAL_FREE_TYPE;
|
||||
|
||||
namespace YaeAchievement.Utilities;
|
||||
|
||||
public unsafe class GameProcess {
|
||||
public sealed unsafe class GameProcess {
|
||||
|
||||
public uint Id { get; }
|
||||
|
||||
|
||||
48
YaeAchievement/src/Utilities/SelectionPromptCompat.cs
Normal file
48
YaeAchievement/src/Utilities/SelectionPromptCompat.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using Spectre.Console;
|
||||
using YaeAchievement.res;
|
||||
|
||||
namespace YaeAchievement.Utilities;
|
||||
|
||||
public sealed class SelectionPromptCompat<T> where T : notnull {
|
||||
|
||||
private readonly List<T> _choices = [];
|
||||
private readonly SelectionPrompt<T> _prompt = new ();
|
||||
|
||||
public SelectionPromptCompat<T> Title(string? title) {
|
||||
_prompt.Title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SelectionPromptCompat<T> AddChoices(params IEnumerable<T> choices) {
|
||||
foreach (var choice in choices) {
|
||||
_prompt.AddChoice(choice);
|
||||
_choices.Add(choice);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public T Prompt() {
|
||||
if (AnsiConsole.Profile.Capabilities.Ansi) {
|
||||
var title = _prompt.Title;
|
||||
_prompt.Title += $" ({App.SelectionPromptCompatAnsiTip})";
|
||||
var result = AnsiConsole.Prompt(_prompt);
|
||||
_prompt.Title = title;
|
||||
return result;
|
||||
}
|
||||
if (_prompt.Title != null) {
|
||||
AnsiConsole.WriteLine(_prompt.Title + $" ({App.SelectionPromptCompatNonAnsiTip})");
|
||||
}
|
||||
for (var i = 0; i < _choices.Count; i++) {
|
||||
var choice = _choices[i];
|
||||
AnsiConsole.WriteLine($"[{i}] {choice}");
|
||||
}
|
||||
var choosePrompt = new TextPrompt<int>(App.SelectionPromptCompatChooseOne).Validate(i => {
|
||||
if (i < 0 || i >= _choices.Count) {
|
||||
return ValidationResult.Error(string.Format(App.SelectionPromptCompatInvalidChoice, _choices.Count - 1));
|
||||
}
|
||||
return ValidationResult.Success();
|
||||
});
|
||||
var resultIndex = AnsiConsole.Prompt(choosePrompt);
|
||||
return _choices[resultIndex];
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO.Pipes;
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
@@ -244,11 +245,27 @@ public static class Utils {
|
||||
}).ContinueWith(task => { if (task.IsFaulted) OnUnhandledException(task.Exception!); });
|
||||
}
|
||||
|
||||
public static unsafe void SetQuickEditMode(bool enable) {
|
||||
internal static unsafe void SetQuickEditMode(bool enable) {
|
||||
var handle = Native.GetStdHandle(STD_HANDLE.STD_INPUT_HANDLE);
|
||||
CONSOLE_MODE mode = default;
|
||||
Native.GetConsoleMode(handle, &mode);
|
||||
mode = enable ? mode | CONSOLE_MODE.ENABLE_QUICK_EDIT_MODE : mode &~CONSOLE_MODE.ENABLE_QUICK_EDIT_MODE;
|
||||
Native.SetConsoleMode(handle, mode);
|
||||
}
|
||||
|
||||
internal static unsafe void FixTerminalFont() {
|
||||
if (!CultureInfo.CurrentCulture.Name.StartsWith("zh")) {
|
||||
return;
|
||||
}
|
||||
var handle = Native.GetStdHandle(STD_HANDLE.STD_OUTPUT_HANDLE);
|
||||
var fontInfo = new CONSOLE_FONT_INFOEX {
|
||||
cbSize = (uint) sizeof(CONSOLE_FONT_INFOEX)
|
||||
};
|
||||
if (!Native.GetCurrentConsoleFontEx(handle, false, &fontInfo)) {
|
||||
return;
|
||||
}
|
||||
if (fontInfo.FaceName.ToString() == "Terminal") { // 点阵字体
|
||||
CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("en-US"); // todo: use better way like auto set console font etc.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user