How can I set a char variable to the KeyCode of Input.GetKey? - c#

I'm trying to make a cheat code system. I had an array of chars. I want to assign whatever input the player puts in to that char, and then ill change the index to the next char and repeat with that. At the end I want to combine all the chars together to a string and see if that's a cheat code. If it is then the player will get a powerup or whatever.
I basically want the char to be whatever button I press. Is there any better way to do it that's not like this:
if (Input.GetKeyDown(KeyCode.A))
{
CodeAttempt[index] = 'a'
index++;
}
if (Input.GetKeyDown(KeyCode.C))
{
CodeAttempt[index] = 'b'
index++;
}
if (Input.GetKeyDown(KeyCode.C))
{
CodeAttempt[index] = 'c'
index++;
}
And so on?

You can use Input.anyKeyDown and Input.inputString (case-sensitive):
private void Update()
{
if( Input.anyKeyDown )
{
foreach( char c in Input.inputString )
CodeAttempt[index++] = char.ToLowerInvariant( c );
}
}

As far as I know, Unity doesn't have built-in KeyCode to char mappings.
I found a Gist that has a char to KeyCode dictionary. Simply swap the keys and values and you should be good to go: https://gist.github.com/b-cancel/c516990b8b304d47188a7fa8be9a1ad9
I don't want to put the code here in the answer since it is too long, but I made a fork in case the original Gist goes down: https://gist.github.com/starikcetin/62506e691ecd465159a235fb7acb44f0
Edit: Why don't you keep your cheat code in the form of a KeyCode array? Then you don't have to deal with chars.

Related

Use variable instead of keycode unity

Okay so I'm trying to make a system that picks a random word then it turns that word into a char array. Then it will track if you type the characters. But the method that I'm trying to do hasn't been working. mainly because it won't let me use a variable name as a keycode. Is this a worthwhile problem, or should I abort mission and try something else.
string currentWord = wordArray[Random.Range(0, typingWords.Length)];
char[] wordAsArray = currentWord.ToCharArray();
Keycode currentLetter = wordAsArray[0];
if (Input.GetKey(currentLetter))
{
Debug.Log("Test");
}
most of this works fine but what doesn't work the problem is the if (Input.GetKey(currentLetter))
is there something that can turn the word into a KeycodeArray or something like that or turn the specific character into keycode.
Does anybody know if this problem is solvable or will I have to use another method.
is there something that can turn the word into a KeycodeArray or something like that or turn the specific character into keycode.
There is not a built-in function for that. You can create a keycode array with each keycodes in it and use that to determine current letter. Like:
KeyCode[] letterCodes = new KeyCode[] {
KeyCode.A, KeyCode.B, KeyCode.C, ... KeyCode.Z
};
KeyCode currentLetterCode = letterCodes[wordAsArray[0] - 'A'];
'A' is subtracted from it to get the index of the letter in the letterCodes array. This assumes that the word only contains uppercase letters.
Instead of that method i would use a different approach. I will write down a complete example of how i would do it with comments.
public class TypingGame : MonoBehaviour
{
public Text wordText;
private string currentWord;
private int currentIndex;
private void Start()
{
// Pick a random word to type
currentWord = GetRandomWord();
// Display the word on screen
wordText.text = currentWord;
}
private void Update()
{
// Check if the current letter has been typed
if (Input.anyKeyDown)
{
KeyCode keyPressed = GetKeyPressed();
if (keyPressed != KeyCode.None && keyPressed == GetNextKeyCode())
{
currentIndex++;
if (currentIndex >= currentWord.Length)
{
// The word has been completely typed
currentWord = GetRandomWord();
wordText.text = currentWord;
currentIndex = 0;
}
else
{
// Update the display to show the next letter
wordText.text = currentWord.Substring(currentIndex);
}
}
}
}
private string GetRandomWord()
{
// Replace this with your own word selection logic
string[] words = { "cat", "dog", "bird", "fish" };
return words[Random.Range(0, words.Length)];
}
private KeyCode GetNextKeyCode()
{
char nextChar = currentWord[currentIndex];
KeyCode keyCode = (KeyCode)System.Enum.Parse(typeof(KeyCode), nextChar.ToString().ToUpper());
return keyCode;
}
private KeyCode GetKeyPressed()
{
foreach (KeyCode keyCode in System.Enum.GetValues(typeof(KeyCode)))
{
if (Input.GetKeyDown(keyCode))
{
return keyCode;
}
}
return KeyCode.None;
}
}
GetNextKeyCode method converts the next letter in the word to a KeyCode value by converting the letter to uppercase and using System.Enum.Parse to look up the corresponding KeyCode value.
GetKeyPressed method checks which key was pressed and returns the corresponding KeyCode value by looping over all possible KeyCode values and checking which one has been pressed using Input.GetKeyDown.

Make invisible object visible with typed word

I want to make an invisible object visible when I type the word I chose in my game, how can I do that?
Making an invisible object visible is generally easy — just start with its renderer disabled and then enable it for example.
GetComponent<Renderer>().enabled = true;
(This may vary slightly for e.g. a sprite.)
For the second part, assuming you mean something like a cheat code where the game is accepting normal control input without anything like an input field, but pressing a specific combination of keys will activate a secret function, I think something like this should work:
string cheatCode = “magiceye”;
int index=0;
void Update()
{
foreach(char c in Input.inputString) {
if( c == cheatCode[index] )
index++;
else
index=0; // Reset if a wrong key is typed
if( index == cheatCode.Length ) {
RevealInvisibleObject(); // Full cheat code was entered uninterrupted
index=0;
}
}
}

C#: recursively replace characters in a string

I have a string "abcdef" I want to change recursively. If a character cha is found, all characters up to this should be replaced with another character, chb
Ex.
If cha = 'd', the modified string becomes "xxxxef" (if chb = 'x').
If cha = 'g', the string shouldn't be changed.
This is what I've tried
string myString = "abcdef";
char[] str = myString.ToCharArray();
void FindInString(int p)
{
if (p < str.Length-1)
{
if (str[p] != cha)
FindInString(p + 1);
}
str[p] = chb;
}
What I don't understand about recursitivity is what's happening on it's way back, ie. how to write a condition for the line
str[p] = chb;
I assume the easiest way: That you want to tackle the first appearance of the char cha in the string.
The first thing about recursion: be clear when this recursive-call-charade has to end! So you need the right exit strategy.
string s = "abcdefg";
you would stop if there is no match for cha
if (!s.Contains(cha))
you would stop if you have found your match
else if (s[index] == cha)
otherwise you would increase the index and repeat the call
Now the second thing is the return value. Your method is supposed to change a string and return it. So It would be good to let it do so. If you pass all the necessary parameters into the method, it becomes independent of variables outside of its scope. You need:
the string s
an index to index the position
and the matching char
and of course the fitting return value
public static string FindInString(string s, int index, char cha)
For string manipulations a StringBuilder is a convenient tool. It allows you to change chars at certain positions like in an array which is not possible in strings because they are immutable.
StringBuilder sb = new StringBuilder(s);
// change the char at index:
sb[index] = 'x';
Now the final step is of course the recursive call. You basically go one step further with your index and call the method again in the return statement
index++;
return FindInString(sb.ToString(), index, cha);
This should suffice to enable you to write this method as a recursive version.
Write a comment if you still need help.
EDIT:
What I don't understand about recursitivity is what's happening on it's way back,
What one tries to do is to break the entire problem into smaller sub-problems that resemble the structure of the entire problem. Imagine that at each recursive step you solve a part-problem of the entire problem and leave the part-solution at this step. As you keep walking down the stairs of recursion you ask at each step "is the entire problem solved?" if not repeat yourself/problem-solving-procedure. When you reach the final step and the question is answered with yes, you turn around and collect the solutions backwards when you climb the stairs of return statements backwards. This is of course only metaphorical, but one way to illustrate the process.
I'll try to better explain as suggested by #Mong Zhu
1) Identify the position of cha in your myString
2) Create a substring of all the character after cha --> stringAfterCha
3) Add the right number of chb before the stringAfterCha --> The PadLeft method add to your string as many as chb (2nd argument) are needed to reach the length (1st argument)
var cha = 'd';
var chb = 'x';
var myString = "abcdef";
int positionOfChaInMyString = myString.IndexOf(cha) + 1;
string stringAfterCha = myString.Substring(positionOfChaInMyString);
string result = stringAfterCha.PadLeft(myString.Length, chb);
I still don't see this as a good example of recursion, but maybe this code helps you. Basically, you must return a bool for the calling method to know if the seached character has been found. If it has been found, you change the character you are analyzing and return true also to the previous calling method.Of course, this can be probably optimized, and decide what to do if there are duplicated searched characters, but it is just an example. And BTW, i'd advise you to always debug step by step your code, that way you'll see how it is working.
static bool FindInString(int p)
{
char cha = 'd';
char chb = 'x';
if (p < str.Length - 1)
{
if (str[p] != cha)
{
if (FindInString(p + 1))
{
str[p] = chb;
return true;
}
}
else
{
str[p] = chb;
return true;
}
}
return false;
}
The example call:
str = myString.ToCharArray();
FindInString(0);

How do I get the char for a keypress knowing only the ConsoleKey enum and Modifiers?

I want to create a ConsoleKeyInfo instance of the matching closing brace of any open brace typed in a PowerShell session (I'm using PSReadline to do the key handling). For your convenience, here are the properties of all the keys involved
PS> while($true){ [System.Console]::ReadKey($true) }
KeyChar Key Modifiers
------- --- ---------
[ Oem4 0
] Oem6 0
{ Oem4 Shift
} Oem6 Shift
In the key handler, I am given the ConsoleKeyInfo for the "chord" that was pressed (and PSReadline does filtering, so I already know I'm receiving only an Oem4 or Shift+Oem4). I want to generate the matching ConsoleKeyInfo so I can send the pair printing to the console.
The ConsoleKeyInfo constructor takes
a char
a System.ConsoleKey
a bool each for Shift, Alt, and Control
I can get the correct ConsoleKey by casting it to an int and moving up two...
PS> [System.ConsoleKey]([int]$key.Key + 2)
Oem6
And I can map from the pressed key's Modifiers by testing it bitwise...
PS> ($key.Modifiers -band [System.ConsoleModifiers]::Shift) -ne 0
False
But, I have no idea how to get the literal char for this console key. How does the console get the char from the keyboard key? Can this only be done with a live console/keyboard?
I'd rather not maintain a map of the key pairs nor split the handlers, one for each "chord", and hardcode the matching key char. :(
You probably don't need to create a ConsoleKeyInfo just for PSReadline.
Occasionally you may need to pass a ConsoleKeyInfo to a method in PSConsoleReadLine, but most methods in PSConsoleReadLine that accept a ConsoleKeyInfo don't even look at the argument. That's why the parameter is Nullable.
This doesn't actually answer your question though. JaredPar is absolutely correct that in general, it's not possible to convert a ConsoleKey/ConsoleModifiers pair to a char. If we don't care about full generality (and currently PSReadline doesn't), you can use code similar to what PSReadline uses:
internal static char GetCharFromConsoleKey(ConsoleKey key, ConsoleModifiers modifiers)
{
// default for unprintables and unhandled
char keyChar = '\u0000';
// emulate GetKeyboardState bitmap - set high order bit for relevant modifier virtual keys
var state = new byte[256];
state[NativeMethods.VK_SHIFT] = (byte)(((modifiers & ConsoleModifiers.Shift) != 0) ? 0x80 : 0);
state[NativeMethods.VK_CONTROL] = (byte)(((modifiers & ConsoleModifiers.Control) != 0) ? 0x80 : 0);
state[NativeMethods.VK_ALT] = (byte)(((modifiers & ConsoleModifiers.Alt) != 0) ? 0x80 : 0);
// a ConsoleKey enum's value is a virtual key code
uint virtualKey = (uint)key;
// get corresponding scan code
uint scanCode = NativeMethods.MapVirtualKey(virtualKey, NativeMethods.MAPVK_VK_TO_VSC);
// get corresponding character - maybe be 0, 1 or 2 in length (diacriticals)
var chars = new char[2];
int charCount = NativeMethods.ToUnicode(
virtualKey, scanCode, state, chars, chars.Length, NativeMethods.MENU_IS_INACTIVE);
// TODO: support diacriticals (charCount == 2)
if (charCount == 1)
{
keyChar = chars[0];
}
return keyChar;
}
If you're just trying to insert the closing brace then you should be able to do what this handler does - it does the same for single and double quotes:
Set-PSReadlineKeyHandler -Chord "Ctrl+'","Ctrl+Shift+'" `
-BriefDescription SmartInsertQuote `
-Description "Insert paired quotes if not already on a quote" `
-ScriptBlock {
param($key, $arg)
$line = $null
$cursor = $null
[PSConsoleUtilities.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
$keyChar = $key.KeyChar
if ($key.Key -eq 'Oem7') {
if ($key.Modifiers -eq 'Control') {
$keyChar = "`'"
}
elseif ($key.Modifiers -eq 'Shift','Control') {
$keyChar = '"'
}
}
if ($line[$cursor] -eq $keyChar) {
# Just move the cursor
[PSConsoleUtilities.PSConsoleReadLine]::SetCursorPosition($cursor + 1)
}
else {
# Insert matching quotes, move cursor to be in between the quotes
[PSConsoleUtilities.PSConsoleReadLine]::Insert("$keyChar" * 2)
[PSConsoleUtilities.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
[PSConsoleUtilities.PSConsoleReadLine]::SetCursorPosition($cursor - 1)
}
}
It may not work on all keyboards AFAIK but I'm guessing you're only interested in getting this to work on your keyboard. :-)
Unfortunately you can't really do this. Keyboard input is not as simple as a keyboard key + modifier = a character. Instead it's more that a sequence of keyboard key + modifier values = a character. In English keyboards this sequence tends to be of length 1 but in other languages the sequence can be much longer. This means that generally speaking this isn't a solvable problem because one key can't definitely produce a given character
Michael Kaplan has a fabulous blog series that goes through this in great detail
http://www.siao2.com/2006/04/13/575500.aspx

Get the char on Control.KeyDown?

When handling Control.OnKeyPress event, there is a KeyPressEventArgs that contains a KeyChar.
For usability reasons I need exactly the same KeyChar but when handling OnKeyDown event.
The KeyEventArgs does not contains any char related data. I mean, if press the A key with or without Shift its not affecting the KeyCode, KeyData or KeyValue. The same when using another language, i still getting capital english values.
How to get a KeyPressEventArgs.KeyChar inside KeyDown event?
Thanks.
Convert it. Here is simple function for converting 'A' to 'a'. It converts only capital chars from [A-Z] set. The value 32 is diff between 'A' and 'a'.. Sure you can extend it to your requirements, or ask for feature here.
char getChar( KeyEventArgs e )
{
int keyValue = e.KeyValue;
if ( !e.Shift && keyValue >= (int) Keys.A && keyValue <= (int) Keys.Z )
return (char)(keyValue + 32);
return (char) keyValue;
}
if you need it to works with your current culture you should override ProcessKeyMessage Control method:
protected override bool ProcessKeyMessage( ref Message m )
{
if ( ( m.Msg == 0x102 ) || ( m.Msg == 0x106 ) ) // this is special - don't remove
{
char c = (char) m.WParam; // here is your char for OnKeyDown event ;)
}
return base.ProcessKeyMessage( ref m );
}
Hope it helpful.
I think that what you are looking for is in fact the KeyCode property.
private void textBox1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
// Determine whether the key entered is the F1 key. If it is, display Help.
if(e.KeyCode == Keys.A)
{
// Do something kewl
}
else if(e.KeyCode == Keys.B)
{
// Do something even kewler
}
}
If you are just looking for certain keys you could setup a switch statment or whatever your heart desires.
If the reason you're wanting to use KeyDown instead of KeyPress is to capture the extra information that's given to a KeyDown event, could you perhaps capture that extra information in a KeyDown event and then use it when you get the KeyPress? Rather a hokey approach, to be sure, but I'm not sure of any other approach that will really work in a keyboard mapping that has "dead keys" (i.e. two-key sequences that produce a single character). I don't know why Microsoft didn't carry along more information through to the KeyPress event (or a lot of its events, for that matter) since trying to match up cause-and-effect events isn't perfect, but I don't really know any better alternative.

Categories