-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
Showing
191 changed files
with
18,460 additions
and
9,768 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,36 @@ | ||
using System; | ||
using System.Text.Json.Serialization; | ||
using Key2Joy.Contracts.Mapping.Actions; | ||
using Key2Joy.Contracts.Mapping.Triggers; | ||
|
||
namespace Key2Joy.Contracts.Mapping; | ||
|
||
public abstract class AbstractMappedOption : ICloneable | ||
{ | ||
[JsonInclude] | ||
public AbstractAction Action { get; set; } | ||
[JsonInclude] | ||
public AbstractTrigger Trigger { get; set; } | ||
|
||
public abstract object Clone(); | ||
} | ||
using System; | ||
using System.Text.Json.Serialization; | ||
using Key2Joy.Contracts.Mapping.Actions; | ||
using Key2Joy.Contracts.Mapping.Triggers; | ||
|
||
namespace Key2Joy.Contracts.Mapping; | ||
|
||
public abstract class AbstractMappedOption : ICloneable | ||
{ | ||
/// <summary> | ||
/// The unique identifier for this mapping. | ||
/// This way it can be referenced by other mappings. | ||
/// </summary> | ||
[JsonInclude] | ||
public Guid Guid { get; protected set; } | ||
|
||
/// <summary> | ||
/// The action that is executed when this mapping is executed. | ||
/// </summary> | ||
[JsonInclude] | ||
public AbstractAction Action { get; set; } | ||
|
||
/// <summary> | ||
/// The trigger that causes this mapping to be executed. | ||
/// </summary> | ||
[JsonInclude] | ||
public AbstractTrigger Trigger { get; set; } | ||
|
||
/// <summary> | ||
/// The unique identifier of the parent mapped option. | ||
/// </summary> | ||
[JsonInclude] | ||
public Guid? ParentGuid { get; set; } = null; | ||
|
||
public abstract object Clone(); | ||
} |
298 changes: 156 additions & 142 deletions
298
Core/Key2Joy.Contracts/Mapping/AbstractMappingAspect.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,142 +1,156 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Key2Joy.Contracts.Mapping; | ||
|
||
public abstract class AbstractMappingAspect : MarshalByRefObject, ICloneable, IComparable<AbstractMappingAspect> | ||
{ | ||
public string Name { get; set; } | ||
|
||
public AbstractMappingAspect(string name) => this.Name = name; | ||
|
||
private PropertyInfo[] GetProperties() | ||
{ | ||
var type = this.GetType(); | ||
var properties = type.GetProperties(); | ||
|
||
return properties.Where(p => p.GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Length == 0).ToArray(); | ||
} | ||
|
||
public virtual MappingAspectOptions SaveOptions() | ||
{ | ||
MappingAspectOptions options = new(); | ||
var properties = this.GetProperties(); | ||
|
||
foreach (var property in properties) | ||
{ | ||
this.SaveOptionsGetProperty(options, property); | ||
} | ||
|
||
return options; | ||
} | ||
|
||
/// <summary> | ||
/// Can be overridden by child actions or triggers to allow saving more complex types. | ||
/// </summary> | ||
/// <param name="property"></param> | ||
/// <param name="value"></param> | ||
protected virtual void SaveOptionsGetProperty(MappingAspectOptions options, PropertyInfo property) | ||
{ | ||
var value = property.GetValue(this); | ||
|
||
switch (value) | ||
{ | ||
case DateTime dateTime: | ||
value = dateTime.Ticks; | ||
break; | ||
|
||
default: | ||
break; | ||
} | ||
|
||
options.Add(property.Name, value); | ||
} | ||
|
||
public virtual void LoadOptions(MappingAspectOptions options) | ||
{ | ||
var properties = this.GetProperties(); | ||
|
||
foreach (var property in properties) | ||
{ | ||
if (!options.ContainsKey(property.Name)) | ||
{ | ||
continue; | ||
} | ||
|
||
this.LoadOptionSetProperty(options, property); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Can be overridden by child actions or triggers to allow loading more complex types. | ||
/// </summary> | ||
/// <param name="property"></param> | ||
/// <param name="value"></param> | ||
protected virtual void LoadOptionSetProperty(MappingAspectOptions options, PropertyInfo property) | ||
{ | ||
var propertyType = property.PropertyType; | ||
var value = options[property.Name]; | ||
var genericTypeDefinition = propertyType.IsGenericType ? propertyType.GetGenericTypeDefinition() : null; | ||
|
||
if (propertyType.IsEnum) | ||
{ | ||
value = Enum.Parse(propertyType, (string)value); | ||
} | ||
else if (propertyType == typeof(DateTime)) | ||
{ | ||
value = new DateTime(Convert.ToInt64(value)); | ||
} | ||
else if (propertyType.IsGenericType | ||
&& (genericTypeDefinition == typeof(List<>) || genericTypeDefinition == typeof(IList<>))) | ||
{ | ||
var constructedListType = typeof(List<>).MakeGenericType(propertyType.GetGenericArguments()); | ||
var instance = Activator.CreateInstance(constructedListType); | ||
|
||
if (value is List<object> list) | ||
{ | ||
var addMethod = constructedListType.GetMethod("Add"); | ||
|
||
foreach (var item in list) | ||
{ | ||
addMethod.Invoke(instance, new object[] { item }); | ||
} | ||
|
||
value = instance; | ||
} | ||
else | ||
{ | ||
throw new ArgumentException($"Expected value to be of type List<> to parse. But was: {value.GetType()}"); | ||
} | ||
} | ||
else | ||
{ | ||
value = Convert.ChangeType(value, propertyType); | ||
} | ||
|
||
property.SetValue(this, value); | ||
} | ||
|
||
public virtual int CompareTo(AbstractMappingAspect other) => this.ToString().CompareTo(other.ToString()); | ||
|
||
public static bool operator ==(AbstractMappingAspect a, AbstractMappingAspect b) | ||
{ | ||
if (ReferenceEquals(a, b)) | ||
{ | ||
return true; | ||
} | ||
|
||
if (a is null || b is null) | ||
{ | ||
return false; | ||
} | ||
|
||
return a.Equals(b); | ||
} | ||
|
||
public static bool operator !=(AbstractMappingAspect a, AbstractMappingAspect b) => !(a == b); | ||
|
||
public virtual object Clone() => this.MemberwiseClone(); | ||
} | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Key2Joy.Contracts.Mapping; | ||
|
||
public abstract class AbstractMappingAspect : MarshalByRefObject, ICloneable, IComparable<AbstractMappingAspect> | ||
{ | ||
public string Name { get; set; } | ||
|
||
public AbstractMappingAspect(string name) => this.Name = name; | ||
|
||
public virtual string GetNameDisplay() => this.Name; | ||
|
||
public override string ToString() => this.GetNameDisplay(); | ||
|
||
private PropertyInfo[] GetProperties() | ||
{ | ||
var type = this.GetType(); | ||
var properties = type.GetProperties(); | ||
|
||
return properties.Where(p => p.GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Length == 0).ToArray(); | ||
} | ||
|
||
public virtual MappingAspectOptions SaveOptions() | ||
{ | ||
MappingAspectOptions options = new(); | ||
var properties = this.GetProperties(); | ||
|
||
foreach (var property in properties) | ||
{ | ||
this.SaveOptionsGetProperty(options, property); | ||
} | ||
|
||
return options; | ||
} | ||
|
||
/// <summary> | ||
/// Can be overridden by child actions or triggers to allow saving more complex types. | ||
/// </summary> | ||
/// <param name="property"></param> | ||
/// <param name="value"></param> | ||
protected virtual void SaveOptionsGetProperty(MappingAspectOptions options, PropertyInfo property) | ||
{ | ||
var value = property.GetValue(this); | ||
|
||
switch (value) | ||
{ | ||
case DateTime dateTime: | ||
value = dateTime.Ticks; | ||
break; | ||
|
||
default: | ||
break; | ||
} | ||
|
||
options.Add(property.Name, value); | ||
} | ||
|
||
public virtual void LoadOptions(MappingAspectOptions options) | ||
{ | ||
var properties = this.GetProperties(); | ||
|
||
foreach (var property in properties) | ||
{ | ||
if (!options.ContainsKey(property.Name)) | ||
{ | ||
continue; | ||
} | ||
|
||
this.LoadOptionSetProperty(options, property); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Can be overridden by child actions or triggers to allow loading more complex types. | ||
/// </summary> | ||
/// <param name="property"></param> | ||
/// <param name="value"></param> | ||
protected virtual void LoadOptionSetProperty(MappingAspectOptions options, PropertyInfo property) | ||
{ | ||
var propertyType = property.PropertyType; | ||
var value = options[property.Name]; | ||
var genericTypeDefinition = propertyType.IsGenericType ? propertyType.GetGenericTypeDefinition() : null; | ||
|
||
propertyType = Nullable.GetUnderlyingType(propertyType) ?? propertyType; | ||
|
||
if (propertyType.IsEnum) | ||
{ | ||
value = Enum.Parse(propertyType, (string)value); | ||
} | ||
else if (propertyType == typeof(DateTime)) | ||
{ | ||
value = new DateTime(Convert.ToInt64(value)); | ||
} | ||
else if (propertyType == typeof(TimeSpan)) | ||
{ | ||
value = TimeSpan.Parse((string)value); | ||
} | ||
else if (propertyType == typeof(short)) | ||
{ | ||
value = Convert.ToInt16(value); | ||
} | ||
else if (propertyType.IsGenericType | ||
&& (genericTypeDefinition == typeof(List<>) || genericTypeDefinition == typeof(IList<>))) | ||
{ | ||
var constructedListType = typeof(List<>).MakeGenericType(propertyType.GetGenericArguments()); | ||
var instance = Activator.CreateInstance(constructedListType); | ||
|
||
if (value is List<object> list) | ||
{ | ||
var addMethod = constructedListType.GetMethod("Add"); | ||
|
||
foreach (var item in list) | ||
{ | ||
addMethod.Invoke(instance, new object[] { item }); | ||
} | ||
|
||
value = instance; | ||
} | ||
else | ||
{ | ||
throw new ArgumentException($"Expected value to be of type List<> to parse. But was: {value.GetType()}"); | ||
} | ||
} | ||
else if (value != null) | ||
{ | ||
value = Convert.ChangeType(value, propertyType); | ||
} | ||
|
||
property.SetValue(this, value); | ||
} | ||
|
||
public virtual int CompareTo(AbstractMappingAspect other) => this.ToString().CompareTo(other.ToString()); | ||
|
||
public static bool operator ==(AbstractMappingAspect a, AbstractMappingAspect b) | ||
{ | ||
if (ReferenceEquals(a, b)) | ||
{ | ||
return true; | ||
} | ||
|
||
if (a is null || b is null) | ||
{ | ||
return false; | ||
} | ||
|
||
return a.Equals(b); | ||
} | ||
|
||
public static bool operator !=(AbstractMappingAspect a, AbstractMappingAspect b) => !(a == b); | ||
|
||
public virtual object Clone() => this.MemberwiseClone(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.