Minecraft-Console-Client
Minecraft-Console-Client copied to clipboard
Fix Console IO for Chinese keyboards
For a Chinese player there is such trouble that sometimes using backspace after entering characters cannot accurately delete characters.
Chinese character takes two spaces on console. When backspace is pressed, only one space is cleared, leaving behind a space on the console that cannot be deleted. Not only backspace, left and right arrow key also not work with Chinese characters. @ORelio I can help you on this issue if you need as I know Chinese :)
The culprit is ConsoleIO.cs. This class handles the chat-like prompt that allows you to type while messages are being printed in chat. I could only test it using European keyboard where each character fits in a single byte. You can start looking at RemoveOneChar(). I think you'd need to check what kind of character is sitting behind the cursor and adjust the deletion mechanism. Then repeat the same process with GoLeft() and GoRight().
I have wrote a similar console like this but in javascript. My way to handle it is clear the whole line and write them back after finish process the key. It may not be the best way but is the easiest solution.
This is also how ConsoleIO handles this in its Write() method. When new text needs to be printed, user input is temporarily removed and printed back.
@ORelio It is very hard (for me) to modify the current exists code because I don't understand what it is doing. I might re-write almost every method if I attempt to fix this issue. Do you mind about that?
I'd like to say I don't mind, but many bugs were fixed across the years and ConsoleIO has come to be pretty stable although there is still room for improvement (this issue being a proof 😄). I'm afraid rewriting everything from scratch would reintroduce more bugs than it fixes 😕
Here is a summary of how it works:
bufferandbuffer2holds text being typed by the User,buffer2holds text on the right of the cursor if you move back using the Left arrow keyReadLine()handles the reading prompt. It waits for keys to be pressed and perform actions depending on the key being pressed:AddChar()to add a new character typed by the user,RemoveOneChar()to remove a character on press on Backspace, etc, until the user finally presses Enter to validate the input.DebugReadInput()can be used to debug how MCC sees your keypresses. You can invoke it using--keyboard-debugwhen launching MCC. It should help you understand how MCC sees your keypresses in theReadLine()method.Write()handles the writing. It makes a copy ofbufferandbuffer2, then clears everything usingClearLineAndBuffer(), then erases the>prompt using\bescape sequence in terminal andwhitespace character. There is also a special case depending on whether the cursor needs to go back to the previous line or not. This allows going back exactly where the cursor was before spawning the input prompt, and resume printing text that was not finishing with a newline character\n. Finally, after performing the write operation, it restores the prompt and buffers.WriteLineFormatted()takes a minecraft-formatted string likehello§1worldand breaks it into several Write() calls separated by console color changesClearLineAndBuffer()is a shortcut for as many GoRight() right arrow key and RemoveOneChar() backspace as necessary to effectively removes everything typed by the user.RemoveOneChar()is called when using backspace. It goes back\b, writes a whitespacethen go back again\bto erase the last character. This might be what does not work properly for Chinese characters where you may need multiple backspace\bcharacters to effectively go back in the terminal. Additionally, there is a special handling if the cursor is at the beginning of a line because\bdoes not work and the cursor needs to be manually moved at the end of the previous line before printing the white space. Finally, everything on the right of the cursor needs to be printed back to the console, and the cursor is placed back using multipleGoBack()calls.GoBack()moves the cursor back of 1 character to the left. Here again, there's a special case when the cursor needs to go back to the previous line inside the terminal.GoLeft()is called when using left arrow key. It is the same asGoBack()but adjustsbufferandbuffer2accordingly.GoRight()is called when using right arrow key. It moves the cursor of 1 character to the right by printing back the character and adjusting the buffers.AddChar()is called when inserting a new character inside the user input. As withRemoveOneChar()it needs to print back the text on the right of the cursor.
I think you need to adjust the RemoveOneChar() / AddChar() methods that handle addition and removal of a single character, and maybe GoBack() / GoLeft() / GoRight() for moving the cursor inside the input prompt.
Also any debugger with step-by-step code execution like in Visual Studio would help you understand what each line does by running single instructions and seeing how it reflects in the terminal.
Actually I don't understand what this part do. (the Console.Cursor and Console.Buffer)
Are they for handling multiple lines input?
Edited
I figured out it myself. It is for multiple lines handle.
But GoLeft() or GoBack() do not have multiple lines handling, hence we cannot go back to the previous row (a bug that no one found/reported across the year)
Ok, Chinese characters worked now :smile: See my repo The bug mentioned above have not been fixed yet.
Edited This is still not perfect. Characters may left over if there are CJK char across multiple lines.
Indeed, this is the multiline handling part, when we need to go back to the previous line:
if (Console.CursorLeft == 0) // We are at beginning of line
{
Console.CursorLeft = Console.BufferWidth - 1; // Move the cursor at right end of terminal
if (Console.CursorTop > 0) // ... and move the cursor up of to previous line if not the first line
Console.CursorTop--;
Console.Write(' '); // Write a whitespace: This will proceed to next line and erase the first character
Console.CursorLeft = Console.BufferWidth - 1; // Move back the cursor at right and of terminal
if (Console.CursorTop > 0) // ... And move up to the line above
Console.CursorTop--;
}
// Otherwise, move back 1 character, write a whitespace, move back again of 1 character. Done.
else Console.Write("\b \b");
Just had a look to your modified file. Apparently, the \b backspace character was indeed the culprit since you can get around this by using multiple \b. In that case, what if we manually move the cursor back instead of using \b at all? It might fix that kind of issue for any other character set, not just Chinese. Attempted that in commit e4cae97dd77fdb1f4b4876a847aa91f802c28569. It has no downside for Western character sets, but I could not test its effect on Eastern character sets. Could you try it out for me?
I have tested sending a left arrow key instead of \b in the GoLeft() method but no luck. I will test your code when I get home 😊
@ORelio I have tested the code and unfortunately, it didn't work :cry: It just act like before.
Closing due to being stale. Use the latest release, as since the issue was opened a lot of things have been changed. Re-open the issue if you still have it.