Repository navigation
Расширенный метод обработки нажатия кнопок в консольке. #1801
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
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| Пока Истина Цикл | ||
|
|
||
| Нажатие = Консоль.ПрочитатьНажатие(); | ||
|
|
||
| Сообщить("Код кнопки: " + Нажатие.КодКнопки); | ||
|
|
||
| Если Нажатие.Модификаторы.Control Тогда | ||
| Сообщить("Ctrl + " + Нажатие.Символ); | ||
| ИначеЕсли Нажатие.Модификаторы.Shift Тогда | ||
| Сообщить("Shift + " + Нажатие.Символ); | ||
| ИначеЕсли Нажатие.Модификаторы.Alt Тогда | ||
| Сообщить("Alt + " + Нажатие.Символ); | ||
| Иначе | ||
| Сообщить(Нажатие.Символ); | ||
| КонецЕсли; | ||
|
|
||
| Если Нажатие.КодКнопки = 27 Тогда // Escape | ||
| Сообщить("Выход"); | ||
| Прервать; | ||
| КонецЕсли; | ||
|
|
||
| КонецЦикла; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,7 @@ | |
| using OneScript.Exceptions; | ||
| using OneScript.Execution; | ||
| using OneScript.StandardLibrary.Binary; | ||
| using OneScript.StandardLibrary.Collections; | ||
| using OneScript.Values; | ||
| using ScriptEngine.Machine; | ||
| using ScriptEngine.Machine.Contexts; | ||
|
|
@@ -88,6 +89,63 @@ | |
| return (int)kki.Key; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Читает нажатие клавиши и возвращает подробное описание нажатия. | ||
| /// В отличие от <see cref="ReadKey"/>, возвращает не только код клавиши, но и введённый символ | ||
| /// (в том числе кириллический), а также состояние модификаторов. | ||
| /// Символ не выводится в консоль (чтение выполняется без эха). | ||
| /// </summary> | ||
| /// <returns> | ||
| /// Структура с полями: | ||
| /// <list type="bullet"> | ||
| /// <item><description><c>КодКнопки</c> — код клавиши (значение перечисления <see cref="ConsoleKey"/>), | ||
| /// совпадает с результатом <see cref="ReadKey"/>;</description></item> | ||
| /// <item><description><c>Символ</c> — введённый символ; пустая строка для служебных клавиш | ||
| /// и управляющих сочетаний;</description></item> | ||
| /// <item><description><c>Модификаторы</c> — структура с булевыми полями <c>Shift</c>, <c>Alt</c>, <c>Control</c>.</description></item> | ||
| /// </list> | ||
| /// </returns> | ||
| /// <remarks> | ||
| /// Возможности платформы различаются: | ||
| /// <list type="bullet"> | ||
| /// <item><description>в Windows код клавиши и состояние модификаторов определяются для любых нажатий;</description></item> | ||
| /// <item><description>в Unix-подобных системах .NET распознаёт клавиши и модификаторы только для известных | ||
| /// символов и управляющих последовательностей. Для символов за пределами ASCII (в том числе кириллицы) | ||
| /// <c>КодКнопки</c> может быть равен 0, а <c>Shift</c> для заглавной кириллической буквы может не определиться | ||
| /// (при этом сам символ всегда возвращается в поле <c>Символ</c>).</description></item> | ||
| /// </list> | ||
| /// </remarks> | ||
| [ContextMethod("ПрочитатьНажатие", "ReadKeyPress")] | ||
| public StructureImpl ReadKeyPress() | ||
|
Check notice on line 119 in src/OneScript.StandardLibrary/Text/ConsoleContext.cs
|
||
| { | ||
| return CreateKeyPressInfo(Console.ReadKey(true)); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Преобразует нажатие, полученное от <see cref="Console.ReadKey(bool)"/>, | ||
| /// в структуру, доступную из BSL. | ||
| /// </summary> | ||
| internal static StructureImpl CreateKeyPressInfo(ConsoleKeyInfo keyInfo) | ||
| { | ||
| var modifiers = new StructureImpl( | ||
| "Shift, Alt, Control", | ||
| ValueFactory.Create((keyInfo.Modifiers & ConsoleModifiers.Shift) != 0), | ||
| ValueFactory.Create((keyInfo.Modifiers & ConsoleModifiers.Alt) != 0), | ||
| ValueFactory.Create((keyInfo.Modifiers & ConsoleModifiers.Control) != 0)); | ||
|
|
||
| var result = new StructureImpl(); | ||
| result.Insert("КодКнопки", ValueFactory.Create((int)keyInfo.Key)); | ||
| result.Insert("Символ", ValueFactory.Create(GetPrintableSymbol(keyInfo.KeyChar))); | ||
| result.Insert("Модификаторы", modifiers); | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| private static string GetPrintableSymbol(char keyChar) | ||
| { | ||
| return char.IsControl(keyChar) ? string.Empty : keyChar.ToString(); | ||
| } | ||
|
Comment on lines
+144
to
+147
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| [ContextMethod("Очистить", "Clear")] | ||
| public void Clear() | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| /*---------------------------------------------------------- | ||
| This Source Code Form is subject to the terms of the | ||
| Mozilla Public License, v.2.0. If a copy of the MPL | ||
| was not distributed with this file, You can obtain one | ||
| at http://mozilla.org/MPL/2.0/. | ||
| ----------------------------------------------------------*/ | ||
|
|
||
| using System; | ||
| using System.Reflection; | ||
| using OneScript.Contexts; | ||
| using OneScript.StandardLibrary.Collections; | ||
| using OneScript.StandardLibrary.Text; | ||
| using OneScript.Values; | ||
| using ScriptEngine.Machine; | ||
| using Xunit; | ||
|
|
||
| namespace OneScript.StandardLibrary.Tests | ||
| { | ||
| public class ConsoleContextTests | ||
| { | ||
| private static IValue GetProperty(StructureImpl structure, string name) => | ||
| structure.GetPropValue(structure.GetPropertyNumber(name)); | ||
|
|
||
| private static int GetNumber(StructureImpl structure, string name) => | ||
| (BslNumericValue)GetProperty(structure, name); | ||
|
|
||
| private static string GetString(StructureImpl structure, string name) => | ||
| (BslStringValue)GetProperty(structure, name); | ||
|
|
||
| private static bool GetBoolean(StructureImpl structure, string name) => | ||
| (bool)(BslBooleanValue)GetProperty(structure, name); | ||
|
|
||
| private static StructureImpl GetNestedStructure(StructureImpl structure, string name) => | ||
| (StructureImpl)GetProperty(structure, name); | ||
|
|
||
| [Fact] | ||
| public void ReadKeyPress_Is_Exposed_With_Bilingual_Name() | ||
| { | ||
| var method = typeof(ConsoleContext).GetMethod(nameof(ConsoleContext.ReadKeyPress)); | ||
|
|
||
| Assert.NotNull(method); | ||
|
|
||
| var attribute = method!.GetCustomAttribute<ContextMethodAttribute>(); | ||
| Assert.NotNull(attribute); | ||
| Assert.Equal("ПрочитатьНажатие", attribute!.Name); | ||
| Assert.Equal("ReadKeyPress", attribute.Alias); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void KeyPressInfo_Results_Have_Expected_Structure() | ||
| { | ||
| var keyPress = ConsoleContext.CreateKeyPressInfo( | ||
| new ConsoleKeyInfo('ф', (ConsoleKey)0, false, false, false)); | ||
|
|
||
| Assert.Equal(3, keyPress.GetPropCount()); | ||
| Assert.Equal("КодКнопки", keyPress.GetPropName(0)); | ||
| Assert.Equal("Символ", keyPress.GetPropName(1)); | ||
| Assert.Equal("Модификаторы", keyPress.GetPropName(2)); | ||
|
|
||
| var modifiers = GetNestedStructure(keyPress, "Модификаторы"); | ||
| Assert.Equal(3, modifiers.GetPropCount()); | ||
| Assert.Equal("Shift", modifiers.GetPropName(0)); | ||
| Assert.Equal("Alt", modifiers.GetPropName(1)); | ||
| Assert.Equal("Control", modifiers.GetPropName(2)); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void KeyPressInfo_Returns_Cyrillic_Symbol() | ||
| { | ||
| var keyPress = ConsoleContext.CreateKeyPressInfo( | ||
| new ConsoleKeyInfo('ф', (ConsoleKey)0, false, false, false)); | ||
|
|
||
| Assert.Equal("ф", GetString(keyPress, "Символ")); | ||
| Assert.Equal(0, GetNumber(keyPress, "КодКнопки")); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void KeyPressInfo_Returns_Upper_Case_Cyrillic_Symbol_With_Shift() | ||
| { | ||
| var keyPress = ConsoleContext.CreateKeyPressInfo( | ||
| new ConsoleKeyInfo('Ф', (ConsoleKey)0, shift: true, alt: true, control: false)); | ||
|
|
||
| Assert.Equal("Ф", GetString(keyPress, "Символ")); | ||
|
|
||
| var modifiers = GetNestedStructure(keyPress, "Модификаторы"); | ||
| Assert.True(GetBoolean(modifiers, "Shift")); | ||
| Assert.True(GetBoolean(modifiers, "Alt")); | ||
| Assert.False(GetBoolean(modifiers, "Control")); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void KeyPressInfo_Returns_Empty_Symbol_For_Control_Key_Combination() | ||
| { | ||
| // Ctrl+A: .NET сообщает управляющий символ и код клавиши A | ||
| var keyPress = ConsoleContext.CreateKeyPressInfo( | ||
| new ConsoleKeyInfo('\u0001', ConsoleKey.A, shift: false, alt: false, control: true)); | ||
|
|
||
| Assert.Equal(string.Empty, GetString(keyPress, "Символ")); | ||
| Assert.Equal((int)ConsoleKey.A, GetNumber(keyPress, "КодКнопки")); | ||
|
|
||
| var modifiers = GetNestedStructure(keyPress, "Модификаторы"); | ||
| Assert.True(GetBoolean(modifiers, "Control")); | ||
| Assert.False(GetBoolean(modifiers, "Shift")); | ||
| Assert.False(GetBoolean(modifiers, "Alt")); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void KeyPressInfo_Returns_Empty_Symbol_For_Function_Key() | ||
| { | ||
| var keyPress = ConsoleContext.CreateKeyPressInfo( | ||
| new ConsoleKeyInfo('\0', ConsoleKey.F1, false, false, false)); | ||
|
|
||
| Assert.Equal(string.Empty, GetString(keyPress, "Символ")); | ||
| Assert.Equal((int)ConsoleKey.F1, GetNumber(keyPress, "КодКнопки")); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void KeyPressInfo_Keeps_Space_As_Symbol() | ||
| { | ||
| var keyPress = ConsoleContext.CreateKeyPressInfo( | ||
| new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false)); | ||
|
|
||
| Assert.Equal(" ", GetString(keyPress, "Символ")); | ||
| } | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.