GFramework/GFramework.Godot/Input/GodotInputMapBackend.cs
gewuyou 5f9589ed3c fix(input): 修复输入绑定快照与导入语义
- 修复 InputBindingStore 只读查询会污染导出快照的问题

- 修复 Godot 输入绑定导入时未清理残留动作绑定的问题

- 补充输入运行时与 Godot backend 的 XML 契约说明和 README 入口

- 更新 ai-plan 跟踪并补充针对 PR #346 的回归测试
2026-05-11 08:53:14 +08:00

98 lines
2.6 KiB
C#

// Copyright (c) 2025-2026 GeWuYou
// SPDX-License-Identifier: Apache-2.0
using GFramework.Game.Abstractions.Input;
namespace GFramework.Godot.Input;
/// <summary>
/// 基于 Godot `InputMap` 的默认后端实现。
/// </summary>
internal sealed class GodotInputMapBackend : IGodotInputMapBackend
{
private readonly Dictionary<string, List<InputBindingDescriptor>> _defaults;
/// <summary>
/// 初始化后端,并捕获当前 `InputMap` 作为默认快照。
/// </summary>
public GodotInputMapBackend()
{
_defaults = GetActionNames().ToDictionary(
static actionName => actionName,
actionName => GetBindings(actionName).ToList(),
StringComparer.Ordinal);
}
/// <inheritdoc />
public IReadOnlyList<string> GetActionNames()
{
return [..InputMap.GetActions().Select(static action => action.ToString())];
}
/// <inheritdoc />
public IReadOnlyList<InputBindingDescriptor> GetBindings(string actionName)
{
ArgumentException.ThrowIfNullOrWhiteSpace(actionName);
if (!InputMap.HasAction(actionName))
{
return Array.Empty<InputBindingDescriptor>();
}
var bindings = new List<InputBindingDescriptor>();
foreach (var inputEvent in InputMap.ActionGetEvents(actionName))
{
if (GodotInputBindingCodec.TryCreateBinding(inputEvent, out var binding))
{
bindings.Add(binding);
}
}
return bindings;
}
/// <inheritdoc />
public void SetBindings(string actionName, IReadOnlyList<InputBindingDescriptor> bindings)
{
ArgumentException.ThrowIfNullOrWhiteSpace(actionName);
ArgumentNullException.ThrowIfNull(bindings);
if (!InputMap.HasAction(actionName))
{
InputMap.AddAction(actionName);
}
InputMap.ActionEraseEvents(actionName);
foreach (var binding in bindings)
{
InputMap.ActionAddEvent(actionName, GodotInputBindingCodec.CreateInputEvent(binding));
}
}
/// <inheritdoc />
public void ResetAction(string actionName)
{
ArgumentException.ThrowIfNullOrWhiteSpace(actionName);
if (_defaults.TryGetValue(actionName, out var bindings))
{
SetBindings(actionName, bindings);
return;
}
if (InputMap.HasAction(actionName))
{
InputMap.ActionEraseEvents(actionName);
}
}
/// <inheritdoc />
public void ResetAll()
{
foreach (var actionName in GetActionNames())
{
ResetAction(actionName);
}
}
}