-
Notifications
You must be signed in to change notification settings - Fork 724
Fixes #3071 & #3079. Key cast and static props are not correct #3089
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
Conversation
public Key (char ch) | ||
{ | ||
switch (ch) { | ||
case >= 'A' and <= 'Z': | ||
// Upper case A..Z mean "Shift-char" so we need to add Shift | ||
KeyCode = (KeyCode)ch | KeyCode.ShiftMask; | ||
break; | ||
case >= 'a' and <= 'z': | ||
// Lower case a..z mean no shift, so we need to store as Key.A...Key.Z | ||
KeyCode = (KeyCode)(ch - 32); | ||
return; | ||
default: | ||
KeyCode = (KeyCode)ch; | ||
break; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tig you can leverage this code https://github.com/BDisp/Terminal.Gui/blob/9349d542974c6eb59044b3ca4716cc1a25101321/Terminal.Gui/Input/Key.cs#L195-L253 to get the shift or not based on more range of characters to allow test this:
[InlineData ('á', (KeyCode)'á')]
[InlineData ('Á', (KeyCode)'Á' | KeyCode.ShiftMask)]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that is correct behavior. Is it really needed for VK packet support or is it something you think is a nice-to-have?
If it's not absolutely needed for VK packet support then I'd prefer to have A..Z be the only keys supported in the test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah if it's only needed for the tests ok, but you still need this for TextView
recognize that they are valid characters to pass on the GetIsKeyCodeAtoZ
method to insert the text.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An aside, as I've been looking at all these tests:
Might I suggest using MemberData to generate test cases instead of all the InlineData?
It's xUnit's analogue to NUnit's TestCaseSource and would allow you to have more exhaustive and authoritative tests with less work and less code.
The general pattern is:
[Theory]
[MemberData(nameof(TheoryA_Cases))]
public void TheoryA( string s, int i, object o )
{
// Test code
}
private static IEnumerable<object[]> TheoryA_Cases()
{
// Code that provides an IEnumerable of 3-element object arrays that satisfy the parameters of the test.
}
xUnit's documentation is sorely lacking, but that's the basic pattern for using that.
I do not know if xUnit has a way to generate tests from combinatorial parameter sources, but that effect can be achieved by just doing the combinatorial loops yourself in the case generator method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right and that's fine, because the information is still there. As long as you can round-trip it, you're golden.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only exceptions where a shift key can be added alone to a
Key
is when a non-printable character is used, like F1..F12, cursor keys, delete, backspace, etc.
Makes perfect sense.
Theoretical question, though:
Say I have a string on the clipboard that has all characters my keyboard can produce - letters, digits, symbols, and whitespace - and I paste that string while holding ctrl.
Would characters such as the ! be interpreted as "ctrl+shift+D1"? Or would they come across as just D1? Or would they come across as ctrl+D1? Or do they not even take that path and only ever come in as a literal "!"?🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my PR I was creating as (KeyCode)'!' | KeyCode.ShiftMask
to leverage the character. ConsoleKeyInfo
parses it as KeyChar='!', Key=ConsoleKey.D1, ConsoleModifiers.Shift
.
Pasting from the clipboard only will return the clipboard content and not the ctrl key and will return as (KeyCode)'!' | KeyCode.ShiftMask
. In TextField
you use the Ctrl+V
to paste and in TextView
you use the Ctrl+Y
.
But now the problem adding only a shift key on a character other than A..Z, because the shift key is removed from the Key
before insert the text in a TextView
and not for the others characters. Because of this issue, Terminal.Gui
never added before the shift key alone on printable character. Now it's only possible to A..Z and thus is impossible normalize all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tell me the user scenario that no longer works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that is correct behavior. Is it really needed for VK packet support or is it something you think is a nice-to-have?
With the current Key
code is the correct behavior if the GetIsKeyCodeAtoZ
is to persist always because the shift key does not is present only from A..Z. It's good to have, although the shift key must be removed before sending to a consumer and the IsShift
indicates whether the shift key was pressed.
If it's not absolutely needed for VK packet support then I'd prefer to have A..Z be the only keys supported in the test.
With the current Key
code that only is supporting the shift key for A..Z, this is needed for the VK packet support as well.
I already proved that 'Ó'
is (Key)'Ó' | Key.Shift
but there are also others printable character that has the shift key, like !"#$%&/()=?»*ª>;:_
. There are two options:
- Not including only the shift key to any printable character as before which will not provide the
IsShift
property astrue
. - Including the shift key to any printable character which will provide the
IsShift
property astrue
. I prefer this one but if the first is preferable the theGetIsKeyCodeAtoZ
must be removed and treat all as equal as before.
What do you think of maybe also adding a constructor taking string that essentially operates as a Parse method would, and/or adding a Parse method (ie a normal/non-try version of TryParse)? I'm always a fan of implementing the TryX pattern, but Try and non-Try versions each have their valid use cases, and providing both requires no code duplication, since one can simply delegate to the other. "Regular" Parse methods also provide the opportunity to communicate to the caller why the parse failed, rather than simply that it failed, if appropriate exceptions are thrown, whereas a TryParse method requires stepping through foreign source to trace the cause of a false result. |
💯 👆 |
I'm also finding, at least from the usage in TerminalGuiDesigner, as I'm adapting it to match the new Key type, that an implicit cast operator to and from string that use ToString() and Parse() respectively would be a pretty nice thing to have, and would feel really natural in use. It would also make configuration a ton easier, since M.E.C. looks for string conversions for incoming data to the declared type. |
Done. |
[InlineData ("Shift+A", KeyCode.A | KeyCode.ShiftMask)] | ||
[InlineData ("A", KeyCode.A | KeyCode.ShiftMask)] | ||
[InlineData ("â", (KeyCode)'â')] | ||
[InlineData ("Shift+â", (KeyCode)'â' | KeyCode.ShiftMask)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is wrong. 'â' is the lower case of 'Â'. So it haven't the shift key. Only the 'Â' has the shift key. Because of only consider the A..Z for the test the logic of the shift key is broken.
@BDisp I'm going to merge this now, ahead of me reviewing the VKPacket PR. I can't keep my changes and your suggestions straight in my head as-is. I know we disagree on something fundamental, and I'm eager to understand the crux of our disagreement, but I don't have clarity yet. |
…rrect (gui-cs#3089) * Removed char->Key cast. Added Key(char) * Re-added char->key cast. Added unit tests * Fixed standard keys to always return new instead of being readonly * Re-fixed WindowsDriver to report shift/alt/ctrl as key/down/up * Re-fixed WindowsDriver to report shift/alt/ctrl as key/down/up * Adds string constructor to Key + tests. * Simplified Key json * Added string/Key cast operators.
Fixes #3071
Fixes #3079
Fixes #3081
new Key (char)
constructor(char)Key
cast to use char constructorPull Request checklist:
CTRL-K-D
to automatically reformat your files before committing.dotnet test
before commit///
style comments)