aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Ava/UI/Helpers/ButtonKeyAssigner.cs
blob: 6730b57118217f9372751a42bf694b48b2cc2b80 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.LogicalTree;
using Avalonia.Threading;
using Ryujinx.Input;
using Ryujinx.Input.Assigner;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace Ryujinx.Ava.UI.Helpers
{
    internal class ButtonKeyAssigner
    {
        internal class ButtonAssignedEventArgs : EventArgs
        {
            public ToggleButton Button { get; }
            public bool IsAssigned { get; }

            public ButtonAssignedEventArgs(ToggleButton button, bool isAssigned)
            {
                Button = button;
                IsAssigned = isAssigned;
            }
        }
        
        public ToggleButton ToggledButton { get; set; }

        private bool _isWaitingForInput;
        private bool _shouldUnbind;
        public event EventHandler<ButtonAssignedEventArgs> ButtonAssigned;

        public ButtonKeyAssigner(ToggleButton toggleButton)
        {
            ToggledButton = toggleButton;
        }

        public async void GetInputAndAssign(IButtonAssigner assigner, IKeyboard keyboard = null)
        {
            Dispatcher.UIThread.Post(() =>
            {
                ToggledButton.IsChecked = true;
            });

            if (_isWaitingForInput)
            {
                Dispatcher.UIThread.Post(() =>
                {
                    Cancel();
                });

                return;
            }

            _isWaitingForInput = true;

            assigner.Initialize();

            await Task.Run(async () =>
            {
                while (true)
                {
                    if (!_isWaitingForInput)
                    {
                        return;
                    }

                    await Task.Delay(10);

                    assigner.ReadInput();

                    if (assigner.HasAnyButtonPressed() || assigner.ShouldCancel() || (keyboard != null && keyboard.IsPressed(Key.Escape)))
                    {
                        break;
                    }
                }
            });

            await Dispatcher.UIThread.InvokeAsync(() =>
            {
                string pressedButton = assigner.GetPressedButton();

                if (_shouldUnbind)
                {
                    SetButtonText(ToggledButton, "Unbound");
                }
                else if (pressedButton != "")
                {
                    SetButtonText(ToggledButton, pressedButton);
                }

                _shouldUnbind = false;
                _isWaitingForInput = false;

                ToggledButton.IsChecked = false;

                ButtonAssigned?.Invoke(this, new ButtonAssignedEventArgs(ToggledButton, pressedButton != null));

                static void SetButtonText(ToggleButton button, string text)
                {
                    ILogical textBlock = button.GetLogicalDescendants().First(x => x is TextBlock);

                    if (textBlock != null && textBlock is TextBlock block)
                    {
                        block.Text = text;
                    }
                }
            });
        }

        public void Cancel(bool shouldUnbind = false)
        {
            _isWaitingForInput = false;
            ToggledButton.IsChecked = false;
            _shouldUnbind = shouldUnbind;
        }
    }
}