Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NEW: Added support for F13 to F24 keys #2075

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Assets/Tests/InputSystem/CorePerformanceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,13 @@ public void Performance_ReadEveryKey()

Measure.Method(() =>
{
int keyIndex = 0;
foreach (var key in keyboard.allKeys)
{
if (++keyIndex == (int)KeyEx.IMESelected) // Skip IMESelected as it's not a real key.
continue;
key.ReadValue();
}
})
.MeasurementCount(100)
.WarmupCount(5)
Expand Down
2 changes: 1 addition & 1 deletion Assets/Tests/InputSystem/CoreTests_Devices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2674,7 +2674,7 @@ public void Devices_AnyKeyOnKeyboard_DoesNotReactToIMESelected()
{
var keyboard = InputSystem.AddDevice<Keyboard>();

InputSystem.QueueStateEvent(keyboard, new KeyboardState(Key.IMESelected));
InputSystem.QueueStateEvent(keyboard, new KeyboardState(IMESelected: true));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to have a test that has an underlying struct/memory representation that looks like the previous one to prove that its backwards compatible?

InputSystem.Update();

Assert.That(keyboard.anyKey.isPressed, Is.False);
Expand Down
1 change: 1 addition & 0 deletions Packages/com.unity.inputsystem/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ however, it has to be formatted properly to pass verification tests.
### Added
- Added new API `InputSystem.settings.useIMGUIEditorForAssets` that should be used in custom `InputParameterEditor` that use both IMGUI and UI Toolkit.
- Added ProfilerMakers to `InputAction.Enable()` and `InputActionMap.ResolveBindings()` to enable gathering of profiling data.
- Added support of F13-F24 keys. [UUM-44328](https://issuetracker.unity3d.com/product/unity/issues/guid/UUM-44328)

## [1.11.2] - 2024-10-16

Expand Down
262 changes: 251 additions & 11 deletions Packages/com.unity.inputsystem/InputSystem/Devices/Keyboard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ public unsafe struct KeyboardState : IInputStateTypeInfo
/// <seealso cref="InputStateBlock.format"/>
public static FourCC Format => new FourCC('K', 'E', 'Y', 'S');

private const int kSizeInBits = Keyboard.KeyCount;
private const int kSizeInBits = Keyboard.KeyCount + 1; // +1 for IMESelected.
internal const int kSizeInBytes = (kSizeInBits + 7) / 8;

[InputControl(name = "anyKey", displayName = "Any Key", layout = "AnyKey", sizeInBits = kSizeInBits - 1, synthetic = true)] // Exclude IMESelected.
[InputControl(name = "anyKey", displayName = "Any Key", layout = "AnyKey", offset = 1, sizeInBits = (int)Key.F24, synthetic = true)]
[InputControl(name = "escape", displayName = "Escape", layout = "Key", usages = new[] {"Back", "Cancel"}, bit = (int)Key.Escape)]
[InputControl(name = "space", displayName = "Space", layout = "Key", bit = (int)Key.Space)]
[InputControl(name = "enter", displayName = "Enter", layout = "Key", usage = "Submit", bit = (int)Key.Enter)]
Expand Down Expand Up @@ -163,17 +163,41 @@ public unsafe struct KeyboardState : IInputStateTypeInfo
[InputControl(name = "OEM3", layout = "Key", bit = (int)Key.OEM3)]
[InputControl(name = "OEM4", layout = "Key", bit = (int)Key.OEM4)]
[InputControl(name = "OEM5", layout = "Key", bit = (int)Key.OEM5)]
[InputControl(name = "IMESelected", layout = "Button", bit = (int)Key.IMESelected, synthetic = true)]
[InputControl(name = "f13", displayName = "F13", layout = "Key", bit = (int)Key.F13)]
[InputControl(name = "f14", displayName = "F14", layout = "Key", bit = (int)Key.F14)]
[InputControl(name = "f15", displayName = "F15", layout = "Key", bit = (int)Key.F15)]
[InputControl(name = "f16", displayName = "F16", layout = "Key", bit = (int)Key.F16)]
[InputControl(name = "f17", displayName = "F17", layout = "Key", bit = (int)Key.F17)]
[InputControl(name = "f18", displayName = "F18", layout = "Key", bit = (int)Key.F18)]
[InputControl(name = "f19", displayName = "F19", layout = "Key", bit = (int)Key.F19)]
[InputControl(name = "f20", displayName = "F20", layout = "Key", bit = (int)Key.F20)]
[InputControl(name = "f21", displayName = "F21", layout = "Key", bit = (int)Key.F21)]
[InputControl(name = "f22", displayName = "F22", layout = "Key", bit = (int)Key.F22)]
[InputControl(name = "f23", displayName = "F23", layout = "Key", bit = (int)Key.F23)]
[InputControl(name = "f24", displayName = "F24", layout = "Key", bit = (int)Key.F24)]
[InputControl(name = "IMESelected", layout = "Button", bit = (int)KeyEx.RemappedIMESelected, synthetic = true)] // Use the last bit to hold IME selected state.
public fixed byte keys[kSizeInBytes];

public KeyboardState(params Key[] pressedKeys)
// will be the default in new editor [InputControl(name = "IMESelected", layout = "Button", bit = 0, sizeInBits = 1, synthetic = true)]
//public byte modifiers;

public KeyboardState(params Key[] pressedKeys) : this(false, pressedKeys)
{
}

public KeyboardState(bool IMESelected, params Key[] pressedKeys)
{
if (pressedKeys == null)
throw new ArgumentNullException(nameof(pressedKeys));

fixed(byte* keysPtr = keys)
{
UnsafeUtility.MemClear(keysPtr, kSizeInBytes);

if (IMESelected)
{
MemoryHelpers.WriteSingleBit(keysPtr, (uint)KeyEx.IMESelected, true);
}

for (var i = 0; i < pressedKeys.Length; ++i)
MemoryHelpers.WriteSingleBit(keysPtr, (uint)pressedKeys[i], true);
}
Expand All @@ -185,6 +209,14 @@ public void Set(Key key, bool state)
MemoryHelpers.WriteSingleBit(keysPtr, (uint)key, state);
}

internal bool Get(Key key)
{
fixed(byte* keysPtr = keys)
{
return MemoryHelpers.ReadSingleBit(keysPtr, (uint)key);
}
}

public void Press(Key key)
{
Set(key, true);
Expand Down Expand Up @@ -858,9 +890,86 @@ public enum Key
/// </summary>
OEM5,

////FIXME: This should never have been a Key but rather just an extra button or state on keyboard
// Not exactly a key, but binary data sent by the Keyboard to say if IME is being used.
IMESelected
/// <summary>
/// Don't use this. This is a dummy key that is only used internally to represent the IME selected state.
/// Will be removed in the future.
/// </summary>
[Obsolete("Don't use this. This is a dummy key that is only used internally to represent the IME selected state. Will be removed in the future.", true)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Older Input Systems would still rely on this bit

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the old input system use this?

IMESelected,

/// <summary>
/// The <see cref="Keyboard.f13Key"/>.
/// </summary>
F13,

/// <summary>
/// The <see cref="Keyboard.f14Key"/>.
/// </summary>
F14,

/// <summary>
/// The <see cref="Keyboard.f15Key"/>.
/// </summary>
F15,

/// <summary>
/// The <see cref="Keyboard.f16Key"/>.
/// </summary>
F16,

/// <summary>
/// The <see cref="Keyboard.f17Key"/>.
/// </summary>
F17,

/// <summary>
/// The <see cref="Keyboard.f18Key"/>.
/// </summary>
F18,

/// <summary>
/// The <see cref="Keyboard.f19Key"/>.
/// </summary>
F19,

/// <summary>
/// The <see cref="Keyboard.f20Key"/>.
/// </summary>
F20,

/// <summary>
/// The <see cref="Keyboard.f21Key"/>.
/// </summary>
F21,

/// <summary>
/// The <see cref="Keyboard.f22Key"/>.
/// </summary>
F22,

/// <summary>
/// The <see cref="Keyboard.f23Key"/>.
/// </summary>
F23,

/// <summary>
/// The <see cref="Keyboard.f24Key"/>.
/// </summary>
F24,

/// <summary>
/// Don't use this. This is a dummy key that is only used internally to represent the IME selected state.
/// Will be removed in the future.
/// FIXME: This should never have been a Key but rather just an extra button or state on keyboard
/// Not exactly a key, but binary data sent by the Keyboard to say if IME is being used.
/// </summary>
//InternalForIMESelected = 127,
}

internal static class KeyEx
{
internal const Key IMESelected = (Key)111; //IMESelected value
internal const Key RemappedIMESelected = (Key)127; //IMESelected value
}

/// <summary>
Expand Down Expand Up @@ -919,13 +1028,14 @@ public enum Key
/// </example>
/// <seealso cref="InputDevice"/>
[InputControlLayout(stateType = typeof(KeyboardState), isGenericTypeOfDevice = true)]
public class Keyboard : InputDevice, ITextInputReceiver
public class Keyboard : InputDevice, ITextInputReceiver, IEventPreProcessor
{
/// <summary>
/// Total number of key controls on a keyboard, i.e. the number of controls
/// in <see cref="allKeys"/>.
/// </summary>
public const int KeyCount = (int)Key.OEM5;
/// <value>Total number of key controls.</value>
public const int KeyCount = (int)Key.F24 - 1; // without IMESelected

/// <summary>
/// Event that is fired for every single character entered on the keyboard.
Expand Down Expand Up @@ -2051,6 +2161,102 @@ public string keyboardLayout
/// </remarks>
public KeyControl oem5Key => this[Key.OEM5];

/// <summary>
/// The F13 key on the keyboard
/// </summary>
/// <remarks><see cref="KeyControl"/> representing <see cref="Key.F13"/>.
/// Keyboards may have additional Functions keys that are not part of the standardized 104-key keyboard layout
/// </remarks>
public KeyControl f13Key => this[Key.F13];

/// <summary>
/// The F14 key on the keyboard
/// </summary>
/// <remarks><see cref="KeyControl"/> representing <see cref="Key.F14"/>.
/// Keyboards may have additional Functions keys that are not part of the standardized 104-key keyboard layout
/// </remarks>
public KeyControl f14Key => this[Key.F14];

/// <summary>
/// The F15 key on the keyboard
/// </summary>
/// <remarks><see cref="KeyControl"/> representing <see cref="Key.F15"/>.
/// Keyboards may have additional Functions keys that are not part of the standardized 104-key keyboard layout
/// </remarks>
public KeyControl f15Key => this[Key.F15];

/// <summary>
/// The F16 key on the keyboard
/// </summary>
/// <remarks><see cref="KeyControl"/> representing <see cref="Key.F16"/>.
/// Keyboards may have additional Functions keys that are not part of the standardized 104-key keyboard layout
/// </remarks>
public KeyControl f16Key => this[Key.F16];

/// <summary>
/// The F17 key on the keyboard
/// </summary>
/// <remarks><see cref="KeyControl"/> representing <see cref="Key.F17"/>.
/// Keyboards may have additional Functions keys that are not part of the standardized 104-key keyboard layout
/// </remarks>
public KeyControl f17Key => this[Key.F17];

/// <summary>
/// The F18 key on the keyboard
/// </summary>
/// <remarks><see cref="KeyControl"/> representing <see cref="Key.F18"/>.
/// Keyboards may have additional Functions keys that are not part of the standardized 104-key keyboard layout
/// </remarks>
public KeyControl f18Key => this[Key.F18];

/// <summary>
/// The F19 key on the keyboard
/// </summary>
/// <remarks><see cref="KeyControl"/> representing <see cref="Key.F19"/>.
/// Keyboards may have additional Functions keys that are not part of the standardized 104-key keyboard layout
/// </remarks>
public KeyControl f19Key => this[Key.F19];

/// <summary>
/// The F20 key on the keyboard
/// </summary>
/// <remarks><see cref="KeyControl"/> representing <see cref="Key.F20"/>.
/// Keyboards may have additional Functions keys that are not part of the standardized 104-key keyboard layout
/// </remarks>
public KeyControl f20Key => this[Key.F20];

/// <summary>
/// The F21 key on the keyboard
/// </summary>
/// <remarks><see cref="KeyControl"/> representing <see cref="Key.F21"/>.
/// Keyboards may have additional Functions keys that are not part of the standardized 104-key keyboard layout
/// </remarks>
public KeyControl f21Key => this[Key.F21];

/// <summary>
/// The F22 key on the keyboard
/// </summary>
/// <remarks><see cref="KeyControl"/> representing <see cref="Key.F22"/>.
/// Keyboards may have additional Functions keys that are not part of the standardized 104-key keyboard layout
/// </remarks>
public KeyControl f22Key => this[Key.F22];

/// <summary>
/// The F23 key on the keyboard
/// </summary>
/// <remarks><see cref="KeyControl"/> representing <see cref="Key.F23"/>.
/// Keyboards may have additional Functions keys that are not part of the standardized 104-key keyboard layout
/// </remarks>
public KeyControl f23Key => this[Key.F23];

/// <summary>
/// The F24 key on the keyboard
/// </summary>
/// <remarks><see cref="KeyControl"/> representing <see cref="Key.F24"/>.
/// Keyboards may have additional Functions keys that are not part of the standardized 104-key keyboard layout
/// </remarks>
public KeyControl f24Key => this[Key.F24];

/// <summary>
/// An artificial combination of <see cref="leftShiftKey"/> and <see cref="rightShiftKey"/> into one control.
/// </summary>
Expand Down Expand Up @@ -2299,17 +2505,32 @@ protected override void FinishSetup()
"oem3",
"oem4",
"oem5",
null, // IMESelected
"f13",
"f14",
"f15",
"f16",
"f17",
"f18",
"f19",
"f20",
"f21",
"f22",
"f23",
"f24",
};
m_Keys = new KeyControl[keyStrings.Length];
for (var i = 0; i < keyStrings.Length; ++i)
{
if (string.IsNullOrEmpty(keyStrings[i]))
continue;
m_Keys[i] = GetChildControl<KeyControl>(keyStrings[i]);

////REVIEW: Ideally, we'd have a way to do this through layouts; this way nested key controls could work, too,
//// and it just seems somewhat dirty to jam the data into the control here
m_Keys[i].keyCode = (Key)(i + 1);
}
Debug.Assert(keyStrings[(int)Key.OEM5 - 1] == "oem5",
Debug.Assert(keyStrings[(int)Key.F24 - 1] == "f24",
"keyString array layout doe not match Key enum layout");
anyKey = GetChildControl<AnyKeyControl>("anyKey");
shiftKey = GetChildControl<ButtonControl>("shift");
Expand Down Expand Up @@ -2431,6 +2652,25 @@ public void OnIMECompositionChanged(IMECompositionString compositionString)
}
}

public unsafe bool PreProcessEvent(InputEventPtr currentEventPtr)
{
if (currentEventPtr.type == StateEvent.Type)
{
var stateEvent = StateEvent.FromUnchecked(currentEventPtr);
if (stateEvent->stateFormat == KeyboardState.Format)
{
var keyboardState = ((KeyboardState*)(stateEvent->stateData));
if (keyboardState->Get(KeyEx.IMESelected))
{
keyboardState->Set(KeyEx.IMESelected, false);
keyboardState->Set(KeyEx.RemappedIMESelected, true);
}
}
}

return true;
}

private InlinedArray<Action<char>> m_TextInputListeners;
private string m_KeyboardLayoutName;
private KeyControl[] m_Keys;
Expand Down
Loading
Loading