Skip to content

Commit 6b38fe9

Browse files
authored
Add XInput in preparation for gamepad triggers + add xmldoc (#50)
* Add XInput in preparation for gamepad triggers + add xmldoc * add parent-child relation between mapped options * add remove child mappings option + remove debug context menu * x86 > AnyCPU (gives more sensible errors in WinForms Designer) - Fixed Designer failing on MappingForm * Fix polling gamepad * Add gamepad input trigger and config control + Fix mapping list not updating correctly * remove broken and quite useless test * update readme with warning regarding #46 + update readme special thanks * add warning on same gamepad id trigger and action * attempt to give github actions more time before timeout (tests sometimes fail) * use current default mapping profile from app (so we dont have to copy it to tests everytime manually) * Add gamepad button trigger * Add multi-property edit mode * Show physical gamepad connection warning * give even more time for tests so they dont fail * Block arming mappings if simulated gamepad index collides with physical gamepad * Cleanup + add GamePad Trigger Trigger * Fix combined trigger remove not working * Separate stick action and allow custom scaling * improve stick feeling * fix parent picker * update default mappings * add trigger and try work out conflicts between physical and simulated devices (no luck yet) * Fix simulated gamepad recognized as physical * Show gamepad devices in UI * fix mapping form + add more multi-edit type support * make reverse mapping tool more useful * easily setup/update reverse mappings while creating/updating a mapping * update readme screenshots + prefer 'Arm' terminology for enabling profile * support more nullable types in mapping profile * simplify groups * add configurable grouping * prevent wonky sorting across groups * Add easy switch group option * Fix being able to create corrupt profile * fail loading incorrect profile safely
1 parent 14b7ce9 commit 6b38fe9

File tree

191 files changed

+18460
-9768
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

191 files changed

+18460
-9768
lines changed

Core/Key2Joy.Contracts/Key2Joy.Contracts.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<Authors>luttje</Authors>
@@ -14,7 +14,7 @@
1414
<TargetFramework>NET48</TargetFramework>
1515
<LangVersion>latest</LangVersion>
1616
<RootNamespace>Key2Joy.Contracts</RootNamespace>
17-
<PlatformTarget>x86</PlatformTarget>
17+
<PlatformTarget>AnyCPU</PlatformTarget>
1818
<SignAssembly>False</SignAssembly>
1919
<AssemblyOriginatorKeyFile></AssemblyOriginatorKeyFile>
2020
<BaseOutputPath>bin\$(MSBuildProjectName)</BaseOutputPath>
Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,36 @@
1-
using System;
2-
using System.Text.Json.Serialization;
3-
using Key2Joy.Contracts.Mapping.Actions;
4-
using Key2Joy.Contracts.Mapping.Triggers;
5-
6-
namespace Key2Joy.Contracts.Mapping;
7-
8-
public abstract class AbstractMappedOption : ICloneable
9-
{
10-
[JsonInclude]
11-
public AbstractAction Action { get; set; }
12-
[JsonInclude]
13-
public AbstractTrigger Trigger { get; set; }
14-
15-
public abstract object Clone();
16-
}
1+
using System;
2+
using System.Text.Json.Serialization;
3+
using Key2Joy.Contracts.Mapping.Actions;
4+
using Key2Joy.Contracts.Mapping.Triggers;
5+
6+
namespace Key2Joy.Contracts.Mapping;
7+
8+
public abstract class AbstractMappedOption : ICloneable
9+
{
10+
/// <summary>
11+
/// The unique identifier for this mapping.
12+
/// This way it can be referenced by other mappings.
13+
/// </summary>
14+
[JsonInclude]
15+
public Guid Guid { get; protected set; }
16+
17+
/// <summary>
18+
/// The action that is executed when this mapping is executed.
19+
/// </summary>
20+
[JsonInclude]
21+
public AbstractAction Action { get; set; }
22+
23+
/// <summary>
24+
/// The trigger that causes this mapping to be executed.
25+
/// </summary>
26+
[JsonInclude]
27+
public AbstractTrigger Trigger { get; set; }
28+
29+
/// <summary>
30+
/// The unique identifier of the parent mapped option.
31+
/// </summary>
32+
[JsonInclude]
33+
public Guid? ParentGuid { get; set; } = null;
34+
35+
public abstract object Clone();
36+
}
Lines changed: 156 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,156 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Reflection;
5-
using System.Text.Json.Serialization;
6-
7-
namespace Key2Joy.Contracts.Mapping;
8-
9-
public abstract class AbstractMappingAspect : MarshalByRefObject, ICloneable, IComparable<AbstractMappingAspect>
10-
{
11-
public string Name { get; set; }
12-
13-
public AbstractMappingAspect(string name) => this.Name = name;
14-
15-
private PropertyInfo[] GetProperties()
16-
{
17-
var type = this.GetType();
18-
var properties = type.GetProperties();
19-
20-
return properties.Where(p => p.GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Length == 0).ToArray();
21-
}
22-
23-
public virtual MappingAspectOptions SaveOptions()
24-
{
25-
MappingAspectOptions options = new();
26-
var properties = this.GetProperties();
27-
28-
foreach (var property in properties)
29-
{
30-
this.SaveOptionsGetProperty(options, property);
31-
}
32-
33-
return options;
34-
}
35-
36-
/// <summary>
37-
/// Can be overridden by child actions or triggers to allow saving more complex types.
38-
/// </summary>
39-
/// <param name="property"></param>
40-
/// <param name="value"></param>
41-
protected virtual void SaveOptionsGetProperty(MappingAspectOptions options, PropertyInfo property)
42-
{
43-
var value = property.GetValue(this);
44-
45-
switch (value)
46-
{
47-
case DateTime dateTime:
48-
value = dateTime.Ticks;
49-
break;
50-
51-
default:
52-
break;
53-
}
54-
55-
options.Add(property.Name, value);
56-
}
57-
58-
public virtual void LoadOptions(MappingAspectOptions options)
59-
{
60-
var properties = this.GetProperties();
61-
62-
foreach (var property in properties)
63-
{
64-
if (!options.ContainsKey(property.Name))
65-
{
66-
continue;
67-
}
68-
69-
this.LoadOptionSetProperty(options, property);
70-
}
71-
}
72-
73-
/// <summary>
74-
/// Can be overridden by child actions or triggers to allow loading more complex types.
75-
/// </summary>
76-
/// <param name="property"></param>
77-
/// <param name="value"></param>
78-
protected virtual void LoadOptionSetProperty(MappingAspectOptions options, PropertyInfo property)
79-
{
80-
var propertyType = property.PropertyType;
81-
var value = options[property.Name];
82-
var genericTypeDefinition = propertyType.IsGenericType ? propertyType.GetGenericTypeDefinition() : null;
83-
84-
if (propertyType.IsEnum)
85-
{
86-
value = Enum.Parse(propertyType, (string)value);
87-
}
88-
else if (propertyType == typeof(DateTime))
89-
{
90-
value = new DateTime(Convert.ToInt64(value));
91-
}
92-
else if (propertyType.IsGenericType
93-
&& (genericTypeDefinition == typeof(List<>) || genericTypeDefinition == typeof(IList<>)))
94-
{
95-
var constructedListType = typeof(List<>).MakeGenericType(propertyType.GetGenericArguments());
96-
var instance = Activator.CreateInstance(constructedListType);
97-
98-
if (value is List<object> list)
99-
{
100-
var addMethod = constructedListType.GetMethod("Add");
101-
102-
foreach (var item in list)
103-
{
104-
addMethod.Invoke(instance, new object[] { item });
105-
}
106-
107-
value = instance;
108-
}
109-
else
110-
{
111-
throw new ArgumentException($"Expected value to be of type List<> to parse. But was: {value.GetType()}");
112-
}
113-
}
114-
else
115-
{
116-
value = Convert.ChangeType(value, propertyType);
117-
}
118-
119-
property.SetValue(this, value);
120-
}
121-
122-
public virtual int CompareTo(AbstractMappingAspect other) => this.ToString().CompareTo(other.ToString());
123-
124-
public static bool operator ==(AbstractMappingAspect a, AbstractMappingAspect b)
125-
{
126-
if (ReferenceEquals(a, b))
127-
{
128-
return true;
129-
}
130-
131-
if (a is null || b is null)
132-
{
133-
return false;
134-
}
135-
136-
return a.Equals(b);
137-
}
138-
139-
public static bool operator !=(AbstractMappingAspect a, AbstractMappingAspect b) => !(a == b);
140-
141-
public virtual object Clone() => this.MemberwiseClone();
142-
}
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
using System.Text.Json.Serialization;
6+
7+
namespace Key2Joy.Contracts.Mapping;
8+
9+
public abstract class AbstractMappingAspect : MarshalByRefObject, ICloneable, IComparable<AbstractMappingAspect>
10+
{
11+
public string Name { get; set; }
12+
13+
public AbstractMappingAspect(string name) => this.Name = name;
14+
15+
public virtual string GetNameDisplay() => this.Name;
16+
17+
public override string ToString() => this.GetNameDisplay();
18+
19+
private PropertyInfo[] GetProperties()
20+
{
21+
var type = this.GetType();
22+
var properties = type.GetProperties();
23+
24+
return properties.Where(p => p.GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Length == 0).ToArray();
25+
}
26+
27+
public virtual MappingAspectOptions SaveOptions()
28+
{
29+
MappingAspectOptions options = new();
30+
var properties = this.GetProperties();
31+
32+
foreach (var property in properties)
33+
{
34+
this.SaveOptionsGetProperty(options, property);
35+
}
36+
37+
return options;
38+
}
39+
40+
/// <summary>
41+
/// Can be overridden by child actions or triggers to allow saving more complex types.
42+
/// </summary>
43+
/// <param name="property"></param>
44+
/// <param name="value"></param>
45+
protected virtual void SaveOptionsGetProperty(MappingAspectOptions options, PropertyInfo property)
46+
{
47+
var value = property.GetValue(this);
48+
49+
switch (value)
50+
{
51+
case DateTime dateTime:
52+
value = dateTime.Ticks;
53+
break;
54+
55+
default:
56+
break;
57+
}
58+
59+
options.Add(property.Name, value);
60+
}
61+
62+
public virtual void LoadOptions(MappingAspectOptions options)
63+
{
64+
var properties = this.GetProperties();
65+
66+
foreach (var property in properties)
67+
{
68+
if (!options.ContainsKey(property.Name))
69+
{
70+
continue;
71+
}
72+
73+
this.LoadOptionSetProperty(options, property);
74+
}
75+
}
76+
77+
/// <summary>
78+
/// Can be overridden by child actions or triggers to allow loading more complex types.
79+
/// </summary>
80+
/// <param name="property"></param>
81+
/// <param name="value"></param>
82+
protected virtual void LoadOptionSetProperty(MappingAspectOptions options, PropertyInfo property)
83+
{
84+
var propertyType = property.PropertyType;
85+
var value = options[property.Name];
86+
var genericTypeDefinition = propertyType.IsGenericType ? propertyType.GetGenericTypeDefinition() : null;
87+
88+
propertyType = Nullable.GetUnderlyingType(propertyType) ?? propertyType;
89+
90+
if (propertyType.IsEnum)
91+
{
92+
value = Enum.Parse(propertyType, (string)value);
93+
}
94+
else if (propertyType == typeof(DateTime))
95+
{
96+
value = new DateTime(Convert.ToInt64(value));
97+
}
98+
else if (propertyType == typeof(TimeSpan))
99+
{
100+
value = TimeSpan.Parse((string)value);
101+
}
102+
else if (propertyType == typeof(short))
103+
{
104+
value = Convert.ToInt16(value);
105+
}
106+
else if (propertyType.IsGenericType
107+
&& (genericTypeDefinition == typeof(List<>) || genericTypeDefinition == typeof(IList<>)))
108+
{
109+
var constructedListType = typeof(List<>).MakeGenericType(propertyType.GetGenericArguments());
110+
var instance = Activator.CreateInstance(constructedListType);
111+
112+
if (value is List<object> list)
113+
{
114+
var addMethod = constructedListType.GetMethod("Add");
115+
116+
foreach (var item in list)
117+
{
118+
addMethod.Invoke(instance, new object[] { item });
119+
}
120+
121+
value = instance;
122+
}
123+
else
124+
{
125+
throw new ArgumentException($"Expected value to be of type List<> to parse. But was: {value.GetType()}");
126+
}
127+
}
128+
else if (value != null)
129+
{
130+
value = Convert.ChangeType(value, propertyType);
131+
}
132+
133+
property.SetValue(this, value);
134+
}
135+
136+
public virtual int CompareTo(AbstractMappingAspect other) => this.ToString().CompareTo(other.ToString());
137+
138+
public static bool operator ==(AbstractMappingAspect a, AbstractMappingAspect b)
139+
{
140+
if (ReferenceEquals(a, b))
141+
{
142+
return true;
143+
}
144+
145+
if (a is null || b is null)
146+
{
147+
return false;
148+
}
149+
150+
return a.Equals(b);
151+
}
152+
153+
public static bool operator !=(AbstractMappingAspect a, AbstractMappingAspect b) => !(a == b);
154+
155+
public virtual object Clone() => this.MemberwiseClone();
156+
}

Core/Key2Joy.Contracts/Mapping/Actions/AbstractAction.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Text.Json.Serialization;
33
using System.Threading.Tasks;
44
using Key2Joy.Contracts.Mapping.Triggers;
5-
using Key2Joy.Contracts.Util;
65

76
namespace Key2Joy.Contracts.Mapping.Actions;
87

@@ -25,8 +24,6 @@ public abstract class AbstractAction : AbstractMappingAspect
2524
/// <exception cref="System.NotImplementedException"></exception>
2625
public virtual Task Execute(AbstractInputBag inputBag = null) => throw new System.NotImplementedException();
2726

28-
public virtual string GetNameDisplay() => this.Name;
29-
3027
public AbstractAction(string name)
3128
: base(name) { }
3229

0 commit comments

Comments
 (0)