Compare commits

...

10 Commits

Author SHA1 Message Date
Holly McFarland 9a6a6079d4 support controllers that aren't PlayerIndex.One 2020-04-20 14:23:35 -04:00
undergroundmonorail 63fb57d3a3
Update README.md 2020-04-19 19:14:04 -04:00
Holly a794dd5024 support all 9 stick states 2020-04-19 18:57:38 -04:00
undergroundmonorail 8347f52363
less confusing image for button override example 2020-01-31 20:39:06 -05:00
Holly 174bb2d323 add roadmap and update readme 2020-01-31 20:30:33 -05:00
Holly 0e47489209 fix some things missed during project rename 2020-01-31 20:30:09 -05:00
Holly dae7bf7708 Merge branch 'master' of https://github.com/undergroundmonorail/sticky-viewer 2020-01-31 19:23:27 -05:00
Holly 2c5915561e change name to be less generic 2020-01-31 19:20:28 -05:00
undergroundmonorail cb51b02055
Update README.md 2019-12-30 15:10:26 -05:00
undergroundmonorail e7b444a9ff
Create README.md 2019-12-30 15:00:20 -05:00
29 changed files with 177 additions and 73 deletions

19
README.md Normal file
View File

@ -0,0 +1,19 @@
# Sticky Viewer
A simple XInput input viewer designed for fightsticks. Appears always-on-top.
Currently, configuration is quite limited. Check ROADMAP.md for planned updates. Most notably, exactly five remappable buttons ~~and only left and right stick directions~~ are supported right now, because I play Fantasy Strike and that was my priority. :P **UPDATE: we got all nine valid stick positions babey**
To remap buttons, open sticky_viewer.exe.config and modify the values there. If the configuration file is missing at runtime, the values used in the unmodified file are the defaults.
## Screenshots
No inputs held:
![fightstick with no inputs held](https://i.imgur.com/TcLUlLw.png)
All buttons held and stick held left:
![fightstick with all buttons held and stick held left](https://i.imgur.com/GkvcVxI.png)
The images composing the stick and button visuals are provided and can be customized. If they're missing at runtime, these defaults are used.

40
ROADMAP.md Normal file
View File

@ -0,0 +1,40 @@
# Roadmap
These are the plans for what I want to be customizable via .config modification and supplying custom images.
## Visual Customization
### Buttons
- How many buttons are visible ☐
- Position of buttons ☐
- Which hardware button is mapped to which visible button 🗹
- Pressed and unpressed images of buttons 🗹
- Override images for specific buttons ☐
- e.g. something like this:
![overriding a specific button image with a custom one](https://i.imgur.com/QU5pTDm.png)
### Stick
- Choose between left analog, right analog or d-pad ☐
- How the stick looks 🗹
- Position of stick ☐
- Hitbox mode ☐
- Could be implemented by allowing you to turn off stick display and just adding more buttons, I guess
- Analog directions would have to be made valid button inputs, but I'm already doing something like that for LT and RT
### Window
- Location (support both x/y coords and something like BOTTOM_MIDDLE, TOP_LEFT) ☐
- Width and height ☐
- Background (support both RGBA colour and a supplied image) ☐
## Misc
- Optionally assign "close" keybind to a combination of stick buttons ☐
- Choose an XInput device instead of defaulting to whichever one is considered player 1 🗹
- ~~"Press Start" prompt if ambiguous, save to config file?~~
- Every frame, just use the controller with the lowest index and any input
- Keybinds to generate .config file and default images in execution folder ☐
- This would allow the distribution of just the .exe file. If someone wishes to customize, those default resources could be generated from the program

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29326.143
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "input_display", "input_display\input_display.csproj", "{7D0FEB20-AB4F-4E57-AD69-CC88D4423F53}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sticky_viewer", "sticky_viewer\sticky_viewer.csproj", "{7D0FEB20-AB4F-4E57-AD69-CC88D4423F53}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@ -1,13 +1,14 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
namespace input_display
namespace sticky_viewer
{
/// <summary>
/// Access functionality from user32.dll
@ -31,6 +32,12 @@ namespace input_display
private Texture2D pressed;
private Texture2D unpressed;
private Texture2D upleft;
private Texture2D up;
private Texture2D upright;
private Texture2D downleft;
private Texture2D down;
private Texture2D downright;
private Texture2D left;
private Texture2D neutral;
private Texture2D right;
@ -41,7 +48,6 @@ namespace input_display
private Texture2D C;
private Texture2D J;
private Texture2D S;
public Display()
{
graphics = new GraphicsDeviceManager(this);
@ -66,6 +72,27 @@ namespace input_display
base.Initialize();
}
Stream GetStreamFromFileOrAssembly(Assembly assembly, string s)
{
try
{
return new FileStream($"{s}.png", FileMode.Open);
}
catch
{
// uh oh,! time to panic
return assembly.GetManifestResourceStream(assembly.GetName().Name.Replace(' ', '_') + $".Content.{s}.png");
}
}
Texture2D GetTexture(Assembly assembly, string s)
{
using (Stream stream = GetStreamFromFileOrAssembly(assembly, s))
{
return Texture2D.FromStream(GraphicsDevice, stream);
}
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
@ -85,66 +112,20 @@ namespace input_display
// default images
Assembly assembly = Assembly.GetExecutingAssembly();
Stream dataStream = assembly.GetManifestResourceStream(assembly.GetName().Name.Replace(' ', '_') + ".Content.left.png");
left = Texture2D.FromStream(GraphicsDevice, dataStream);
dataStream.Dispose();
dataStream = assembly.GetManifestResourceStream(assembly.GetName().Name.Replace(' ', '_') + ".Content.neutral.png");
neutral = Texture2D.FromStream(GraphicsDevice, dataStream);
dataStream.Dispose();
dataStream = assembly.GetManifestResourceStream(assembly.GetName().Name.Replace(' ', '_') + ".Content.right.png");
right = Texture2D.FromStream(GraphicsDevice, dataStream);
dataStream.Dispose();
dataStream = assembly.GetManifestResourceStream(assembly.GetName().Name.Replace(' ', '_') + ".Content.pressed.png");
pressed = Texture2D.FromStream(GraphicsDevice, dataStream);
dataStream.Dispose();
dataStream = assembly.GetManifestResourceStream(assembly.GetName().Name.Replace(' ', '_') + ".Content.unpressed.png");
unpressed = Texture2D.FromStream(GraphicsDevice, dataStream);
dataStream.Dispose();
pressed = GetTexture(assembly, "pressed");
unpressed = GetTexture(assembly, "unpressed");
upleft = GetTexture(assembly, "upleft");
up = GetTexture(assembly, "up");
upright = GetTexture(assembly, "upright");
left = GetTexture(assembly, "left");
neutral = GetTexture(assembly, "neutral");
right = GetTexture(assembly, "right");
downleft = GetTexture(assembly, "downleft");
down = GetTexture(assembly, "down");
downright = GetTexture(assembly, "downright");
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// If an image file exists, replace the one in memory with it
FileStream fileStream;
if (File.Exists("pressed.png"))
{
fileStream = new FileStream("pressed.png", FileMode.Open);
pressed = Texture2D.FromStream(GraphicsDevice, fileStream);
fileStream.Dispose();
}
if (File.Exists("unpressed.png"))
{
fileStream = new FileStream("unpressed.png", FileMode.Open);
unpressed = Texture2D.FromStream(GraphicsDevice, fileStream);
fileStream.Dispose();
}
if (File.Exists("left.png"))
{
fileStream = new FileStream("left.png", FileMode.Open);
left = Texture2D.FromStream(GraphicsDevice, fileStream);
fileStream.Dispose();
}
if (File.Exists("neutral.png"))
{
fileStream = new FileStream("neutral.png", FileMode.Open);
neutral = Texture2D.FromStream(GraphicsDevice, fileStream);
fileStream.Dispose();
}
if (File.Exists("right.png"))
{
fileStream = new FileStream("right.png", FileMode.Open);
right = Texture2D.FromStream(GraphicsDevice, fileStream);
fileStream.Dispose();
}
}
/// <summary>
@ -168,19 +149,53 @@ namespace input_display
Exit();
}
if (GamePad.GetState(PlayerIndex.One).DPad.Left == ButtonState.Pressed)
// Find the controller being used currently
GamePadState emptyInput = new GamePadState();
GamePadState currentState = new GamePadState();
foreach (PlayerIndex p in Enum.GetValues(typeof(PlayerIndex)))
{
if ((currentState = GamePad.GetState(p)) != emptyInput) { break; }
}
GamePadDPad dpad = currentState.DPad;
if (dpad.Up == ButtonState.Pressed && dpad.Left == ButtonState.Pressed)
{
stick = upleft;
}
else if (dpad.Up == ButtonState.Pressed && dpad.Right == ButtonState.Pressed)
{
stick = upright;
}
else if (dpad.Up == ButtonState.Pressed)
{
stick = up;
}
else if (dpad.Down == ButtonState.Pressed && dpad.Left == ButtonState.Pressed)
{
stick = downleft;
}
else if (dpad.Down == ButtonState.Pressed && dpad.Right == ButtonState.Pressed)
{
stick = downright;
}
else if (dpad.Down == ButtonState.Pressed)
{
stick = down;
}
else if (dpad.Left == ButtonState.Pressed)
{
stick = left;
} else if (GamePad.GetState(PlayerIndex.One).DPad.Right == ButtonState.Pressed)
}
else if (dpad.Right == ButtonState.Pressed)
{
stick = right;
} else
}
else
{
stick = neutral;
}
GamePadState currentState = GamePad.GetState(PlayerIndex.One);
Dictionary<string, bool> inputs = new Dictionary<string, bool>()
{
{"A", currentState.Buttons.A == ButtonState.Pressed},
@ -212,7 +227,7 @@ namespace input_display
spriteBatch.Begin();
spriteBatch.Draw(stick, new Vector2(16, 24), Color.White);
spriteBatch.Draw(stick, new Vector2(21, 16), Color.White);
spriteBatch.Draw(A, new Vector2(96, 11), Color.White);
spriteBatch.Draw(B, new Vector2(128, 6), Color.White);
spriteBatch.Draw(C, new Vector2(161, 6), Color.White);

View File

Before

Width:  |  Height:  |  Size: 167 KiB

After

Width:  |  Height:  |  Size: 167 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -1,6 +1,6 @@
using System;
namespace input_display
namespace sticky_viewer
{
#if WINDOWS || LINUX
/// <summary>

View File

@ -5,8 +5,8 @@ using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("input display")]
[assembly: AssemblyProduct("input display")]
[assembly: AssemblyTitle("Sticky Viewer")]
[assembly: AssemblyProduct("Sticky Viewer")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyCompany("")]

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="input_display"/>
<assemblyIdentity version="1.0.0.0" name="sticky_viewer"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">

View File

@ -10,8 +10,8 @@
<ProjectGuid>{7D0FEB20-AB4F-4E57-AD69-CC88D4423F53}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>input_display</RootNamespace>
<AssemblyName>input_display</AssemblyName>
<RootNamespace>sticky_viewer</RootNamespace>
<AssemblyName>sticky_viewer</AssemblyName>
<FileAlignment>512</FileAlignment>
<MonoGamePlatform>Windows</MonoGamePlatform>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
@ -57,6 +57,30 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Content\upleft.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>upleft.png</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Content\up.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>up.png</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Content\upright.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>upright.png</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Content\downleft.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>downleft.png</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Content\down.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>down.png</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Content\downright.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>downright.png</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Content\left.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>left.png</TargetPath>
@ -92,6 +116,12 @@
<EmbeddedResource Include="Content\unpressed.png">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="Content\down.png" />
<EmbeddedResource Include="Content\downleft.png" />
<EmbeddedResource Include="Content\downright.png" />
<EmbeddedResource Include="Content\up.png" />
<EmbeddedResource Include="Content\upleft.png" />
<EmbeddedResource Include="Content\upright.png" />
<Content Include="Icon.ico" />
</ItemGroup>
<ItemGroup>