COOKED_READ (cmd.exe) doesn't properly support emoji input #2042

Closed
opened 2026-01-30 22:45:21 +00:00 by claunia · 4 comments
Owner

Originally created by @peter-bertok on GitHub (Jun 24, 2019).

Environment

Windows build number: 1903
Windows Terminal version (if applicable): 0.2.1715.0

Steps to reproduce

Paste text containing complex Unicode characters such as emoji into a PowerShell tab as a string literal.
Emoji will be displayed as "??" placeholders, but then display correctly when the literal is "output" by pressing enter.

Expected behavior

Unicode characters such as Emoji should be consistently displayed, including in string literals, input text, command-line arguments, etc...

Actual behavior

Inconsistent display:

Screenshot

Originally created by @peter-bertok on GitHub (Jun 24, 2019). # Environment ```none Windows build number: 1903 Windows Terminal version (if applicable): 0.2.1715.0 ``` # Steps to reproduce Paste text containing complex Unicode characters such as emoji into a PowerShell tab as a string literal. Emoji will be displayed as "??" placeholders, but then display correctly when the literal is "output" by pressing enter. # Expected behavior Unicode characters such as Emoji should be consistently displayed, including in string literals, input text, command-line arguments, etc... # Actual behavior Inconsistent display: ![Screenshot](https://user-images.githubusercontent.com/14988123/59984055-60b94d80-9669-11e9-9d48-bc4a8ed85e9b.png)
Author
Owner

@DHowett-MSFT commented on GitHub (Jun 24, 2019):

This one is fascinating. I spy two bugs here. One is with the emoji input (this could just be PSReadline's fault), and the other is that some emoji are still too tiny!

@DHowett-MSFT commented on GitHub (Jun 24, 2019): This one is fascinating. I spy two bugs here. One is with the emoji input (this could just be PSReadline's fault), and the other is that some emoji are _still_ too tiny!
Author
Owner

@Shorotshishir commented on GitHub (Jun 28, 2019):

dumping any of the two files in the terminal doesn't render any data properly. these two files ocntails all the emojis that windows provide.

CMD:
use more or type to dump content into the terminal.
shows garbage text, but doesn't crash

PowerShell
use get-content to dump the data into the terminal
nothing shows , hangs the terminal app and crashes

WSL
use cat to dump the content into the terminal
nothing shows, hangs the terminal app and crashes

N.B. --> Crash doesn't terminate terminal app

@Shorotshishir commented on GitHub (Jun 28, 2019): dumping any of the two files in the terminal doesn't render any data properly. these two files ocntails all the emojis that windows provide. - [emoji.txt](https://drive.google.com/open?id=1QjnGdp_mA6v8M30ZGj52Vn2bb3_Y-fmk) - [emoji.docx](https://drive.google.com/open?id=1C--OnOKwHzCdAczeFy-PjRG4gpGnB22D) **CMD**: use `more` or `type` to dump content into the terminal. shows garbage text, but _doesn't crash_ **PowerShell** use `get-content` to dump the data into the terminal _nothing shows , hangs the terminal app and crashes_ **WSL** use `cat` to dump the content into the terminal _nothing shows, hangs the terminal app and crashes_ **N.B. --> Crash doesn't terminate terminal app**
Author
Owner

@davidhewitt commented on GitHub (Jan 6, 2020):

Pasting emoji input is also an issue with cmd. In the screenshot below, I paste a string of smileys in, but they come out as invalid glyphs.

Hitting enter and up displays the correct input string though, so it is making it into the console buffer correctly.

image

@davidhewitt commented on GitHub (Jan 6, 2020): Pasting emoji input is also an issue with `cmd`. In the screenshot below, I paste a string of smileys in, but they come out as invalid glyphs. Hitting `enter` and `up` displays the correct input string though, so it _is_ making it into the console buffer correctly. ![image](https://user-images.githubusercontent.com/1939362/71823514-4f78e100-308f-11ea-9241-061d48f30d16.png)
Author
Owner

@zadjii-msft commented on GitHub (Mar 27, 2020):

For me later:

Emoji.txt

😁😁😂🤣😃😄😅😆😉😊😋😎😍😘🥰😗😙😚🙂🤗🤩🤔🤨😐😑😶🙄😏😣😥😮🤐😯😪😫🥱😴😌😛😜😝🤤😒😓😔😕🙃🤑😲🙁😖😞😟😤😢😭😦😧😨😩🤯😬😰😱🥵🥶😳🤪😵🥴😠😡🤬😷🤒🤕🤢🤮🤧😇🥳🥺🤠🤡🤥🤫🤭🧐🤓😈👿👹👺💀👻👽👾🤖💩😺😸😹😻😼😽🙀😿😾🐱👤🐱‍🏍🐱💻🐱🐉🐱👓🐱🚀🙈🙉🙊🐵🐶🐺🐱🦁🐯🦒🦊🦝🐮🐷🐗🐭🐹🐰🐻🐨🐼🐸🦓🐴🦄🐔🐲🐽🐾🐒🦍🦧🦮🐕‍🦺🐩🐕🐈🐅🐆🐎🦌🦏🦛🐂🐃🐄🐖🐏🐑🐐🐪🐫🦙🦘🦥🦨🦡🐘🐁🐀🦔🐇🐿🦎🐊🐢🐍🐉🦕🦖🦦🦈🐬🐳🐋🐟🐠🐡🦐🦑🐙🦞🦀🐚🦆🐓🦃🦅🕊🦢🦜🦩🦚🦉🐦🐧🐥🐤🐣🦇🦋🐌🐛🦟🦗🐜🐝🐞🦂🕷🕸🦠🧞‍♀️🧞‍♂️🗣👤👥👁👀🦴🦷👅👄🧠🦾🦿👣🤺🤼‍♂️🤼‍♀️👯‍♂️👯‍♀️💑👩‍❤️‍👩👨‍❤️‍👨💏👩‍❤️‍💋‍👩👨‍❤️‍💋‍👨👪👨‍👩‍👦👨‍👩‍👧👨‍👩‍👧‍👦👨‍👩‍👦‍👦👨‍👩‍👧‍👧👨‍👨‍👦👨‍👨‍👧👨‍👨‍👧‍👦👨‍👨‍👦‍👦👨‍👨‍👧‍👧👩‍👩‍👦👩‍👩‍👧👩‍👩‍👧‍👦👩‍👩‍👦‍👦👩‍👩‍👧‍👧👩‍👦👩‍👧👩‍👧‍👦👩‍👦‍👦👩‍👧‍👧👨‍👦👨‍👧👨‍👧‍👦👨‍👦‍👦👨‍👧‍👧👭👩🏻🤝👩🏻👩🏼🤝👩🏻👩🏼🤝👩🏼👩🏽🤝👩🏻👩🏽🤝👩🏼👩🏽🤝👩🏽👩🏾🤝👩🏻👩🏾🤝👩🏼👩🏾🤝👩🏽👩🏾🤝👩🏾👩🏿🤝👩🏻👩🏿🤝👩🏼👩🏿🤝👩🏽👩🏿🤝👩🏾👩🏿🤝👩🏿👫👩🏻🤝🧑🏻👩🏻🤝🧑🏼👩🏻🤝🧑🏽👩🏻🤝🧑🏾👩🏻🤝🧑🏿👩🏼🤝🧑🏻👩🏼🤝🧑🏼👩🏼🤝🧑🏽👩🏼🤝🧑🏾👩🏼🤝🧑🏿👩🏽🤝🧑🏻👩🏽🤝🧑🏼👩🏽🤝🧑🏽👩🏽🤝🧑🏾👩🏽🤝🧑🏿👩🏾🤝🧑🏻👩🏾🤝🧑🏼👩🏾🤝🧑🏽👩🏾🤝🧑🏾👩🏾🤝🧑🏿👩🏿🤝🧑🏻👩🏿🤝🧑🏼👩🏿🤝🧑🏽👩🏿🤝🧑🏾👩🏿🤝🧑🏿👬👨🏻🤝👨🏻👨🏼🤝👨🏻👨🏼🤝👨🏼👨🏽🤝👨🏻👨🏽🤝👨🏼👨🏽🤝👨🏽👨🏾🤝👨🏻👨🏾🤝👨🏼👨🏾🤝👨🏽👨🏾🤝👨🏾👨🏿🤝👨🏻👨🏿🤝👨🏼👨🏿🤝👨🏽👨🏿🤝👨🏾👨🏿🤝👨🏿👨🏿🤝👨
👩👨🧑👧👦🧒👶👵👴🧓👩‍🦰👨‍🦰👩‍🦱👨‍🦱👩‍🦲👨‍🦲👩‍🦳👨‍🦳👱‍♀️👱‍♂️👸🤴👳‍♀️👳‍♂️👲🧔👼🤶🎅👮‍♀️👮‍♂️🕵️‍♀️🕵️‍♂️💂‍♀️💂‍♂️👷‍♀️👷‍♂️👩‍⚕️👨‍⚕️👩‍🎓👨‍🎓👩‍🏫👨‍🏫👩‍⚖️👨‍⚖️👩‍🌾👨‍🌾👩‍🍳👨‍🍳👩‍🔧👨‍🔧👩‍🏭👨‍🏭👩‍💼👨‍💼👩‍🔬👨‍🔬👩‍💻👨‍💻👩‍🎤👨‍🎤👩‍🎨👨‍🎨👩‍✈️👨‍✈️👩‍🚀👨‍🚀👩‍🚒👨‍🚒🧕👰🤵🤱🤰🦸‍♀️🦸‍♂️🦹‍♀️🦹‍♂️🧙‍♀️🧙‍♂️🧚‍♀️🧚‍♂️🧛‍♀️🧛‍♂️🧜‍♀️🧜‍♂️🧝‍♀️🧝‍♂️🧟‍♀️🧟‍♂️🙍‍♀️🙍‍♂️🙎‍♀️🙎‍♂️🙅‍♀️🙅‍♂️🙆‍♀️🙆‍♂️🧏‍♀️🧏‍♂️💁‍♀️💁‍♂️🙋‍♀️🙋‍♂️🙇‍♀️🙇‍♂️🤦‍♀️🤦‍♂️🤷‍♀️🤷‍♂️💆‍♀️💆‍♂️💇‍♀️💇‍♂️🧖‍♀️🧖‍♂️🤹‍♀️🤹‍♂️👩‍🦽👨‍🦽👩‍🦼👨‍🦼👩‍🦯👨‍🦯🧎‍♀️🧎‍♂️🧍‍♀️🧍‍♂️🚶‍♀️🚶‍♂️🏃‍♀️🏃‍♂️💃🕺🧗‍♀️🧗‍♂️🧘‍♀️🧘‍♂️🛀🛌🕴🏇🏂🏌️‍♀️🏌️‍♂️🏄‍♀️🏄‍♂️🚣‍♀️🚣‍♂️🏊‍♀️🏊‍♂️🤽‍♀️🤽‍♂️🤾‍♀️🤾‍♂️⛹️‍♀️⛹️‍♂️🏋️‍♀️🏋️‍♂️🚴‍♀️🚴‍♂️🚵‍♀️🚵‍♂️🤸‍♀️🤸‍♂️🤳💪🦵🦶👂🦻👃🤏👈👉👆👇🤞🖖🤘🤙🖐👌👍👎👊🤛🤜🤚👋🤟👏👐🙌🤲🙏🤝💅
🎈🎆🎇🧨🎉🎊🎃🎄🎋🎍🎎🎏🎐🎑🧧🎀🎁🎗🎞🎟🎫🎠🎡🎢🎪🎭🖼🎨🧵🧶🛒👓🕶🦺🥽🥼🧥👔👕👖🩳🧣🧤🧦👗🥻👘👚🩲🩱👙👛👜👝🛍🎒👞👟🥾🥿👠👡👢🩰👑🧢👒🎩🎓💋💄💍💎🥎🏀🏐🏈🏉🎱🎳🥌🎣🤿🎽🛶🎿🛷🥅🏒🥍🏏🏑🏓🏸🎾🥏🪁🎯🥊🥋🥇🥈🥉🏅🎖🏆🎮🕹🎰🎲🔮🧿🧩🧸🪀🎴🃏🀄♟♠♣♥♦🔈🔉🔊📢📣🔔🎼🎵🎶🎙🎤🎚🎛🎧📯🥁🎷🎺🎸🪕🎻🎹📻🔒🔓🔏🔐🔑🗝🪓🔨⛏⚒🛠🔧🔩🧱⚙🗜🛢⚗🧪🧫🧬🩺💉🩸🩹💊🔬🔭📿🔗🧰🧲🦯🛡🏹🗡⚔🔪💣🔫📞📟📠📱📲📳📴🚬⚰⚱🗿🔋🔌💻🖥🖨⌨🖱🖲💽💾💿📀🧮🎥🎬📽📡📺📷📸📹📼🔍🔎🕯🪔💡🔦🏮📔📕📖📗📘📙📚📓📒📃📜📄📑📰🗞🔖🏷💰💴💵💶💷💸💳🧾🏧📧📨📩📤📥📦📫📪📬📭📮🗳✏✒🖋🖊🖌🖍📝🗒💼📁📂🗂📅📆🗓📇📈📉📊📋📌📍📎🖇📏📐✂🗃🗄🗑⏱⏲🕰
🍕🍔🍟🌭🍿🧂🥓🥚🍳🧇🥞🧈🍞🥐🥨🥯🥖🧀🥗🥙🥪🌮🌯🥫🍖🍗🥩🍠🥟🥠🥡🍱🍘🍙🍚🍛🍜🦪🍣🍤🍥🥮🍢🧆🥘🍲🍝🥣🥧🍦🍧🍨🍩🍪🎂🍰🧁🍫🍬🍭🍡🍮🍯🍼🥛🧃🍵🧉🍶🍾🍷🍸🍹🍺🍻🥂🥃🧊🥤🥢🍽🍴🥄🏺🥝🥥🍇🍈🍉🍊🍋🍌🍍🥭🍎🍏🍐🍑🍒🍓🍅🍆🌽🌶🍄🥑🥒🥬🥦🥔🧄🧅🥕🌰🥜💐🌸🏵🌹🌺🌻🌼🌷🥀🌱🌲🌳🌴🌵🌾🌿🍀🍁🍂🍃
🚗🚓🚕🛺🚙🚌🚐🚎🚑🚒🚚🚛🚜🚘🚔🚖🚍🦽🦼🛹🚲🛴🛵🏍🏎🚄🚅🚈🚝🚞🚃🚋🚆🚉🚊🚇🚟🚠🚡🚂🛩🪂🛫🛬💺🚁🚀🛸🛰🚤🛥⛴🛳🚢🚏🚨🚥🚦🚧🏁🏳‍🌈🏳🏴🏴‍☠️🚩🌌🪐🌍🌎🌏🗺🧭🏔⛰🌋🗻🛤🏕🏞🛣🏖🏜🏝🏟🏛🏗🏘🏙🏚🏠🏡🕋🕌🛕🕍🏢🏣🏤🏥🏦🏨🏩🏪🏫🏬🏭🏯🏰💒🗼🌉🗽🗾🎌🌁🌃🌄🌅🌆🌇💈🛎🧳🪑🚪🛏🛋🚽🧻🚿🛁🧼🧽🧴🪒🧷🧹🧺🧯⛈🌤🌥🌦🌧🌨🌩🌪🌫🌝🌑🌒🌓🌔🌕🌖🌗🌘🌙🌚🌛🌜🌞🌟🌠☄🌡🌬🌀🌈🌂❄☃🔥💧🌊
🧡💛💚💙💜🤎🖤🤍💔💕💞💓💗💖💘💝💟💌💢💥💤💦💨💫🕳☮✝☪🕉☸✡🔯🕎☯☦🛐🆔⚕♾⚛🈳🈹🈶🈚🈸🈺🈷✴🆚🉑💮🉐㊙㊗🈴🈵🈲🚼🅰🅱🆎🆑🅾🆘🛑📛🚫🔇🔕🚭🚷🚯🚳🚱🔞📵‼⁉💯🔅🔆🔱⚜〽☢☣⚠🚸🔰🈯💹❇✳💠🌐Ⓜ🈂🛂🛃🛄🛅🚾🅿🚰🚹🚺🚻🚮📶🈁🆖🆗🆙🆒🆕🆓#️⃣*️⃣0️⃣1️⃣2️⃣3️⃣4️⃣5️⃣6️⃣7️⃣8️⃣9️⃣🔟🔢▶⏸⏯⏹⏺⏭⏮🔀🔁🔂🔼🔽🎦➡⬅⬆⬇↗↘↙↖↕↔🔄↪↩⤴⤵ℹ🔤🔡🔠🔣🔃🔛🔝🔜🔚🔙💲💱©®™🔘🔴🟠🟡🟢🔵🟣🟤🟥🟧🟨🟩🟦🟪🟫◼◻▪▫🔶🔸🔷🔹🔺🔻🔲🔳💭🗯💬🗨👁‍🗨🕐🕑🕒🕓🕔🕕🕖🕗🕘🕙🕚🕛🕜🕝🕞🕟🕠🕡🕢🕣🕤🕥🕦🕧

;-)¯_(ツ)/¯( ••)>⌐■-■(⌐■■):-P:-((••)( ´・・)ノ(..)༼ つ ◕_◕ ༽つ(ˉ﹃ˉ)(╯°□°)╯︵ ┻━┻ಠ_ಠಥ_ಥ:-Dᓚᘏᗢ(┬┬﹏┬┬)^_^:-)(^///^)╰(*°▽°*)╯☆*: .。. o(≧▽≦)o .。.:*☆(*/ω\*)(●'◡'●)(❁´◡❁)(☞゚ヮ゚)☞☜(゚ヮ゚☜)(¬‿¬)(¬¬ )(T_T)(⊙_⊙;)

😁 is "\uD83D\uDE01", or 0n55357, 0n56833

OutputCellView OutputCellIterator::s_GenerateView(const std::wstring_view view,
                                                  const TextAttribute attr,
                                                  const TextAttributeBehavior behavior)
{
    const auto glyph = Utf16Parser::ParseNext(view);
    DbcsAttribute dbcsAttr;
    if (IsGlyphFullWidth(glyph))
    {
        dbcsAttr.SetLeading();
    }

    return OutputCellView(glyph, dbcsAttr, attr, behavior);
}

As the two wchar_ts get written to the buffer by WriteCharsLegacy, we create an OutputCellIterator to write each half of the emoji. Unfortunately, we write each half one char at a time. Utf16Parser::ParseNext doesn't like that. It knows the first wchar_t is a leading byte, but can also tell there's no trailing byte, so it just returns a Replacement char.

The character does end up getting inserted into the cooked read data correctly, which is why hitting enter to submit the commandline in cmd works just fine. The data in the cooked read data is correct, but the text buffer has the wrong data.

Presumably, the cooked read is just writing the text buffer wrong. COOKED_READ_DATA::ProcessInput can only handle one wchar_t at a time.

When you use the emoji picker to input the character, it first comes through ConversionAreaInfo::WriteText straight to _screenBuffer->Write to draw the composition buffer. Then, once the dialog is dismissed, the keys get sent to the input buffer in ConsoleImeInfo::_InsertConvertedString, where again the cooked read gets them one char at a time to display broken in the buffer.


EDIT: March 30th 2020

I've investigated into this a bit, and this is one of those terrible rabbit-hole issues. Even if we do add support for simply typing/pasting emoji to COOKED_READ, that opens up a whole other can of bugs. Then, COOKED_READ should probably also be enlightened to support backspacing an emoji. Also, what happens for applications that are expecting UCS-2 input, not utf-16? It's an unfortunately complex issue that we'll have to resolve on the console side of things.

This is now the "COOKED_READ (cmd.exe) doesn't properly support emoji input" issue, and I'm moving this to 21H1 as a "Feature", so we can try and prioritize for the next Windows release.

Code Snippet for future developers

I found that I could get cooked read to draw the emoji right every time by re-printing the buffer each time, but that wouldn't work for backspacing through emoji. Take a look at this segment for code for COOKED_READ_DATA::ProcessInput

if (AtEol())
    {
        // If at end of line, processing is relatively simple. Just store the character and write it to the screen.
        if (wch == UNICODE_BACKSPACE2)
        {
            wch = UNICODE_BACKSPACE;
        }

        if (wch != UNICODE_BACKSPACE || _bufPtr != _backupLimit)
        {
            fStartFromDelim = IsWordDelim(_bufPtr[-1]);

            bool loop = true;
            while (loop)
            {
                loop = false;
                if (wch == UNICODE_BACKSPACE && _processedInput)
                {
                    _bufPtr -= 1;
                    // clang-format off
#pragma prefast(suppress: __WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY, "This access is fine")
                    // clang-format on
                    *_bufPtr = (WCHAR)' ';
                    _currentPosition -= 1;

                    _screenInfo.GetTextBuffer().GetCursor().SetPosition(_originalCursorPosition);
                    status = WriteCharsLegacy(_screenInfo,
                                              _backupLimit,
                                              _backupLimit,
                                              _backupLimit,
                                              &_bytesRead,
                                              &NumSpaces,
                                              _originalCursorPosition.X,
                                              WC_DESTRUCTIVE_BACKSPACE | WC_KEEP_CURSOR_VISIBLE | WC_ECHO,
                                              &ScrollY);
                    _bytesRead -= sizeof(WCHAR);

                    // Repeat until it hits the word boundary
                    if (wchOrig == EXTKEY_ERASE_PREV_WORD &&
                        _bufPtr != _backupLimit &&
                        fStartFromDelim ^ !IsWordDelim(_bufPtr[-1]))
                    {
                        loop = true;
                    }
                }
                else
                {
                    *_bufPtr = wch;
                    _bytesRead += sizeof(WCHAR);
                    _bufPtr += 1;
                    _currentPosition += 1;
                }
                if (_echoInput)
                {
                    NumToWrite = sizeof(WCHAR);
                    _screenInfo.GetTextBuffer().GetCursor().SetPosition(_originalCursorPosition);

                    status = WriteCharsLegacy(_screenInfo,
                                              _backupLimit,
                                              _backupLimit,
                                              _backupLimit,
                                              &_bytesRead,
                                              &NumSpaces,
                                              _originalCursorPosition.X,
                                              WC_DESTRUCTIVE_BACKSPACE | WC_KEEP_CURSOR_VISIBLE | WC_ECHO,
                                              &ScrollY);
                    if (NT_SUCCESS(status))
                    {
                        _originalCursorPosition.Y += ScrollY;
                    }
                    else
                    {
                        RIPMSG1(RIP_WARNING, "WriteCharsLegacy failed %x", status);
                    }
                }

                // if (wch == UNICODE_BACKSPACE && _processedInput)
                // {
                //     _bytesRead -= sizeof(WCHAR);
                // }
                _visibleCharCount += NumSpaces;
            }
        }
    }
    else
@zadjii-msft commented on GitHub (Mar 27, 2020): For me later: <details> <summary>Emoji.txt</summary> 😁😁😂🤣😃😄😅😆😉😊😋😎😍😘🥰😗😙😚☺🙂🤗🤩🤔🤨😐😑😶🙄😏😣😥😮🤐😯😪😫🥱😴😌😛😜😝🤤😒😓😔😕🙃🤑😲☹🙁😖😞😟😤😢😭😦😧😨😩🤯😬😰😱🥵🥶😳🤪😵🥴😠😡🤬😷🤒🤕🤢🤮🤧😇🥳🥺🤠🤡🤥🤫🤭🧐🤓😈👿👹👺💀☠👻👽👾🤖💩😺😸😹😻😼😽🙀😿😾🐱‍👤🐱‍🏍🐱‍💻🐱‍🐉🐱‍👓🐱‍🚀🙈🙉🙊🐵🐶🐺🐱🦁🐯🦒🦊🦝🐮🐷🐗🐭🐹🐰🐻🐨🐼🐸🦓🐴🦄🐔🐲🐽🐾🐒🦍🦧🦮🐕‍🦺🐩🐕🐈🐅🐆🐎🦌🦏🦛🐂🐃🐄🐖🐏🐑🐐🐪🐫🦙🦘🦥🦨🦡🐘🐁🐀🦔🐇🐿🦎🐊🐢🐍🐉🦕🦖🦦🦈🐬🐳🐋🐟🐠🐡🦐🦑🐙🦞🦀🐚🦆🐓🦃🦅🕊🦢🦜🦩🦚🦉🐦🐧🐥🐤🐣🦇🦋🐌🐛🦟🦗🐜🐝🐞🦂🕷🕸🦠🧞‍♀️🧞‍♂️🗣👤👥👁👀🦴🦷👅👄🧠🦾🦿👣🤺⛷🤼‍♂️🤼‍♀️👯‍♂️👯‍♀️💑👩‍❤️‍👩👨‍❤️‍👨💏👩‍❤️‍💋‍👩👨‍❤️‍💋‍👨👪👨‍👩‍👦👨‍👩‍👧👨‍👩‍👧‍👦👨‍👩‍👦‍👦👨‍👩‍👧‍👧👨‍👨‍👦👨‍👨‍👧👨‍👨‍👧‍👦👨‍👨‍👦‍👦👨‍👨‍👧‍👧👩‍👩‍👦👩‍👩‍👧👩‍👩‍👧‍👦👩‍👩‍👦‍👦👩‍👩‍👧‍👧👩‍👦👩‍👧👩‍👧‍👦👩‍👦‍👦👩‍👧‍👧👨‍👦👨‍👧👨‍👧‍👦👨‍👦‍👦👨‍👧‍👧👭👩🏻‍🤝‍👩🏻👩🏼‍🤝‍👩🏻👩🏼‍🤝‍👩🏼👩🏽‍🤝‍👩🏻👩🏽‍🤝‍👩🏼👩🏽‍🤝‍👩🏽👩🏾‍🤝‍👩🏻👩🏾‍🤝‍👩🏼👩🏾‍🤝‍👩🏽👩🏾‍🤝‍👩🏾👩🏿‍🤝‍👩🏻👩🏿‍🤝‍👩🏼👩🏿‍🤝‍👩🏽👩🏿‍🤝‍👩🏾👩🏿‍🤝‍👩🏿👫👩🏻‍🤝‍🧑🏻👩🏻‍🤝‍🧑🏼👩🏻‍🤝‍🧑🏽👩🏻‍🤝‍🧑🏾👩🏻‍🤝‍🧑🏿👩🏼‍🤝‍🧑🏻👩🏼‍🤝‍🧑🏼👩🏼‍🤝‍🧑🏽👩🏼‍🤝‍🧑🏾👩🏼‍🤝‍🧑🏿👩🏽‍🤝‍🧑🏻👩🏽‍🤝‍🧑🏼👩🏽‍🤝‍🧑🏽👩🏽‍🤝‍🧑🏾👩🏽‍🤝‍🧑🏿👩🏾‍🤝‍🧑🏻👩🏾‍🤝‍🧑🏼👩🏾‍🤝‍🧑🏽👩🏾‍🤝‍🧑🏾👩🏾‍🤝‍🧑🏿👩🏿‍🤝‍🧑🏻👩🏿‍🤝‍🧑🏼👩🏿‍🤝‍🧑🏽👩🏿‍🤝‍🧑🏾👩🏿‍🤝‍🧑🏿👬👨🏻‍🤝‍👨🏻👨🏼‍🤝‍👨🏻👨🏼‍🤝‍👨🏼👨🏽‍🤝‍👨🏻👨🏽‍🤝‍👨🏼👨🏽‍🤝‍👨🏽👨🏾‍🤝‍👨🏻👨🏾‍🤝‍👨🏼👨🏾‍🤝‍👨🏽👨🏾‍🤝‍👨🏾👨🏿‍🤝‍👨🏻👨🏿‍🤝‍👨🏼👨🏿‍🤝‍👨🏽👨🏿‍🤝‍👨🏾👨🏿‍🤝‍👨🏿👨🏿‍🤝‍👨 👩👨🧑👧👦🧒👶👵👴🧓👩‍🦰👨‍🦰👩‍🦱👨‍🦱👩‍🦲👨‍🦲👩‍🦳👨‍🦳👱‍♀️👱‍♂️👸🤴👳‍♀️👳‍♂️👲🧔👼🤶🎅👮‍♀️👮‍♂️🕵️‍♀️🕵️‍♂️💂‍♀️💂‍♂️👷‍♀️👷‍♂️👩‍⚕️👨‍⚕️👩‍🎓👨‍🎓👩‍🏫👨‍🏫👩‍⚖️👨‍⚖️👩‍🌾👨‍🌾👩‍🍳👨‍🍳👩‍🔧👨‍🔧👩‍🏭👨‍🏭👩‍💼👨‍💼👩‍🔬👨‍🔬👩‍💻👨‍💻👩‍🎤👨‍🎤👩‍🎨👨‍🎨👩‍✈️👨‍✈️👩‍🚀👨‍🚀👩‍🚒👨‍🚒🧕👰🤵🤱🤰🦸‍♀️🦸‍♂️🦹‍♀️🦹‍♂️🧙‍♀️🧙‍♂️🧚‍♀️🧚‍♂️🧛‍♀️🧛‍♂️🧜‍♀️🧜‍♂️🧝‍♀️🧝‍♂️🧟‍♀️🧟‍♂️🙍‍♀️🙍‍♂️🙎‍♀️🙎‍♂️🙅‍♀️🙅‍♂️🙆‍♀️🙆‍♂️🧏‍♀️🧏‍♂️💁‍♀️💁‍♂️🙋‍♀️🙋‍♂️🙇‍♀️🙇‍♂️🤦‍♀️🤦‍♂️🤷‍♀️🤷‍♂️💆‍♀️💆‍♂️💇‍♀️💇‍♂️🧖‍♀️🧖‍♂️🤹‍♀️🤹‍♂️👩‍🦽👨‍🦽👩‍🦼👨‍🦼👩‍🦯👨‍🦯🧎‍♀️🧎‍♂️🧍‍♀️🧍‍♂️🚶‍♀️🚶‍♂️🏃‍♀️🏃‍♂️💃🕺🧗‍♀️🧗‍♂️🧘‍♀️🧘‍♂️🛀🛌🕴🏇🏂🏌️‍♀️🏌️‍♂️🏄‍♀️🏄‍♂️🚣‍♀️🚣‍♂️🏊‍♀️🏊‍♂️🤽‍♀️🤽‍♂️🤾‍♀️🤾‍♂️⛹️‍♀️⛹️‍♂️🏋️‍♀️🏋️‍♂️🚴‍♀️🚴‍♂️🚵‍♀️🚵‍♂️🤸‍♀️🤸‍♂️🤳💪🦵🦶👂🦻👃🤏👈👉☝👆👇✌🤞🖖🤘🤙🖐✋👌👍👎✊👊🤛🤜🤚👋🤟✍👏👐🙌🤲🙏🤝💅 🎈🎆🎇🧨✨🎉🎊🎃🎄🎋🎍🎎🎏🎐🎑🧧🎀🎁🎗🎞🎟🎫🎠🎡🎢🎪🎭🖼🎨🧵🧶🛒👓🕶🦺🥽🥼🧥👔👕👖🩳🧣🧤🧦👗🥻👘👚🩲🩱👙👛👜👝🛍🎒👞👟🥾🥿👠👡👢🩰👑🧢⛑👒🎩🎓💋💄💍💎⚽⚾🥎🏀🏐🏈🏉🎱🎳🥌⛳⛸🎣🤿🎽🛶🎿🛷🥅🏒🥍🏏🏑🏓🏸🎾🥏🪁🎯🥊🥋🥇🥈🥉🏅🎖🏆🎮🕹🎰🎲🔮🧿🧩🧸🪀🎴🃏🀄♟♠♣♥♦🔈🔉🔊📢📣🔔🎼🎵🎶🎙🎤🎚🎛🎧📯🥁🎷🎺🎸🪕🎻🎹📻🔒🔓🔏🔐🔑🗝🪓🔨⛏⚒🛠🔧🔩🧱⚙🗜🛢⚗🧪🧫🧬🩺💉🩸🩹💊🔬🔭⚖📿🔗⛓🧰🧲🦯🛡🏹🗡⚔🔪💣🔫☎📞📟📠📱📲📳📴🚬⚰⚱🗿🔋🔌💻🖥🖨⌨🖱🖲💽💾💿📀🧮🎥🎬📽📡📺📷📸📹📼🔍🔎🕯🪔💡🔦🏮📔📕📖📗📘📙📚📓📒📃📜📄📑📰🗞🔖🏷💰💴💵💶💷💸💳🧾🏧✉📧📨📩📤📥📦📫📪📬📭📮🗳✏✒🖋🖊🖌🖍📝🗒💼📁📂🗂📅📆🗓📇📈📉📊📋📌📍📎🖇📏📐✂🗃🗄🗑⌛⏳⌚⏰⏱⏲🕰 🍕🍔🍟🌭🍿🧂🥓🥚🍳🧇🥞🧈🍞🥐🥨🥯🥖🧀🥗🥙🥪🌮🌯🥫🍖🍗🥩🍠🥟🥠🥡🍱🍘🍙🍚🍛🍜🦪🍣🍤🍥🥮🍢🧆🥘🍲🍝🥣🥧🍦🍧🍨🍩🍪🎂🍰🧁🍫🍬🍭🍡🍮🍯🍼🥛🧃☕🍵🧉🍶🍾🍷🍸🍹🍺🍻🥂🥃🧊🥤🥢🍽🍴🥄🏺🥝🥥🍇🍈🍉🍊🍋🍌🍍🥭🍎🍏🍐🍑🍒🍓🍅🍆🌽🌶🍄🥑🥒🥬🥦🥔🧄🧅🥕🌰🥜💐🌸🏵🌹🌺🌻🌼🌷🥀☘🌱🌲🌳🌴🌵🌾🌿🍀🍁🍂🍃 🚗🚓🚕🛺🚙🚌🚐🚎🚑🚒🚚🚛🚜🚘🚔🚖🚍🦽🦼🛹🚲🛴🛵🏍🏎🚄🚅🚈🚝🚞🚃🚋🚆🚉🚊🚇🚟🚠🚡🚂🛩🪂✈🛫🛬💺🚁🚀🛸🛰⛵🚤🛥⛴🛳🚢⚓🚏⛽🚨🚥🚦🚧🏁🏳‍🌈🏳🏴🏴‍☠️🚩🌌🪐🌍🌎🌏🗺🧭🏔⛰🌋🗻🛤🏕🏞🛣🏖🏜🏝🏟🏛🏗🏘🏙🏚🏠🏡⛪🕋🕌🛕🕍⛩🏢🏣🏤🏥🏦🏨🏩🏪🏫🏬🏭🏯🏰💒🗼🌉🗽🗾🎌⛲⛺🌁🌃🌄🌅🌆🌇♨💈🛎🧳🪑🚪🛏🛋🚽🧻🚿🛁🧼🧽🧴🪒🧷🧹🧺🧯☁⛅⛈🌤🌥🌦🌧🌨🌩🌪🌫🌝🌑🌒🌓🌔🌕🌖🌗🌘🌙🌚🌛🌜☀🌞⭐🌟🌠☄🌡🌬🌀🌈🌂☂☔⛱⚡❄☃⛄🔥💧🌊 ❤🧡💛💚💙💜🤎🖤🤍💔❣💕💞💓💗💖💘💝💟💌💢💥💤💦💨💫🕳☮✝☪🕉☸✡🔯🕎☯☦🛐⛎♈♉♊♋♌♍♎♏♐♑♒♓🆔⚕♾⚛🈳🈹🈶🈚🈸🈺🈷✴🆚🉑💮🉐㊙㊗🈴🈵🈲🚼🅰🅱🆎🆑🅾🆘⛔🛑📛❌⭕🚫🔇🔕🚭🚷🚯🚳🚱🔞📵❗❕❓❔‼⁉💯🔅🔆🔱⚜〽☢☣⚠🚸🔰♻🈯💹❇✳❎✅💠🌐Ⓜ🈂➿🛂🛃🛄🛅♿🚾🅿🚰🚹🚺🚻🚮📶🈁🆖🆗🆙🆒🆕🆓#️⃣*️⃣0️⃣1️⃣2️⃣3️⃣4️⃣5️⃣6️⃣7️⃣8️⃣9️⃣🔟🔢▶⏸⏯⏹⏺⏭⏮⏩⏪🔀🔁🔂◀🔼⏫🔽⏬⏏🎦➡⬅⬆⬇↗↘↙↖↕↔🔄↪↩⤴⤵ℹ🔤🔡🔠🔣🔃🔛🔝🔜☑🔚🔙〰➰✔💲💱➕➖✖➗©®™🔘🔴🟠🟡🟢🔵🟣🟤⚫⚪🟥🟧🟨🟩🟦🟪🟫⬛⬜◼◻◾◽▪▫🔶🔸🔷🔹🔺🔻🔲🔳💭🗯💬🗨👁‍🗨🕐🕑🕒🕓🕔🕕🕖🕗🕘🕙🕚🕛🕜🕝🕞🕟🕠🕡🕢🕣🕤🕥🕦🕧 ;-)¯\_(ツ)_/¯( •_•)>⌐■-■(⌐■_■):-P:-((•_•)( ´・・)ノ(._.`)༼ つ ◕_◕ ༽つ(ˉ﹃ˉ)(╯°□°)╯︵ ┻━┻ಠ_ಠಥ_ಥ:-Dᓚᘏᗢ(┬┬﹏┬┬)^_^:-)(^///^)╰(*°▽°*)╯☆*: .。. o(≧▽≦)o .。.:*☆(*/ω\*)(●'◡'●)(❁´◡`❁)(☞゚ヮ゚)☞☜(゚ヮ゚☜)(¬‿¬)(¬_¬ )(T_T)(⊙_⊙;) 😁 is ["\uD83D\uDE01"](https://www.fileformat.info/info/unicode/char/1f601/index.htm), or 0n55357, 0n56833 </details> ```c++ OutputCellView OutputCellIterator::s_GenerateView(const std::wstring_view view, const TextAttribute attr, const TextAttributeBehavior behavior) { const auto glyph = Utf16Parser::ParseNext(view); DbcsAttribute dbcsAttr; if (IsGlyphFullWidth(glyph)) { dbcsAttr.SetLeading(); } return OutputCellView(glyph, dbcsAttr, attr, behavior); } ``` As the two `wchar_t`s get written to the buffer by `WriteCharsLegacy`, we create an `OutputCellIterator` to write each half of the emoji. Unfortunately, we write each half one char at a time. `Utf16Parser::ParseNext` doesn't like that. It knows the first `wchar_t` is a leading byte, but can also tell there's no trailing byte, so it just returns a Replacement char. The character does end up getting inserted into the cooked read data correctly, which is why hitting enter to submit the commandline in `cmd` works just fine. The data in the cooked read data is correct, but the text buffer has the wrong data. Presumably, the cooked read is just writing the text buffer wrong. `COOKED_READ_DATA::ProcessInput` can only handle one `wchar_t` at a time. When you use the emoji picker to input the character, it first comes through `ConversionAreaInfo::WriteText` straight to `_screenBuffer->Write` to draw the composition buffer. Then, once the dialog is dismissed, the keys get sent to the input buffer in `ConsoleImeInfo::_InsertConvertedString`, where again the cooked read gets them one char at a time to display broken in the buffer. <hr> EDIT: March 30th 2020 I've investigated into this a bit, and this is one of those terrible rabbit-hole issues. Even if we do add support for simply typing/pasting emoji to `COOKED_READ`, that opens up a whole other can of bugs. Then, `COOKED_READ` should probably also be enlightened to support _backspacing_ an emoji. Also, what happens for applications that are expecting UCS-2 input, not utf-16? It's an unfortunately complex issue that we'll have to resolve on the console side of things. This is now the "COOKED_READ (cmd.exe) doesn't properly support emoji input" issue, and I'm moving this to 21H1 as a "Feature", so we can try and prioritize for the next Windows release. <details> <summary>Code Snippet for future developers</summary> I found that I could get cooked read to draw the emoji right every time by re-printing the buffer each time, but that wouldn't work for backspacing through emoji. Take a look at this segment for code for `COOKED_READ_DATA::ProcessInput` ```c++ if (AtEol()) { // If at end of line, processing is relatively simple. Just store the character and write it to the screen. if (wch == UNICODE_BACKSPACE2) { wch = UNICODE_BACKSPACE; } if (wch != UNICODE_BACKSPACE || _bufPtr != _backupLimit) { fStartFromDelim = IsWordDelim(_bufPtr[-1]); bool loop = true; while (loop) { loop = false; if (wch == UNICODE_BACKSPACE && _processedInput) { _bufPtr -= 1; // clang-format off #pragma prefast(suppress: __WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY, "This access is fine") // clang-format on *_bufPtr = (WCHAR)' '; _currentPosition -= 1; _screenInfo.GetTextBuffer().GetCursor().SetPosition(_originalCursorPosition); status = WriteCharsLegacy(_screenInfo, _backupLimit, _backupLimit, _backupLimit, &_bytesRead, &NumSpaces, _originalCursorPosition.X, WC_DESTRUCTIVE_BACKSPACE | WC_KEEP_CURSOR_VISIBLE | WC_ECHO, &ScrollY); _bytesRead -= sizeof(WCHAR); // Repeat until it hits the word boundary if (wchOrig == EXTKEY_ERASE_PREV_WORD && _bufPtr != _backupLimit && fStartFromDelim ^ !IsWordDelim(_bufPtr[-1])) { loop = true; } } else { *_bufPtr = wch; _bytesRead += sizeof(WCHAR); _bufPtr += 1; _currentPosition += 1; } if (_echoInput) { NumToWrite = sizeof(WCHAR); _screenInfo.GetTextBuffer().GetCursor().SetPosition(_originalCursorPosition); status = WriteCharsLegacy(_screenInfo, _backupLimit, _backupLimit, _backupLimit, &_bytesRead, &NumSpaces, _originalCursorPosition.X, WC_DESTRUCTIVE_BACKSPACE | WC_KEEP_CURSOR_VISIBLE | WC_ECHO, &ScrollY); if (NT_SUCCESS(status)) { _originalCursorPosition.Y += ScrollY; } else { RIPMSG1(RIP_WARNING, "WriteCharsLegacy failed %x", status); } } // if (wch == UNICODE_BACKSPACE && _processedInput) // { // _bytesRead -= sizeof(WCHAR); // } _visibleCharCount += NumSpaces; } } } else ``` </details>
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#2042