diff --git a/osu.Game.Rulesets.Catch/CatchInputManager.cs b/osu.Game.Rulesets.Catch/CatchInputManager.cs index 2344b41d95..1898ea8d04 100644 --- a/osu.Game.Rulesets.Catch/CatchInputManager.cs +++ b/osu.Game.Rulesets.Catch/CatchInputManager.cs @@ -3,12 +3,13 @@ using System.Collections.Generic; using System.ComponentModel; -using osu.Game.Input; +using osu.Framework.Input.Bindings; +using osu.Game.Input.Bindings; using OpenTK.Input; namespace osu.Game.Rulesets.Catch { - public class CatchInputManager : ActionMappingInputManager + public class CatchInputManager : DatabasedKeyBindingInputManager { public CatchInputManager(RulesetInfo ruleset) : base(ruleset, concurrencyMode: ConcurrentActionMode.UniqueActions) { diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 858dfa770f..9cf6bbc36b 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -8,8 +8,8 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; +using osu.Framework.Input.Bindings; using osu.Framework.MathUtils; -using osu.Game.Input; using osu.Game.Rulesets.Catch.Judgements; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawable; @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Catch.UI catcher.Size = new Vector2(DrawSize.Y); } - private class Catcher : Container, IHandleActions + private class Catcher : Container, IHandleKeyBindings { private Texture texture; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs index 313640a6b3..ef1d8f9e0e 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs @@ -7,12 +7,12 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; -using osu.Game.Input; +using osu.Framework.Input.Bindings; using OpenTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { - public class CirclePiece : Container, IHandleActions + public class CirclePiece : Container, IHandleKeyBindings { private readonly Sprite disc; diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index 83304a9615..9e2a268632 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -4,14 +4,15 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Input; -using osu.Game.Input; +using osu.Framework.Input.Bindings; +using osu.Game.Input.Bindings; using OpenTK.Input; using KeyboardState = osu.Framework.Input.KeyboardState; using MouseState = osu.Framework.Input.MouseState; namespace osu.Game.Rulesets.Osu { - public class OsuInputManager : ActionMappingInputManager + public class OsuInputManager : DatabasedKeyBindingInputManager { public OsuInputManager(RulesetInfo ruleset) : base(ruleset, concurrencyMode: ConcurrentActionMode.UniqueActions) { diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs index 84ef8f5079..b3be6dd610 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs @@ -8,15 +8,15 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Bindings; using osu.Game.Beatmaps; using osu.Game.Configuration; -using osu.Game.Input; using OpenTK; using OpenTK.Graphics; namespace osu.Game.Rulesets.Osu.UI.Cursor { - public class GameplayCursor : CursorContainer, IHandleActions + public class GameplayCursor : CursorContainer, IHandleKeyBindings { protected override Drawable CreateCursor() => new OsuCursor(); diff --git a/osu.Game/Input/ActionMappingInputManager.cs b/osu.Game/Input/ActionMappingInputManager.cs deleted file mode 100644 index a4a356d6ad..0000000000 --- a/osu.Game/Input/ActionMappingInputManager.cs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Input; -using osu.Game.Rulesets; - -namespace osu.Game.Input -{ - /// - /// Maps input actions to custom action data of type . Use in conjunction with s implementing . - /// - /// The type of the custom action. - public abstract class ActionMappingInputManager : PassThroughInputManager - where T : struct - { - private readonly RulesetInfo ruleset; - - private readonly int? variant; - - private readonly ConcurrentActionMode concurrencyMode; - - private readonly List mappings = new List(); - - /// - /// Create a new instance. - /// - /// A reference to identify the current . Used to lookup mappings. Null for global mappings. - /// An optional variant for the specified . Used when a ruleset has more than one possible keyboard layouts. - /// Specify how to deal with multiple matches of s and s. - protected ActionMappingInputManager(RulesetInfo ruleset = null, int? variant = null, ConcurrentActionMode concurrencyMode = ConcurrentActionMode.None) - { - this.ruleset = ruleset; - this.variant = variant; - this.concurrencyMode = concurrencyMode; - } - - protected abstract IDictionary CreateDefaultMappings(); - - private BindingStore store; - - [BackgroundDependencyLoader] - private void load(BindingStore bindings) - { - store = bindings; - ReloadMappings(); - } - - protected void ReloadMappings() - { - var rulesetId = ruleset?.ID; - - mappings.Clear(); - - foreach (var kvp in CreateDefaultMappings()) - mappings.Add(new Binding(kvp.Key, kvp.Value)); - - if (store != null) - { - foreach (var b in store.Query(b => b.RulesetID == rulesetId && b.Variant == variant)) - mappings.Add(b); - } - } - - private readonly List pressedBindings = new List(); - - protected override bool PropagateKeyDown(IEnumerable drawables, InputState state, KeyDownEventArgs args) - { - bool handled = false; - - if (args.Repeat) - { - if (pressedBindings.Count > 0) - return true; - - return base.PropagateKeyDown(drawables, state, args); - } - - if (concurrencyMode == ConcurrentActionMode.None && pressedBindings.Count > 0) - return true; - - Binding validBinding; - - while ((validBinding = mappings.Except(pressedBindings).LastOrDefault(m => m.Keys.CheckValid(state.Keyboard.Keys, concurrencyMode == ConcurrentActionMode.None))) != null) - { - if (concurrencyMode == ConcurrentActionMode.UniqueAndSameActions || pressedBindings.All(p => p.Action != validBinding.Action)) - handled = drawables.OfType>().Any(d => d.OnPressed(validBinding.GetAction())); - - // store both the pressed combination and the resulting action, just in case the assignments change while we are actuated. - pressedBindings.Add(validBinding); - } - - return handled || base.PropagateKeyDown(drawables, state, args); - } - - protected override bool PropagateKeyUp(IEnumerable drawables, InputState state, KeyUpEventArgs args) - { - bool handled = false; - - foreach (var binding in pressedBindings.ToList()) - { - if (!binding.Keys.CheckValid(state.Keyboard.Keys, concurrencyMode == ConcurrentActionMode.None)) - { - // clear the no-longer-valid combination/action. - pressedBindings.Remove(binding); - - if (concurrencyMode == ConcurrentActionMode.UniqueAndSameActions || pressedBindings.All(p => p.Action != binding.Action)) - { - // set data as KeyUp if we're all done with this action. - handled = drawables.OfType>().Any(d => d.OnReleased(binding.GetAction())); - } - } - } - - return handled || base.PropagateKeyUp(drawables, state, args); - } - } - - public enum ConcurrentActionMode - { - /// - /// One action can be pressed at once. The first action matching a chord will take precedence and no other action will be pressed until it has first been released. - /// - None, - /// - /// Unique actions are allowed to be pressed at the same time. There may therefore be more than one action in an actuated state at once. - /// If one action has multiple bindings, only the first will trigger an . - /// The last binding to be released will trigger an . - /// - UniqueActions, - /// - /// Unique actions are allowed to be pressed at the same time. There may therefore be more than one action in an actuated state at once (same as ). - /// In addition to this, multiple are fired for single actions, even if has not yet been fired. - /// The same goes for , which is fired for each matching binding that is released. - /// - UniqueAndSameActions, - } -} diff --git a/osu.Game/Input/Binding.cs b/osu.Game/Input/Binding.cs deleted file mode 100644 index 11db78ec93..0000000000 --- a/osu.Game/Input/Binding.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Game.Rulesets; -using SQLite.Net.Attributes; -using SQLiteNetExtensions.Attributes; - -namespace osu.Game.Input -{ - public class Binding - { - [ForeignKey(typeof(RulesetInfo))] - public int? RulesetID { get; set; } - - [Indexed] - public int? Variant { get; set; } - - [Column("Keys")] - public string KeysString - { - get { return Keys.ToString(); } - set { Keys = value; } - } - - [Ignore] - public KeyCombination Keys { get; private set; } - - public int Action { get; private set; } - - public Binding() - { - - } - - public Binding(KeyCombination keys, object action) - { - Keys = keys; - Action = (int)action; - } - - public virtual T GetAction() => (T)(object)Action; - - public override string ToString() => $"{KeysString}=>{Action}"; - } -} \ No newline at end of file diff --git a/osu.Game/Input/BindingStore.cs b/osu.Game/Input/BindingStore.cs index f66d481a74..25a997e29d 100644 --- a/osu.Game/Input/BindingStore.cs +++ b/osu.Game/Input/BindingStore.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Platform; using osu.Game.Database; +using osu.Game.Input.Bindings; using SQLite.Net; namespace osu.Game.Input @@ -35,12 +36,12 @@ namespace osu.Game.Input protected override void Prepare(bool reset = false) { - Connection.CreateTable(); + Connection.CreateTable(); } protected override Type[] ValidTypes => new[] { - typeof(Binding) + typeof(DatabasedKeyBinding) }; } diff --git a/osu.Game/Input/Bindings/DatabasedKeyBinding.cs b/osu.Game/Input/Bindings/DatabasedKeyBinding.cs new file mode 100644 index 0000000000..cb571cdf04 --- /dev/null +++ b/osu.Game/Input/Bindings/DatabasedKeyBinding.cs @@ -0,0 +1,31 @@ +using osu.Framework.Input.Bindings; +using osu.Game.Rulesets; +using SQLite.Net.Attributes; +using SQLiteNetExtensions.Attributes; + +namespace osu.Game.Input.Bindings +{ + [Table("KeyBinding")] + public class DatabasedKeyBinding : KeyBinding + { + [ForeignKey(typeof(RulesetInfo))] + public int? RulesetID { get; set; } + + [Indexed] + public int? Variant { get; set; } + + [Column("Keys")] + public string KeysString + { + get { return Keys.ToString(); } + private set { Keys = value; } + } + + [Column("Action")] + public new int Action + { + get { return base.Action; } + private set { base.Action = value; } + } + } +} \ No newline at end of file diff --git a/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs b/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs new file mode 100644 index 0000000000..d31c4ab55d --- /dev/null +++ b/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs @@ -0,0 +1,54 @@ +using osu.Framework.Allocation; +using osu.Framework.Input.Bindings; +using osu.Game.Rulesets; + +namespace osu.Game.Input.Bindings +{ + /// + /// A KeyBindingInputManager with a database backing for custom overrides. + /// + /// The type of the custom action. + public abstract class DatabasedKeyBindingInputManager : KeyBindingInputManager + where T : struct + { + private readonly RulesetInfo ruleset; + + private readonly int? variant; + + private BindingStore store; + + /// + /// Create a new instance. + /// + /// A reference to identify the current . Used to lookup mappings. Null for global mappings. + /// An optional variant for the specified . Used when a ruleset has more than one possible keyboard layouts. + /// Specify how to deal with multiple matches of s and s. + protected DatabasedKeyBindingInputManager(RulesetInfo ruleset = null, int? variant = null, ConcurrentActionMode concurrencyMode = ConcurrentActionMode.None) + : base(concurrencyMode) + { + this.ruleset = ruleset; + this.variant = variant; + } + + [BackgroundDependencyLoader] + private void load(BindingStore bindings) + { + store = bindings; + } + + protected override void ReloadMappings() + { + // load defaults + base.ReloadMappings(); + + var rulesetId = ruleset?.ID; + + // load from database if present. + if (store != null) + { + foreach (var b in store.Query(b => b.RulesetID == rulesetId && b.Variant == variant)) + Mappings.Add(b); + } + } + } +} \ No newline at end of file diff --git a/osu.Game/Input/GlobalActionMappingInputManager.cs b/osu.Game/Input/Bindings/GlobalBindingInputManager.cs similarity index 87% rename from osu.Game/Input/GlobalActionMappingInputManager.cs rename to osu.Game/Input/Bindings/GlobalBindingInputManager.cs index 3136fa5be5..4255bfd657 100644 --- a/osu.Game/Input/GlobalActionMappingInputManager.cs +++ b/osu.Game/Input/Bindings/GlobalBindingInputManager.cs @@ -7,16 +7,17 @@ using System.ComponentModel; using System.Linq; using osu.Framework.Graphics; using osu.Framework.Input; +using osu.Framework.Input.Bindings; -namespace osu.Game.Input +namespace osu.Game.Input.Bindings { - public class GlobalActionMappingInputManager : ActionMappingInputManager + public class GlobalBindingInputManager : DatabasedKeyBindingInputManager { private readonly Drawable handler; - public GlobalActionMappingInputManager(OsuGameBase game) + public GlobalBindingInputManager(OsuGameBase game) { - if (game is IHandleActions) + if (game is IHandleKeyBindings) handler = game; } diff --git a/osu.Game/Input/IHandleActions.cs b/osu.Game/Input/IHandleActions.cs deleted file mode 100644 index 34720eb1ee..0000000000 --- a/osu.Game/Input/IHandleActions.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -namespace osu.Game.Input -{ - public interface IHandleActions - where T : struct - { - bool OnPressed(T action); - bool OnReleased(T action); - } -} \ No newline at end of file diff --git a/osu.Game/Input/KeyCombination.cs b/osu.Game/Input/KeyCombination.cs deleted file mode 100644 index 1e8dff0a51..0000000000 --- a/osu.Game/Input/KeyCombination.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenTK.Input; - -namespace osu.Game.Input -{ - /// - /// Represent a combination of more than one s. - /// - public class KeyCombination : IEquatable - { - public readonly IEnumerable Keys; - - public KeyCombination(params Key[] keys) - { - Keys = keys; - } - - public KeyCombination(IEnumerable keys) - { - Keys = keys; - } - - public KeyCombination(string stringRepresentation) - { - Keys = stringRepresentation.Split(',').Select(s => (Key)int.Parse(s)); - } - - public bool CheckValid(IEnumerable keys, bool requireExactMatch = false) - { - if (requireExactMatch) - return Keys.SequenceEqual(keys); - else - return !Keys.Except(keys).Any(); - } - - public bool Equals(KeyCombination other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return Keys.SequenceEqual(other.Keys); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != GetType()) return false; - return Equals((KeyCombination)obj); - } - - public override int GetHashCode() => Keys != null ? Keys.Select(k => k.GetHashCode()).Aggregate((h1, h2) => h1 + h2) : 0; - - public static implicit operator KeyCombination(Key singleKey) => new KeyCombination(singleKey); - - public static implicit operator KeyCombination(string stringRepresentation) => new KeyCombination(stringRepresentation); - - public static implicit operator KeyCombination(Key[] keys) => new KeyCombination(keys); - - public override string ToString() => Keys.Select(k => ((int)k).ToString()).Aggregate((s1, s2) => $"{s1},{s2}"); - } -} \ No newline at end of file diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 9d24597b96..7e5c3987b5 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -18,6 +18,7 @@ using osu.Game.Screens.Menu; using OpenTK; using System.Linq; using System.Threading.Tasks; +using osu.Framework.Input.Bindings; using osu.Framework.Platform; using osu.Framework.Threading; using osu.Game.Graphics; @@ -25,11 +26,11 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; using osu.Game.Screens.Play; -using osu.Game.Input; +using osu.Game.Input.Bindings; namespace osu.Game { - public class OsuGame : OsuGameBase, IHandleActions + public class OsuGame : OsuGameBase, IHandleKeyBindings { public Toolbar Toolbar; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 90d86f5371..344b23cca4 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -20,6 +20,7 @@ using SQLite.Net; using osu.Framework.Graphics.Performance; using osu.Game.Database; using osu.Game.Input; +using osu.Game.Input.Bindings; using osu.Game.IO; using osu.Game.Rulesets; using osu.Game.Rulesets.Scoring; @@ -187,7 +188,7 @@ namespace osu.Game Children = new Drawable[] { Cursor = new MenuCursor(), - new GlobalActionMappingInputManager(this) + new GlobalBindingInputManager(this) { RelativeSizeAxes = Axes.Both, Child = new OsuTooltipContainer(Cursor) diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs index d07f156673..168360ffd1 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs @@ -245,7 +245,7 @@ namespace osu.Game.Overlays.Settings.Sections.General { RelativeSizeAxes = Axes.X, Text = "Register new account", - //Action = registerLink + //Binding = registerLink } }; } diff --git a/osu.Game/Screens/Select/Footer.cs b/osu.Game/Screens/Select/Footer.cs index bb6d16da0f..fc57f5edeb 100644 --- a/osu.Game/Screens/Select/Footer.cs +++ b/osu.Game/Screens/Select/Footer.cs @@ -39,7 +39,7 @@ namespace osu.Game.Screens.Select /// Text on the button. /// Colour of the button. /// Hotkey of the button. - /// Action the button does. + /// Binding the button does. /// /// Higher depth to be put on the left, and lower to be put on the right. /// Notice this is different to ! diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs index 0a410f0e0f..c66cc7beff 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs @@ -86,7 +86,7 @@ namespace osu.Game.Screens.Select.Options /// Colour of the button. /// Icon of the button. /// Hotkey of the button. - /// Action the button does. + /// Binding the button does. /// /// Lower depth to be put on the left, and higher to be put on the right. /// Notice this is different to ! diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a240e58895..7690a56378 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -92,11 +92,10 @@ - + + - - - + @@ -123,7 +122,6 @@ -