@@ -125,7 +125,7 @@ public static extern int ToUnicode(
125
125
126
126
static readonly ThreadLocal < char [ ] > toUnicodeBuffer = new ThreadLocal < char [ ] > ( ( ) => new char [ 2 ] ) ;
127
127
static readonly ThreadLocal < byte [ ] > toUnicodeStateBuffer = new ThreadLocal < byte [ ] > ( ( ) => new byte [ 256 ] ) ;
128
- internal static void TryGetCharFromConsoleKey ( ConsoleKeyInfo key , ref char result )
128
+ internal static void TryGetCharFromConsoleKey ( ConsoleKeyInfo key , ref char result , ref bool isDeadKey )
129
129
{
130
130
var modifiers = key . Modifiers ;
131
131
var virtualKey = key . Key ;
@@ -149,11 +149,20 @@ internal static void TryGetCharFromConsoleKey(ConsoleKeyInfo key, ref char resul
149
149
}
150
150
int charCount = ToUnicode ( virtualKey , scanCode , state , chars , chars . Length , flags ) ;
151
151
152
- // TODO: support diacriticals (charCount == 2)
153
152
if ( charCount == 1 )
154
153
{
155
154
result = chars [ 0 ] ;
156
155
}
156
+ else if ( charCount == - 1 || charCount >= 2 )
157
+ {
158
+ // Quoted from https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-tounicode#return-value:
159
+ // "Return value -1 --
160
+ // The specified virtual key is a dead-key character (accent or diacritic).
161
+ // Return value >=2 --
162
+ // Two or more characters were written to the buffer specified by pwszBuff. The most common cause for this is that a dead-key character
163
+ // (accent or diacritic) stored in the keyboard layout could not be combined with the specified virtual key to form a single character."
164
+ isDeadKey = true ;
165
+ }
157
166
}
158
167
159
168
static readonly ThreadLocal < StringBuilder > keyInfoStringBuilder = new ThreadLocal < StringBuilder > ( ( ) => new StringBuilder ( ) ) ;
@@ -217,6 +226,7 @@ void AppendPart(string str)
217
226
}
218
227
219
228
var c = key . KeyChar ;
229
+ var isDeadKey = false ;
220
230
if ( char . IsControl ( c ) )
221
231
{
222
232
// We have the virtual key code and Windows has a handy api to map that to the non-control
@@ -226,7 +236,7 @@ void AppendPart(string str)
226
236
if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
227
237
{
228
238
var keySansControl = new ConsoleKeyInfo ( key . KeyChar , key . Key , isShift , isAlt , control : false ) ;
229
- TryGetCharFromConsoleKey ( keySansControl , ref c ) ;
239
+ TryGetCharFromConsoleKey ( keySansControl , ref c , ref isDeadKey ) ;
230
240
}
231
241
}
232
242
else if ( isAlt && isCtrl )
@@ -268,8 +278,13 @@ void AppendPart(string str)
268
278
break ;
269
279
270
280
case '\0 ' :
271
- // This is ugly but familiar.
272
- s = "@" ;
281
+ // This could be a dead key for a particular keyboard layout in Windows console.
282
+ // The dead key is not an issue when there is tty involved, so on non-Windows, `isDeadKey` is always false.
283
+ //
284
+ // When we believe it's a dead key, we use the text form of the virtual key so the resulted PSKeyInfo can be
285
+ // converted back to ConsoleKeyInfo correctly later on, and be properly ignored during rendering.
286
+ // Otherwise, we use `@` in case `key.KeyChar = '\0'`. This is ugly but familiar.
287
+ s = isDeadKey ? key . Key . ToString ( ) : "@" ;
273
288
break ;
274
289
275
290
case char _ when ( c >= 1 && c <= 26 ) :
0 commit comments