text:
A keyboard so real you can almost TASTE it
... Not that you would, would you? The task is simple, output the following text:
 ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ________
||` |||1 |||2 |||3 |||4 |||5 |||6 |||7 |||8 |||9 |||0 |||- |||= |||BS    ||
||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||______||
|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/______\|
 ________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
||TAB   |||Q |||W |||E |||R |||T |||Y |||U |||I |||O |||P |||[ |||] |||\ ||
||______|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__||
|/______\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|
 _________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ________
||CAPS   |||A |||S |||D |||F |||G |||H |||J |||K |||L |||; |||' |||ENTER ||
||_______|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||______||
|/_______\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/______\|
 ___________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___________
||SHIFT    |||Z |||X |||C |||V |||B |||N |||M |||, |||. |||/ |||SHIFT    ||
||_________|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||_________||
|/_________\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/_________\|

This is the keyboard of the future because in the future spaces are irrelevant, so are spacebars.

To make things a little bit easier on you:

0123456789ABC...XYZ-=[]\;',./ - These chars are on keys of length 6 (including padding).
TAB / BS / ENTER - These keys are of length 10 (including padding).
CAPS - This key is of length 11 (including padding).
SHIFT - This key is of length 13 (including padding, on both sides).

Each individual key looks more or less like this:
 ____
||* ||
||__||
|/__\|

However, you should make note that two consecutive keys are not:
 ____  ____
||* ||||* ||
||__||||__||
|/__\||/__\|

But they are "conjoined":
 ____ ____
||* |||* ||
||__|||__||
|/__\|/__\|

This challenge shouldn't be too bad, best of luck to you; don't miss out on abusing the repetition! But don't underestimate the "special" keys either ;).

Winning?
Shortest code wins because it's code-golf you know.

Gotta admit I'm surprised not many people are concerned about futuristic keyboards not containing spaces...

It occurs to me, this might technically be a duplicate of this

@ATaco I disagree. That one is just plain English, this one is ASCII-art. I'm sure the approaches will be very different too.

@DjMcMayhem Although I do quite enjoy this challenge, and agree it shouldn't be considered a duplicate, the community does tend to agree that challenges that simply require a constant text to be outputted are a duplicate of that.

I guess spaces weren't the final frontier after all.

"TASTE" is the german word for "key" :)

"TASTE" is the Norwegian word for "typing" :)

But it's the English word for "flavour". Here.

"TASTE" is the Czech (conditional) "draw" like in "[please] draw your sword"... DRAW YOUR KEYBOARD OUT AND DO NOT LICK IT :)

@StewieGriffin but also for "enter", "input", "key" and "keypad" according to Uncle Google's translator.

@KevinCruijssen We can finally drop this complicated whitespace-delineated mixed-width language and switch to a fixed-width language like 中文（あるいは日本語）;)

that moment when, on your new spacebar-less keyboard, you realise you actually need spaces, to make the ascii representation line up correctly!

Now every time I look at a keyboard, I will only think of a giant chocolate bar. Thanks for that. Taste

This is the keyboard of the future – I hope not, it’s still QWERTY.

@Wrzlprmft Still better than AZERTY. >_>

In Italian keyboard is TASTIERA, key is TASTO and keys are TASTI.

@carusocomputing I just want to say, this is hands down the most fun I've ever had on a challenge. Even 6 months later, it's fun to try and golf down. :D

@DJMcMayhem "edited 7 mins ago" xD! each time I get an upvote on here I swear your answer has lost a byte or two.

V, 189, 179, 175, 164, 161, 157, 155, 149, 145, 141, 135 bytes
¬19É`A0-=BS´
TAB³ qwertyuiop[]\
CAPS³ asdfghjkl;'ENTER
SHIFT´ ÄJizxcvbnm,./Í„A-Z ]/Õ&
ÍÓ«ü$/|||&
òÙÓ„|]/_
ÙÓ×«/Ü|¯
kkPÓ/_ _
kòÎx$x

Try it online!
This answer is now tweetable!

Watch it run! This is a slightly modified version that updates as it runs so you can sorta see how it works. This is an outdated version since I haven't gotten around to re-recording it yet, but the general approach is identical.
This is probably the longest V answer ever written. It certainly didn't help that V's interpreter is extremely slow. It took me around an hour to write the first revision, but I've been repeatedly coming back to it to shave a couple bytes off each time. Since the full keyboard is 1215 bytes, currently this answer is 91% shorter than the output, so I'm pretty happy with the results.
Since this contains some unprintable characters, and a lot of gross non-ASCII, here's a hexdump:
00000000: ac31 39c9 6041 302d 3d42 53b4 200a 5441  .19.`A0-=BS. .TA
00000010: 42b3 2071 7765 7274 7975 696f 705b 5d5c  B. qwertyuiop[]\
00000020: 0a43 4150 53b3 2061 7364 6667 686a 6b6c  .CAPS. asdfghjkl
00000030: 3b27 454e 5445 5220 0a53 4849 4654 b420  ;'ENTER .SHIFT.
00000040: 1bc4 4a69 7a78 6376 626e 6d2c 2e2f 1bcd  ..Jizxcvbnm,./..
00000050: 8441 2d5a 205d 2fd5 2620 0acd d3ab fc24  .A-Z ]/.& .....$
00000060: 2f7c 7c7c 260a f2d9 d384 7c5d 2f5f 0ad9  /|||&.....|]/_..
00000070: d3d7 ab2f dc7c af0a 6b6b 50d3 2f5f 205f  .../.|..kkP./_ _
00000080: 0a6b f2ce 7824 78                        .k..x$x

How the heck does it work?
Alright, this explanation is gonna be a doozy. You ready? First off, we need enter the letters so we can build up the keys around them. This is
¬19É`A0-=BS´
TAB³ qwertyuiop[]\
CAPS³ asdfghjkl;'ENTER
SHIFT´ <esc>ÄJizxcvbnm,./<esc>

Which inserts:
`1234567890-=BS
TAB   qwertyuiop[]\
CAPS   asdfghjkl;'ENTER
SHIFT    zxcvbnm,./SHIFT

It enters it pretty straightforward, but there are a few tricks that we use to save characters. For example, ¬19 enters "123456789", ³  enters three spaces, and we duplicate the shift so that we don't need to enter it multiple times.
Note how the letters are lowercase here. This is so that we can easily distinguish between the uppercase keys like "ENTER" and the single letters. Writing them this way makes it easier to tell which characters to put a bar before, and only adds one byte to convert them to lowercase later. So we do a substitute command to convert these to uppercase, and add one space after each of them:
Í               " Globally replace
 [^A-Z ]        " Anything but a uppercase alphabet character or a space
        /       " with
         Õ&     " The matched pattern made uppercase, followed by a space

Now, we take each key sequence (any run of non-whitespace), and put three bars before and after them:
Í           " Globally replace
 Ó«         "   Any number of non-space characters
   ü        "   or
    $       "   an end of line
     /      " with
      |||   "    Three bars
         &  "    And the matched pattern

At this point, the buffer looks like this:
|||` |||1 |||2 |||3 |||4 |||5 |||6 |||7 |||8 |||9 |||0 |||- |||= |||BS    |||
|||TAB   |||Q |||W |||E |||R |||T |||Y |||U |||I |||O |||P |||[ |||] |||\ |||
|||CAPS   |||A |||S |||D |||F |||G |||H |||J |||K |||L |||; |||' |||ENTER |||
|||SHIFT    |||Z |||X |||C |||V |||B |||N |||M |||, |||. |||/ |||SHIFT    |||

Having three bars on the first and last columns is actually very convenient and ends up saving many bytes in the long run.
And here is where we run one giant loop. This will convert something like this:
|||SHIFT    |||Z |||X |||C |||V |||B |||N |||M |||, |||. |||/ |||SHIFT    |||

into something like this:
 ___________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___________
||SHIFT    |||Z |||X |||C |||V |||B |||N |||M |||, |||. |||/ |||SHIFT    ||
||_________|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||_________||
|/_________\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/_________\|

Everything between two instances of ò will run until an error happens, which will happen when we try to go up into a line that does exist yet. Since we just ran a globally substitute command, our cursor is on the last line, and we'll transform these working our way up.
ò         " Recursively:
 Ù        "   Duplicate this line
  Ó       "   Substitute all on this line:
   [^|]   "     Anything but a bar
       /  "   With:
        _ "     An underscore

This is the
|||_________|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||_________|||

line.
Ù         "   Duplicate this line
 Ó        "   Subsitute all on this line:
  ×«      "     A run of *non-word characters* (that is, [^0-9A-Za-z_])
    /     "   With:
     Ü|¯  "     '\|/'

This is the
\|/_________\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/_________\|/

Line.
kk        "   Move up two lines (to the original text with "SHIFT")
  P       "   Paste the last line we duplicated (the one with all the underscores)
   Ó      "   Substitute:
          "     Since we don't give any regex here, it re-uses the last one
          "     (a run of *non-word* characters)
    /     "   With:
     _ _  "     '_ _'

This is the:
_ ___________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___________ _

Line.
k         "   Move up a line (this will throw an error, breaking the loop when we're done)
 ò        " Endwhile

Now we have the full keyboard, but each line contains either an extra bar, an extra slash (forward or backward), or an extra underscore. Super easy fix
Î             " On every line:
 x            "   Delete a character
  $           "   Move to the end of the line
   x          "   and delete another character

After all that madness, the buffer is implicitly printed.

There appear to be 4 extra underscores in the blank space off the right side of the output?

@ErikE On the online interpreter or in the gif? The gif does produce slightly wrong output, but I'm not sure why. It is a modified version though, so I'm not worried about the output being wrong since the original one is right.

Yes, the gif. Ok, no problem, just wanted you to know!

You underestimate how golfy this answer actually is lol.

@carusocomputing Haha, I guess you're right. I'm very proud of this answer and my language to be the only answer beating bubblegum. :)

@DJMcMayhem Marking you as the winner if nobody beats you by 1/3/2017 ;).

Still working out some more bytes I see :P?

@carusocomputing Haha, yep. This challenge is really fun, I'm sure there's a few more bytes in there somewhere. :P

This is still by far my favorite answer on the site, by the way. I can't count how many times I've watched the GIF.

Lua 5.3, 416 394 Bytes.
k="` 1 2 3 4 5 6 7 8 9 0 - = BS|TAB Q W E R T Y U I O P [ ] \\|CAPS A S D F G H J K L ; ' ENTER|SHIFT Z X C V B N M , . / SHIFT"S={TAB=6,BS=6,ENTER=6,CAPS=7,SHIFT=9}for v in k:gmatch"[^|]+"do for i=1,4 do for s in v:gmatch"%S+"do l=S[s]or 2j=("_"):rep(l)io.write(i==1 and" _"..j.."_"or i==2 and"||"..s..(" "):rep(l-#s).."|"or i==3 and"||"..j.."|"or"|/"..j.."\\")end print(i>1 and"|"or"")end end

Ungolfed and with comments.
keys="` 1 2 3 4 5 6 7 8 9 0 - = BS|TAB Q W E R T Y U I O P [ ] \\|CAPS A S D F G H J K L ; ' ENTER|SHIFT Z X C V B N M , . / SHIFT" -- Define a keyboard. Separated with |'s, there's probably a nicer way to do this, but I'm not sure about how to yet.
special_keys={TAB=6,BS=6,ENTER=6,CAPS=7,SHIFT=9} -- Special keys get special definitions
for v in keys:gmatch"[^|]+" do -- For each row on the keyboard...
    for i=1, 4 do -- Each of the 4 rows per key...
        for s in v:gmatch"%S+" do -- Match each individual key.
            l=special_keys[s]or 2 j=("_"):rep(l) -- l is the length of the key, j is "_" repeated length times, which is used a bit.
            io.write(i==1 and -- Lua needs Switch Statements!
                     " _"..j.."_" -- The top of the key is a Space, then j with two _'s around it.
                     or
                     i==2 and
                     "||"..s..(" "):rep(l - #s).."|" -- Second row is || then the key, then the remaining whitespace, and then one more |, which chains together.
                     or
                     i==3 and
                     "||"..j.."|" -- Third row is like the second, but without the key. Instead of whitespace, uses j, which is the underlines.
                     or
                     "|/"..j.."\\") -- Last row is like the third row, but with "|/" and "\" instead of "||" and "|"
        end
        print(i>1 and"|"or"") -- First line is the only line that doresn't need a "|", everything else gets a "|" before the newline.

    end
end

Output
 ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ________
||` |||1 |||2 |||3 |||4 |||5 |||6 |||7 |||8 |||9 |||0 |||- |||= |||BS    ||
||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||______||
|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/______\|
 ________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
||TAB   |||Q |||W |||E |||R |||T |||Y |||U |||I |||O |||P |||[ |||] |||\ ||
||______|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__||
|/______\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|
 _________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ________
||CAPS   |||A |||S |||D |||F |||G |||H |||J |||K |||L |||; |||' |||ENTER ||
||_______|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||______||
|/_______\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/______\|
 ___________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___________
||SHIFT    |||Z |||X |||C |||V |||B |||N |||M |||, |||. |||/ |||SHIFT    ||
||_________|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||_________||
|/_________\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/_________\|

I'm going to get destroyed by other langauges, but I thought I'd give this a shot. Nice amount of complexity, and atleast it's shorter than the keyboard!

Screw other languages, you were the first in a rare language! Impressive, though I'm sure you definitely don't need to put pipes as delimiters on every letter. Notice how the "special" keys are only at the front and end of lines. I'm sure that hint could save you precious bytes somehow.

Which version of Lua are you using? On Lua 5.1 it gives me a syntax error: stdin:1: malformed number near '2j'

@Brianush1 Lua 5.3, It allows number constants to sit next to any letter that isn't a hexadecimal digit or 'x' in the case of 0.

Bubblegum, 191 bytes
0000000: ad d2 35 7a c6 30 10 06 e1 5e a7 50 15 66 fe 99  ..5z.0...^.P.f..
0000010: c1 8c 61 50 0e b2 87 8f 27 24 f7 eb af 78 2b e3  ..aP....'$...x+.
0000020: 3c b2 ae 99 1a 66 8d c8 a7 15 91 73 b8 80 4b b8  <....f.....s..K.
0000030: 82 6b b8 81 5b b8 83 1e 9c c1 31 8c 60 5e d9 66  .k..[.....1.`^.f
0000040: 22 46 c4 39 d1 c2 78 d6 a9 73 6f 5a d8 9b 18 ff  "F.9..x..soZ....
0000050: bb 5a e8 55 cf e6 fc ae 48 01 8f b0 82 12 6a 78  .Z.U....H.....jx
0000060: 86 7b 08 20 83 1c 5e e1 1d de e8 e5 7f 57 b4 d0  .{. ..^......W..
0000070: 8b a9 9b f9 5e 5d 9d af c5 2c af 7e 82 cd a0 82  ....^]...,.~....
0000080: 25 ac 61 03 5b 08 21 82 18 06 b0 0b ab b4 5e 95  %.a.[.!.......^.
0000090: ad 5e 5d 9d 2f d6 e9 f9 d2 c4 f2 bd aa 6d b0 ae  .^]./........m..
00000a0: ed 4f b1 17 78 82 05 3c c0 1c 52 48 e0 08 4e e0  .O..x..<..RH..N.
00000b0: 14 5a 77 fb 5e aa 58 be 97 aa 98 bf db 7c 01     .Zw.^.X......|.

Try it online!

Bubblegum isn't fair.

@Joshua it's good to set a baseline for solutions. and if nothing can beat bubblegum, that's problem's problem.

Haskell, 263 chars (353 bytes UTF-8)
import Data.List
main=mapM_ putStrLn$transpose.foldr k[g]=<<
 [s"`1234567890-="%"   ←"
 ,"↹   ":s"[]\\"
 ,"⇩    ":s";'"%"     ↵"
 ,"⇧       ":s",./"%"       ⇧"]
r%e=r++[e]
g=" |||"
k s r=g:"_||/":['_':c:"__"|c<-s]%"_||\\"++r
s=map(:" ")

As there has been a lot of discussion about the score in light of these unicode characters... here's the same program, reduced to all-ASCII:
Haskell, 263 chars (263 bytes UTF-8)
import Data.List
main=mapM_ putStrLn$transpose.foldr k[g]=<<
 [s"`1234567890-="%"BS  "
 ,"TAB ":s"QWERTYUIOP[]\\"
 ,"CAPS ":s"ASDFGHJKL;'"%"ENTER "
 ,"SHIFT   ":s"ZXCVBNM,./"%"SHIFT   "]
r%e=r++[e]
g=" |||"
k s r=g:"_||/":['_':c:"__"|c<-s]%"_||\\"++r
s=map(:" ")

Unicode keyboard? Interesting choice (nice looking math letters there), but I think it violates the competition rules.

@MarioCarneiro To be fair, it doesn't affect the length of the program at all.

@pydsigner It does, since words like ENTER are longer than characters like ↩.

But you're comparing ENTER  and ↩      , The whitespace padding makes it the same length.

Actually, I expect the unicode to make the program longer by byte count, since high unicode is more bytes in UTF8 than ASCII.

231 bytes

PHP, 303 bytes
Lazy but effective. :)
<?=gzinflate(base64_decode('rdO5DoJAEIDhnqegs/G+jbEAvA88wBuzPsg8vPyLZo3tOMUXmt1k/iy+ycfXYj88kacvIg1oQgva0IEu9KAPA6hDBUYQJn4+IvldxogWhrtqxmRamEw8t66afMc0CO26soczTOAAKVzhCAvYwg7u8IDs06tYVx3Oc+uqw7lef3lfUbBLimABJDCGKcxgDktYwRqGULJ143Ry+O71r/elDvb7vnSx3r2S+WKaFn+U3OACEZzs7wYxbKAMVajZvO6066WK9dNLFcuefgE'));

Nice. Annoyingly, I cannot get the same level of compression with compress/gzip/bzip2/7z, otherwise the Bash version would be trivially shorter. As it stands, it’s at 318 characters instead.

I'm pretty sure using an external compression algorithm not in your program is banned or at least frowned upon. It defeats the purpose of the question.

@KonradRudolph As I understand it, gzdeflate() uses the same compression as gzip command line but skips the file header and checksum so it will always be just a bit shorter.

300 bytes: <?=gzinflate(base64_decode('rdO5DoJAEIDhnqegs/G+jbHA+0QEvDHrg8zDy79EMbTDFF+3m8yfXdek42phHJG3KyItaEMHutCDPgxgCCNoQg0mMI3cdETSu4wRLQx3NYxJtDCJOL9t1cnSFWNvareVE1xhASHEcIczbOAIATzhBck3V7atupuTb6vulucq43XNvCDKenkQwRyWsII1bGEHexhDxcb140X4n6us16XuVXxdulZZrmi9WcbZd5IH3GAGF/vXwIcDVKEODVs3P53nUrUq5FK1sqc/'));. Compressor: http://sandbox.onlinephpfunctions.com/code/646e96c9ff46de26e17f8604370e55be99c52199 Decompressor: http://sandbox.onlinephpfunctions.com/code/4093a61e6cb082ae188cc7a477a01fad0eef67a2

@Nobody There's nothing external, gz is part of PHP's default compile and is therefore implicitly allowed.

@Nobody http://meta.codegolf.stackexchange.com/a/9814/4163

If you'd compressed the generating program, that'd be one thing. Simply embeddeing then compressing the desired output is just lazy!

Absolutely no need to do base64_decode, just paste the original binary there, escaping \", \\ , \n, \x00, \xAF and \x96. See for example http://codegolf.stackexchange.com/questions/18923/create-a-chain-of-spam-generators-in-as-many-languages-as-possible/18979#18979

@LightnessRacesinOrbit lay, of course, yes. Banned, no.

@LightnessRacesinOrbit Heh yes, please note how I freely admitted as much in my original post...

@SztupY Huh, interesting about the 0xAF and 0x96 -- perhaps that's what screwed me up when I tried doing that on another challenge. I'll keep this in mind for next time, thanks.

Python 3.5+, 239 bytes
s="SHIFT   "
for k in[(*"`1234567890-=","BS   "),("TAB  ",*"QWERTYUIOP[]\\"),("CAPS  ",*"ASDFGHJKL;'","ENTER"),(s,*"ZXCVBNM,./",s)]:
 for f in"{1}__ ,|{} ||,|{1}||,/{1}\|".split(","):print(f[-1]+"".join(f.format(c,"_"*-~len(c))for c in k))

Is Python 3.5+ needed for the splat inside the tuples, or something else?

You can save one byte if you invert the construction of each key and use "".join(...) + f[0] in the inner loop. Swapping the format argument order and the respective placeholders in the string also saves two more bytes.

['{1}__ ','|{} ||','|{1}||','/{1}\\|'] is shorter than the use of split.

Batch, 465 452 bytes
@echo off
call:c _ ` 1 2 3 4 5 6 7 8 9 0 - "=" "BS   " _____
call:c _____ "TAB  " Q W E R T Y U I O P [ ] \ _
call:c ______ "CAPS  " A S D F G H J K L ";" ' ENTER _____
call:c ________ "SHIFT   " Z X C V B N M "," . / "SHIFT   " ________
exit/b
:c
set t=%1_
set s=!!%~2 !!!%3 !!
:l
set t=%t%#__
set s=%s%!%~4 !!
shift
if not "%~5"=="" goto l
set t=%t%#%4_
for %%l in (" _%t:#=_ _%_" "%s:!=|%" "||%t:#=|||%||" "|/%t:#=\|/%\|")do echo %%~l

The :c subroutine handles a line of keys. Keys containing extra spaces need to be quoted, as do the =, ;, , keys, possibly due to a bug in the shift command. The first and last parameters are strings of _s of the same length as the first and last key to aid concatenation. t then ends up as the _s common to the first, third and fourth rows, with #s marking the join, which are replaced appropriately before the leading and trailing characters are added, while s is the second row, but with |s changed to !s as they reduce the number of "s that I need. Edit: Saved 1 byte by printing all four lines in a single statement, and 12 bytes by optimising the way I assigned the s variable.

=, ; and , need to be quoted because they are in fact additional command-line argument delimiters. See https://stackoverflow.com/a/8145923/182705

Ruby, 226 bytes
16.times{|i|puts (([[?`,'TAB  ','CAPS  ',s='SHIFT   '][j=i/4]]+%w{1234567890-= QWERTYUIOP[] ASDFGHJKL;' ZXCVBNM,./}[j].chars+[['BS   ',?\\,'ENTER',s][j]]).map{|e|e.tr('^|'[-i%4/3,2],?_)}*3*"__ _ |||_|||_\\|/"[i%4*4,4])[72,75]}

Improvements as follows:
1.No empty string elements at the beginning and end of the array. Instead the array is triplicated making 3 side-by side keyboards. After conversion to string we have 3 keyboards with outer edges missing. This is truncated to only display the middle one, complete with edges.
2.Changed version of Ruby. Used Ideone instead of 1.9.3 installed on my machine. This means .chars.to_a can be shortened to just .chars.
Ruby, 239 bytes
There's a few more bytes to be golfed out of this. Will look tomorrow.
16.times{|i|puts ((['']+[[?`,'TAB  ','CAPS  ',s='SHIFT   '][j=i/4]]+%w{1234567890-= QWERTYUIOP[] ASDFGHJKL;' ZXCVBNM,./}[j].chars.to_a+[['BS   ',?\\,'ENTER',s][j]]+['']).map{|e|e.tr('^|'[-i%4/3,2],?_)}*"__ _ |||_|||_\\|/"[i%4*4,4])[2..-2]}

ungolfed
16.times{|i|                                                            #iterate throug 16 lines of output
  puts ((['']+[[?`,'TAB  ','CAPS  ',s='SHIFT   '][j=i/4]]+              #build row from blank element plus left special key
    %w{1234567890-= QWERTYUIOP[] ASDFGHJKL;' ZXCVBNM,./}[j].chars.to_a+ #plus regular keys
   [['BS   ',?\\,'ENTER',s][j]]+['']).map{|e|                           #plus right special key and another blank element
                                      e.tr('^|'[-i%4/3,2],?_)}*         #if i%4 != 1, replace the keytop legend with _ characters
   "__ _ |||_|||_\\|/"[i%4*4,4])[2..-2]                                 #join the middle parts of the keys with ends. truncate spurious outer ends before printing.
}

C#, 357 bytes (when in one line, and incorporating most suggestions)

var s="";
foreach(var r in@"`|1|2|3|4|5|6|7|8|9|0|-|=|BS   ~TAB  |Q|W|E|R|T|Y|U|I|O|P|[|]|\~CAPS  |A|S|D|F|G|H|J|K|L|;|'|ENTER~SHIFT   |Z|X|C|V|B|N|M|,|.|/|SHIFT   ".Split('~'))
for(int i=0;i<4;s+=i>0?"|\n":"\n",i++)
foreach(var k in r.Split('|'))
{
var u=new string('_',k.Length+1);
s+=i<1?" "+u+"__"
:i<2
?"||"+k+" |"
:i<3
?"||"+u+"|"
:"|/"+u+@"\";
}
Console.Write(s);

Or, 353 with string interpolation and all other suggestions
var s="";foreach(var r in@"`|1|2|3|4|5|6|7|8|9|0|-|=|BS   ~TAB  |Q|W|E|R|T|Y|U|I|O|P|[|]|\~CAPS  |A|S|D|F|G|H|J|K|L|;|'|ENTER~SHIFT   |Z|X|C|V|B|N|M|,|.|/|SHIFT   ".Split('~'))for(int i=0;i<4;s+=i>0?"|\n":"\n",i++)foreach(var k in r.Split('|')){var u=new string('_',k.Length+1);s+=i<1?$" {u}__":i<2?$"||{k} |":i<3?$"||{u}|":$@"|/{u}\";}Console.Write(s);

Ungolfed (without string interpolation):
var solution = "";
foreach (var row in @"`|1|2|3|4|5|6|7|8|9|0|-|=|BS   ~TAB  |Q|W|E|R|T|Y|U|I|O|P|[|]|\~CAPS  |A|S|D|F|G|H|J|K|L|;|'|ENTER~SHIFT   |Z|X|C|V|B|N|M|,|.|/|SHIFT   ".Split('~'))
for (int i = 0; i < 4; solution += i > 0 ? "|\n" : "\n", i++)
foreach (var key in row.Split('|'))
{
   var underscores = new string('_', key.Length + 1);
   solution += i < 1 ? " " + underscores + "__"
                     : i < 2
                     ? "||" + key + " |"
                     : i < 3
                     ? "||" + underscores + "|"
                     : "|/" + underscores + @"\";
}
Console.Write(solution);

You can save lots of bytes formatting the golfed code as one line: foreach(var r in q){for(int i=0;i<4;i++){foreach...

@Mario I just byte checked it, the given value is actually the count without newlines, so it technically has already been done

Slight golf down to 397 bytes using interpolation and replacing == with < s+=i<1?$" {u}__":i<2?$"||{k.PadRight(l)}|":i<3?$"||{u}|":$"|/{u}\\";

Thanks @Alfie Goodacre. I replaced '==' with '<' as per your suggestion. I left interpolation out so to make it less version specific.

@Klinger I agree, the interpolation doesn't work on any online compilers either so that is a good choice!

You don't need to put q in a separate variable, just inline the new[] in the foreach loop. Also new string('_',l) instead of "_________".Substring(0,l).

PowerShell v2+, 465 bytes
($b=($a=' ____')*10)+$a*3+" "+($d='_'*8)
"||``@$(1..9-join'@')@0@-@=@BS    ||
||$(($f=,'__'*10-join'#'))#__#__#__#$(($g='_'*6))||
$(($c=($e='|/__\')*10))$e$e$e|/$g\|
 $d$b$a$a$a
||TAB  @Q@W@E@R@T@Y@U@I@O@P@[@]@\ ||
||$g#$f#__#__#__||
|/$g\$c$e$e$e|
 _$d$b$a $d
||CAPS  @A@S@D@F@G@H@J@K@L@;@'@ENTER ||
||_$g#$f#__#$g||
|/_$g\$c$e|/$g\|
 ___$d$b ___$d
||SHIFT   @Z@X@C@V@B@N@M@,@.@/@SHIFT    ||
||___$g#$f#___$g||
|/___$g\$c|/___$g\|"-replace'@',' #'-replace'#','|||'

I'm halfway embarrassed to be posting this answer, given how short the PHP and Python answers are, nevermind the C# answer, but I'm unable to get this method shorter. Other approaches may yield better results.
It's basically just a giant multi-line string, with variables ($a and the like) substituting for various substrings, and a couple -replaces at the end to finish it out. Script blocks $(...) are inserted where necessary to introduce new variables.
Try it online!

JavaScript (ES6), 286
An anonymous function with no parameters
_=>[..."`1234567890-=~~QWERTYUIOP[]\\~ASDFGHJKL;'~~ZXCVBNM,./~"].map(x=>(o+=`/${b='_'.repeat(w=x<y?2:' 667699'[x=["BS","TAB","CAPS","ENTER"][p++]||'SHIFT',p])}\\|`,m+=y+(x+'    ').slice(0,w)+y+y,n+=y+b+y+y,l+=' __'+b)[73]&&(k.push(l,m,n,o),l='',m=n=o=y),m=n=o=y='|',p=l=k=[])&&k.join`
`

Less golfed
_=>[..."`1234567890-=~~QWERTYUIOP[]\\~ASDFGHJKL;'~~ZXCVBNM,./~"]
  .map(x=>
      (
        w = x < y // special chars are marked '~' that is > '|'
            ? 2 // normal key, width 2
            : ( // else special key, set x and width
                // p should be incremented at next step, but I need to make it numeric as it starts as []
                x = ["BS","TAB","CAPS","ENTER"][p++]||'SHIFT',
                ' 667699'[p], // value for w (note p is off by 1)
              ),
        b = '_'.repeat(w), // bottom border (and top, almost)
        o +=`/${b}\\|`, //  line 4
        n += y+b+y+y,   //  line 3
        m += y+(x+'    ').slice(0,w)+y+y, // line 2
        l += ' __'+b    // top line, the border must be longer
      )[70] && // check if at end of row (check position in l)
         (
            k.push(l, m, n, o), // add lines to list
            l = '', // reset all
            m = n = o = y
         )
    , // initial setup
    // y stays fixed to '|', lines 2,3,4 start as '|'
    m = n = o = y ='|',
    // k is the lines array, l will become as string and starts empty
    // p is the index of current special key and will become numeric
    p = l = k = []
  )
  && k.join`\n` // return lines as a single string

F=_=>[..."`1234567890-=~~QWERTYUIOP[]\\~ASDFGHJKL;'~~ZXCVBNM,./~"].map(x=>(o+=`/${b='_'.repeat(w=x<y?2:' 667699'[x=["BS","TAB","CAPS","ENTER"][p++]||'SHIFT',p])}\\|`,m+=y+(x+'    ').slice(0,w)+y+y,n+=y+b+y+y,l+=' __'+b)[73]&&(k.push(l,m,n,o),l='',m=n=o=y),m=n=o=y='|',p=l=k=[])&&k.join`
`

O.textContent=F()
<pre id=O></pre>

Python, 493 458 Bytes.
k=[['|']*75 for i in [0]*16]
v=' '
w='_'
y=0
def a(s,x,o):k[y+o][x:x+len(s)]=list(s)
def p(s,i,x):a(s+v*(i-len(s)),x+2,1);a(v+w*(i+2)+v,x,0);a(w*i,x+2,2);a(w*i,x+2,3);a('/',x+1,3);a('\\',x+i+2,3);return x+i+3
def q(s,x):return reduce(lambda a,b:p(b,2,a),list(s),x)
p('BS',6,q('`1234567890-=',0))
y=4
q('QWERTYUIOP[]\\',p('TAB',6,0))
y=8
p('ENTER',6,q('ASDFGHJKL;\'',p('CAPS',7,0)))
y=12
p('SHIFT',9,q('ZXCVBNM,./',p('SHIFT',9,0)))
for l in k:print''.join(l)

Functionally equivalent but somewhat more readable:
k=[['|']*75 for i in range(16)]
def a(s,x,y):k[y][x:x+len(s)]=list(s)
def p(s,i,x,y):
    a(s+' '*(i-len(s)),x+2,y+1)
    a(' '+'_'*(i+2)+' ',x,y)
    a('_'*i,x+2,y+2)
    a('_'*i,x+2,y+3)
    k[y+3][x+1]='/'
    k[y+3][x+i+2]='\\'
    return x+i+3
def q(s,x,y):return reduce(lambda a,b:p(b,2,a,y),list(s),x)
p('BS',6,q('`1234567890-=',0,0),0)
q('QWERTYUIOP[]\\',p('TAB',6,0,4),4)
p('ENTER',6,q('ASDFGHJKL;\'',p('CAPS',7,0,8),8),8)
p('SHIFT',9,q('ZXCVBNM,./',p('SHIFT',9,0,12),12),12)
for l in k:print ''.join(l)

Unfortunately it's already longer than the answer provided in Lua.

You can put the lines in the p function on one line separated by semicolons. Also, I thought that you can't make the first line k=[['|']*75]*16, do you know why?

You can also define '_' and ' ' to a variable to save some bytes.

Thanks for the tips! I think k=[['|']*75]*16 creates sixteen references to the same array so a change in one line affects the others as well.

Okay, then you can at least change range(16) to [0]*16.

A small issue is that your code does not technically produce the right output, but you can fix that by changing for l in k:print ' '.join(l) to for l in k:print''.join(l).

Make the indentations only one space, save tons of bytes.

On last line, you can eliminate the space between print and ' '.

@OldBunny2800 To be honest, i coded in vim with tabs for indentations and this is how the bytes are counted.

Useless whitespace at *75 for.

PHP, 316 312 bytes
foreach([($s=str_split)("`1234567890-=")+[13=>"BS   "],["TAB  "]+$s("_QWERTYUIOP[]\\"),["CAPS  "]+$s("_ASDFGHJKL;'")+[12=>ENTER],[$h="SHIFT   "]+$s("_ZXCVBNM,./")+[11=>$h]]as$r)for($y=-1;$y++<3;)foreach($r as$i=>$k)echo["\n".$a="| "[!$y]][$i],"_||/"[$y],str_pad($y-1?_:$k,strlen($k)+1,$y-1?_:" "),"_||\\"[$y],$a;

I´m pretty sure that this approach cannot be golfed any further. But if anyone finds 10 more bytes ... :D
Run with -r.
breakdown
foreach([                       // loop through rows
    ($s=str_split)("`1234567890-=")+[13=>"BS   "],
    ["TAB  "]+$s("_QWERTYUIOP[]\\"),
    ["CAPS  "]+$s("_ASDFGHJKL;'")+[12=>ENTER],
    [$h="SHIFT   "]+$s("_ZXCVBNM,./")+[11=>$h]
]as$r)
    for($y=-1;$y++<3;)          // loop through lines 0..3
        foreach($r as$i=>$k)    // loop through keys
            echo["\n".$a="| "[!$y]][$i],// first key in row: leading NL + space/pipe
                "_||/"[$y],             // key edges
                str_pad(
                    $y-1?_:$k,          // line 1: key label; else underscore
                    strlen($k)+1,       // pad to length+1
                    $y-1?_:" "),        // with spaces for label, underscores else
                "_||\\"[$y],            // more key edges
                $a                      // joining edges
            ;

Bash (on OSX), 12 8 + 221 + 1 = 234 230 bytes
Yeah, I know, compression. But it works, no?
gunzip<f

Requires a file called "f" in the current directory with the following contents (put into base64 for PPCG-friendliness - you can decode this into the file "f" first.):
H4sIAHbPT1gAA63TuQ6CQBCA4Z6noLPxvo2xALwPPMAbsz7IPLz8i2aN7TjFFxo2mT+7vsnH12I/PJGnLyINaEIL2tCBLvSgDwOoQwVGECZ+PiL5WcaIFoazasZkWphMPLeumnzHNAjturKHM0zgAClc4QgL2MIO7vCA7NOrWFcdznPrqsO5Xn+5X1GwS4pgASQwhinMYA5LWMEahlCydeN0cvju9a/7pQ72e790sd69kvlimhYvSm5wgQhO9rlBDBsoQxVqNq/72/VSxfrppYpV9HoBoNfjQcAEAAA=

Can be made trivially shorter by writing gunzip<f.

@KonradRudolph Excellent point. Thanks.

You can save 2 bytes with zcat f, and 2 bytes by removing the two trailing null bytes (gzip complains but produces the desired output).

@Gilles Doesn't really save me bytes - I'd have to rename the file "f.Z" (on OSX at least). Removing the trailing null bytes not only makes gzip complain - it makes it error out and not print anything.

@VoteToClose Oh right, zcat<f then. On Linux, zcat without the trailing zeroes makes gzip complain (“gzip: stdin: unexpected end of file”) but only after printing the desired output.

Shouldn't the size of the gunzip binary count against your byte count? It's not part of bash.

@chepner Nope, since Bash on OSX comes prepackaged with it. It's also a part of the GNU coreutils.

bash does not come prepackaged with gunzip; they are two completely separate programs. It's not the same as a standard library that ships with a language.

No - but OSX does, which Bash imports. That's why this answer is not "Bash" but "Bash (on OSX)".

@chepner I suggest looking at this page about the use of libraries in CG.

That page says nothing about external programs (which are not libraries). You might want to read http://meta.codegolf.stackexchange.com/questions/1061/loopholes-that-are-forbidden-by-default, which contains several mentions of fetching the output from an external source.

Let us continue this discussion in chat.

Swift, 777 Bytes
func b(_ c:String,_ d:Int,_ e:Int)->[String]{var f=Array(" __ |||||||||/\\|".characters),g=[String]()
for h in 0..<4{var i="";for j in e..<4{i.append(f[j+h*4])
if j==1{var k="_",l=0;if h==1{k=" ";l=c.characters.count;i += c}
for _ in l..<d{i+=k}}};g.append(i)};return g}
func c(_ d:String)->[(String,Int)]{return Array(d.characters).map{("\($0)",2)}}
func d(_ e:String,_ f:Int)->[(String,Int)]{return [(e,f)]}
var e=[c("`1234567890-=")+d("BS",6),d("TAB",6)+c("QWERTYUIOP[]\\")]
e+=[d("CAPS",7)+c("ASDFGHJKL;'")+d("ENTER",6),d("SHIFT",9)+c("ZXCVBNM,./")+d("SHIFT",9)]
var f="";for g in 0..<e.count{let h=e[g]
var i=[[String]]();for j in 0..<h.count{
let k=h[j],l=b(k.0,k.1,(j>0 ? 1:0));i.append(l)}
for k in 0..<4{if g>0||k>0{f+="\n"}
for l in i{f+=l[k]}}};print(f,separator:"")

Swift is generally not a great language of choice for golfing, so being less than double the current smallest answer (that was fast) is a good challenge here!
Ungolfed:
func createKeyboard() {
    func createKey(_ text: String, _ middleWidth: Int, _ startingColumn: Int) -> [String] {
        var keyTempalte = " __ |||||||||/\\|"
        var keyTemplateCharacters = Array(keyTempalte.characters)

        var output = [String]()

        for y in 0 ..< 4 {
            var line = ""
            for x in startingColumn ..< 4 {
                line.append(keyTemplateCharacters[x + y*4])

                if x == 1 {
                    var spacingCharacter = "_"
                    var startingOffset = 0
                    if y == 1 {
                        spacingCharacter = " "
                        startingOffset = text.characters.count
                        line += text
                    }

                    for _ in startingOffset ..< middleWidth {
                        line += spacingCharacter
                    }
                }
            }
            output.append(line)
        }

        return output
    }

    func stringToCharacterStrings(_ str: String) -> [(String, Int)] {
        return Array(str.characters).map {("\($0)",2)}
    }

    func specialKey(_ str: String, _ middleWidth: Int) -> [(String, Int)] {
        return [(str, middleWidth)]
    }

    var keys = [stringToCharacterStrings("`1234567890-=") + specialKey("BS", 6),
                specialKey("TAB", 6) + stringToCharacterStrings("QWERTYUIOP[]\\")]
    keys += [specialKey("CAPS", 7) + stringToCharacterStrings("ASDFGHJKL;'") + specialKey("ENTER", 6),
                specialKey("SHIFT", 9) + stringToCharacterStrings("ZXCVBNM,./") + specialKey("SHIFT", 9)]

    var output = ""
    for r in 0 ..< keys.count {
        let row = keys[r]
        var rowKeys = [[String]]()
        for i in 0 ..< row.count {
            let elem = row[i]
            let key = createKey(elem.0, elem.1, (i>0 ? 1 : 0))
            rowKeys.append(key)
        }

        for y in 0 ..< 4 {
            if r > 0 || y > 0 {
                output += "\n"
            }

            for key in rowKeys {
                output += key[y]
            }
        }
    }

    print(output)
}

createKeyboard()

at least it's not applescript

Now I've got to do Java don't I

SOGL V0.12, 131 128 127 bytes (competing?)
⅟]y‘9Δø∑"`ŗ0-=”čΚ"TAB  ”QWERTYUIOP[]\”č+"oF«▒Β²‘⁷Ο‘ASDFGHJKL;'”čΚ+"_№K³‘ZXCVBNM,./”č⁴++¹{"^μ³‘č;{U;"_||/”┼;{"_ŗ__”┼}"Ο  ψ¦℮³‘┼}O

SOGL does have the 2*2/ and 2/2* quirks, but those feel too much like a built-in for this challenge.
Try it Here!
...‘               push "BS   "                                            ["BS   "]
    9Δ             push an array of numbers up to 9                        ["BS   ", [1,2,3,4,5,6,7,8,9]]
      ø∑           join into a single string (without ø it results to 45)  ["BS   ", "123456789"]
        "`ŗ0-=”    push "`ŗ0-=" with ŗ replaced with the digits            ["BS   ", "`1234567890-="]
               č   chop that into an array of characters                   ["BS   ", ["`","1","2","3","4","5","6","7","8","9","0","-","="]]
                Κ  add the first "BS   " to the end of the array           [["BS   ","`","1","2","3","4","5","6","7","8","9","0","-","="]]

"TAB  ”            push "TAB  "                  [[..], "TAB  "]
       Q..P[]\”    push "QWERTYUIOP[]\"          [[..], "TAB  ", "QWERTYUIOP[]\"]
               č   chop that                     [[..], "TAB  ", ["Q","W","E","R","T","Y","U","I","O","P","[","]","\"]]
                +  prepend to the array "TAB  "  [[..], ["TAB  ","Q","W","E","R","T","Y","U","I","O","P","[","]","\"]]

"...‘             push "caps  "                       [.. , "caps  "]
     ⁷Ο‘          push "enter"                        [.. , "caps  ", "enter"]
        AL;'”     push "ASDFGHJKL;'"                  [.. , "caps  ", "enter", "ASDFGHJKL;'"]
             č    chop that                           [.. , "caps  ", "enter", ["A","S","D","F","G","H","J","K","L",";","'"]]
              Κ   append "enter" to the end of array  [.. , "caps  ", ["A","S","D","F","G","H","J","K","L",";","'","enter"]]
               +  prepend "caps  " to the array       [.. , ["caps  ","A","S","D","F","G","H","J","K","L",";","'","enter"]]

"..‘             push "shift   "                [..., "shift   "]
    ZM,./”       push "ZXCVBNM,./"              [..., "shift   ", "ZXCVBNM,./"]
          č      chop it                        [..., "shift   ", ["Z","X","C","V","B","N","M",",",".","/"]]
           ⁴     duplicate the shift            [..., "shift   ", ["Z","X","C","V","B","N","M",",",".","/"], "shift   "]
            ++   append and prepend the shifts  [..., ["shift   ","Z","X","C","V","B","N","M",",",".","/","shift   "]]
              ¹  get all the arrays into one big array
result: [[["BS   ","`","1","2","3","4","5","6","7","8","9","0","-","="], ["TAB  ","Q","W","E","R","T","Y","U","I","O","P","[","]","\"], ["caps  ","A","S","D","F","G","H","J","K","L",";","'","enter"], ["shift   ","Z","X","C","V","B","N","M",",",".","/","shift   "]]]
 - a 2D array of the keyboard characters

{                                    for each array in the array do
 "...‘                                 push " |||"
      č                                chop to chars
       ;                               get the main array ontop
        {                        }     for each string in the array
         U                               uppercase it (before lowercase was used for better compression)
          ;                              get the chopped array ontop
           "_||/”                        push "_||/"
                 ┼                       append vertically
                  ;                      get the string ontop
                   {       }             for each char in the string do
                    "_ŗ__”                 push "_ŗ__"
                          ┼                append vertically
                            "..‘         push "    _||\ |||"
                                ┼        append vertically-then horizontally
                                  O    output that in a newline

Wow, this is super impressive! No one's managed to beat me on this one yet, so good job! I might try to get mine just a little shorter, but no promises. ;)

@dzamia even though it's competing now, I accepted the answer back when this wasn't. Should I switch answers?

@MagicOctopusUrn IMO it's up to you. There's a reason it's suggested to not accept answers :p

It's suggested to not accept answers? Oh... fair enough. Then I guess I'll stop accepting answers in the future and leave stuff as-is.

@MagicOctopusUrn okay, maybe not accepting answers is a bit controversial, but still, a major positive

Python 2, 394 388 380 bytes
k=[4]*13+[8],[8]+[4]*13,[9]+[4]*11+[8],[11]+[4]*10+[11];m='`1234567890-=*','*QWERTYUIOP[]*',"*ASDFGHJKL;'*",'*ZXCVBNM,./*';c,d,e,n,u=0,'','|','\n','_'
for a in 0,1,2,3:
 f=s=t=o='';x=0
 for y in k[a]:g=y-2;f+=' '+u*y;s+=e*2+m[a][x].replace('*','%s')+' |';t+=e*2+u*g+e;o+='|/'+u*g+'\\';x+=1
 d+=f+n+s+e+n+t+e+n+o+e+n
l='SHIFT   ';print d%('BS   ','TAB  ','\\','CAPS  ','ENTER',l,l)

Just builds a big string representing the whole keyboard, replaces * with %s for the special keys then uses string formatting to update the specials.
Edit
Now has a trailing newline at the end of the output but I don't see anywhere that's not allowed.
Try it online!

I think you should remove the output , as it does not add anything relevant.

@sergiol - good point. Wasn't aware to TIO at the time of posting. Now updated.

m4, 456
changequote({,})define(d,{define($@)})d(p,{patsubst($@)})d(a,{{_}p({$1},.,_)_ })d(b,{|$1||})d(c,{|p({$1},.,_)||})d(e,{/p({$1},.,_)\|})d(f,{ifelse(len({$2}),0,,{indir({$1},{$2})f({$1},shift(shift($@)))})})d(g,{ f({a},$@)
|f({b},$@)
|f({c},$@)
|f({e},$@)
})g(` ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,0 ,- ,= ,BS    )g(TAB   ,Q ,W ,E ,R ,T ,Y ,U ,I ,O ,P ,[ ,] ,\ )g(CAPS   ,A ,S ,D ,F ,G ,H ,J ,K ,L ,; ,' ,ENTER )g(SHIFT    ,Z ,X ,C ,V ,B ,N ,M ,{,} ,. ,/ ,SHIFT    )

Ungolfed:
changequote({,})dnl
define(key1, {{_}patsubst({$1}, ., _)_ })dnl _______
define(key2, {|$1||})dnl                     |TAB  ||
define(key3, {|patsubst({$1}, ., _)||})dnl   |_____||
define(key4, {/patsubst({$1}, ., _)\|})dnl   /_____\|
define(rkey, {dnl
ifelse(dnl
len({$2}), 0, ,dnl terminate on empty argument
{dnl
indir({$1}, {$2})dnl
rkey({$1}, shift(shift($@)))dnl
}dnl
)dnl
})dnl
define(row, {dnl
 rkey({key1}, $@)
|rkey({key2}, $@)
|rkey({key3}, $@)
|rkey({key4}, $@)dnl
})dnl
row(` ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,0 ,- ,= ,BS    )
row(TAB   ,Q ,W ,E ,R ,T ,Y ,U ,I ,O ,P ,[ ,] ,\ )
row(CAPS   ,A ,S ,D ,F ,G ,H ,J ,K ,L ,; ,' ,ENTER )
row(SHIFT    ,Z ,X ,C ,V ,B ,N ,M ,{,} ,. ,/ ,SHIFT    )

(This is actually the first time I'm both code-golfing and giving m4 a try.)

Not bad for a first answer. Welcome to the site! :)

C#, 376 bytes (when in one line)

var s="";foreach(var r in@"`|1|2|3|4|5|6|7|8|9|0|-|=|BS   ~TAB  |Q|W|E|R|T|Y|U|I|O|P|[|]|\~CAPS  |A|S|D|F|G|H|J|K|L|;|'|ENTER~SHIFT   |Z|X|C|V|B|N|M|,|.|/|SHIFT   ".Split('~'))for(int i=0,l;i<4;i++){foreach(var k in r.Split('|')){l=k.Length+1;var u=new string('_',l);s+=i<1?" "+u+"__":i<2?"||"+k.PadRight(l)+"|":i<3?"||"+u+"|":"|/"+u+@"\";}s+=i>0?"|\n":"\n";}Console.Write(s);

This is based entirely on Klinger's C# answer.  I don't have enough rep to comment on his answer, otherwise I would.
I was able to slim down Klinger's code by 5 bytes, by modifying the initial foreach loop, and removing extraneous brackets.
var s="";
foreach(var r in@"`|1|2|3|4|5|6|7|8|9|0|-|=|BS   ~TAB  |Q|W|E|R|T|Y|U|I|O|P|[|]|\~CAPS  |A|S|D|F|G|H|J|K|L|;|'|ENTER~SHIFT   |Z|X|C|V|B|N|M|,|.|/|SHIFT   ".Split('~'))
for(int i=0,l;i<4;i++)
{
foreach(var k in r.Split('|'))
{
l=k.Length+1;
var u=new string('_',l);
s+=i<1?" "+u+"__"
:i<2
?"||"+k.PadRight(l)+"|"
:i<3
?"||"+u+"|"
:"|/"+u+@"\";
}
s+=i>0?"|\n":"\n";
}
Console.Write(s);

Good one @Bence Joful. With your suggestion I would be able to get it to 367. I have not incorporated to the current answer.

Could not resist. Your suggestion + some additional minor changes brings it to 361 (or 358 with string interpolation).

@Klinger - please do use my tweaks!  I was inspired to play around with it based on your work.  I learned something about initialization in the process.

Could you include the one line program? You won't exactly lose much readability over the current one

@Cyoce, you got it, thanks for the suggestion.  Though at this point, Klinger has already posted a new, smaller version incorporating these changes.

stacked, 228 bytes
Try it here!
[,{a:a size@n(' __' '_'n 1+:@k*LF'||'a' ' '|'LF'||' '_'k*:@o'|'LF'|/'o'\')sum}"!$hcat#/!' |||'hcat out]@:p$chars@:c'`1234567890-='c'BS   'p'TAB  ' 'QWERTYUIOP[]\'c p'CAPS  ' 'ASDFGHJKL;'''c,'ENTER'p'SHIFT   ':@q'ZXCVBNM,./'c,q p

Or, slightly more readable:
{a:a size@n(' __' '_'n 1+:@k*LF'||'a' ' '|'LF'||' '_'k*'|'LF'|/' '_'k*'\')sum}"@:m
[,m$hcat#/!' |||'hcat out]@:p
'`1234567890-='chars'BS   'p
'TAB  ' 'QWERTYUIOP[]\'chars p
'CAPS  ' 'ASDFGHJKL;'''chars,'ENTER'p
'SHIFT   ':@q'ZXCVBNM,./'chars,q p

This works by defining a function p that makes a key, then hcating multiple keys.

Haskell, 255
import Data.List;a#b=a++[b];e=" |||";s=map(:" ");k x=[e,"_||/"]++['_':c:"__"|c<-x]#"_||\\";t="SHIFT    ";main=mapM_ putStrLn$transpose.(#e).(k=<<)=<<[s"`1234567890-="#"BS    ","TAB   ":s"QWERTYUIOP[]\\","CAPS   ":s"ASDFGHJKL;'"#"ENTER ",t:s"ZXCVBNM,./"#t]

In retrospect, similar in concept to this Haskell answer, but producing the ASCII keyboard, and with slightly different golfing.
Formatted and renamed:
import Data.List

main :: IO ()
main = mapM_ putStrLn
  $ concatMap (transpose . (`append` end) . concatMap key)
  [ split "`1234567890-=" `append` "BS    "
  , "TAB   " : split "QWERTYUIOP[]\\"
  , "CAPS   " : split "ASDFGHJKL;'" `append` "ENTER "
  , shift : split "ZXCVBNM,./" `append` shift
  ]

key :: String -> [String]
key x
  = [end, "_||/"]
  ++ ['_' : c : "__" | c <- x]
  `append` "_||\\"

append :: [a] -> a -> [a]
append a b = a ++ [b]

split :: [Char] -> [String]
split = map (: " ")

end :: String
end = " |||"

shift :: String
shift = "SHIFT    "

tcl, 368
As counted by http://textmechanic.com/text-tools/basic-text-tools/count-characters-words-lines/ with the "Count line breaks as spaces." set to on, it occupies 505 496 452 451 439 403 401 396 391 388 385 384 382 379 378 377 369 368
proc N x {split $x @}
proc M a\ b {string map $a $b}
regsub -all \[^@|] [set b [M [N {||||@|||@$@BS   @%@TAB  @&@CAPS @? @ENTER  @*@SHIFT   }] [regsub -all {[^@]} "`1234567890-=$@%QWERTYUIOP\[\]\\@&ASDFGHJKL;'?@*ZXCVBNM,./*" {||& ||}]]] _ f
lmap x [N [M {\\ _ / _ | \ } [set g [M {||_ |/_ _|| _\\|} [M {||| \\|/} $f]]]]] y [N $b] z [N $f] w [N $g] {puts "$x
$y
$z
$w"}

Demo: http://rextester.com/live/NTVAV88033
The ungolf:
Live cooperation on http://rextester.com/live/UDO43692
regsub -all {(\S)} "`1234567890-=←\n%QWERTYUIOP\[\]\\\n⇩ASDFGHJKL;'↵\n⇧ZXCVBNM,./⇧" {||\1 ||} b
set b [string map {|||| |||  ← "BS   " % "TAB  " ⇩ "CAPS  " ↵ "ENTER" ⇧ "SHIFT   "} $b]

regsub -all {[^\n|]} $b _ f

set g [string map {||| \\|/} $f]
set g [string map {||_ |/_  _|| _\\|} $g]
set h [string map {\\ _ / _ | " "} $g]

set H [split $h \n]
set B [split $b \n]
set F [split $f \n]
set G [split $g \n]

lmap x $H y $B z $F w $G {
puts $x
puts $y
puts $z
puts $w
}

Anyone is free and welcome to improve my version on live cooperation sites, but please: do not edit my original answer here; just say you've edited in the comments and people will visit the links.
UPDATE 1: Replaced for by foreach, because latter produces shorter code
UPDATE 2: Replaced foreach by lmap, because latter produces shorter code
UPDATE 3: Shaved one char because I Replaced " " by \
UPDATE 4: In respect to first comment, I changed all the 1st line 2 byte Unicode place holder characters to 1 byte ASCII ones
UPDATE 5: multiple puts line made into only one
UPDATE 6: use directly split commands return values on the lmap call instead of using intermediate list variables
UPDATE 7: Quotes around ENTER were not needed
UPDATE 8: string map is long enough and repeated a number of times that it is worth to encapsulate it in a proc
UPDATE 9: split $x \n is long enough and repeated a number of times that it is worth to encapsulate it in a proc
UPDATE 10: On "replacement" string can use & instead of \1, because in this case both coincide; another consequence of this is it allows to get rid of ()on the "matching" string.
UPDATE 11: Use @ instead of \nas line separator for further use on split instructions. Although the "match" string lengthens from \S to [^@] it pays off , due to number of repetitions
UPDATE 12: Replaced the first regsub "match" string {[^@|]} by\[^@|] to shave one character off. Unfortunately, could not do the same to the second regsub, because the instruction is inside a pair of [] :(
UPDATE 13: Shaved two Enter characters by concentrating the lmap body with its own heading.
UPDATE 14: Used a call to the split based procedure N instead of a direct call to the string map based procedure N which allows to shorten by 3 characters
UPDATE 15: There was an unneeded   space character. Removed it to shave one char off.
UPDATE 16: set h can be embedded to get rid of $h, to shave one character off.
UPDATE 17: set h statement can really be shaved off.
UPDATE 18: puts argument changed from the ...\n...\n...\n... format to the
"...
...
...
..."

format.
Thanks to people that helped me to shorten it, especially evilotto and aspect of the tcl IRC channel!

Nice answer, and Welcome to the site! I made a minor edit to your post so that the byte count would appear in the header, I hope you don't mind. Just so you know, I think this is actually 469 bytes since some of those characters are multiple bytes in UTF-8. I don't know very much about tcl, does it use a custom encoding where those are one byte?

@DJMcMayhem I didn't know it was based byte count instead of character count but it is a non-problem because everything that is a one byte symbol still not used can be a placeholder and I still have many available.

@DJMcMayhem after my edit, the non-problem you reported has gone!

@DJMcMayhem Why the 401 on top had a yellow background for some time?

tcl, 369
Initially based in tcl's sergiol version.
(Note that many left spaces are part of tcl's "nature")
lmap z {S R M} w {set "regsub -all" "string map"} {interp alias {} $z {} {*}$w};lmap x {"`1234567890-=¿BS   ¿" "¿TAB  ¿QWERTYUIOP\[\]\\" "¿CAPS  ¿ASDFGHJKL;'¿ENTER¿" "¿SHIFT   ¿ZXCVBNM,./¿SHIFT   ¿"} {S h [M {\\ _ / _ | \ } [S g [M {||_ |/_  _|| _\\|} [M {||| \\|/} [S f [R {[^\n|]} [S b [M {|||| |||} [R {¿(\S+\s*)¿|(.)} $x {||\1\2 ||}]]] _ ]]]]]];puts $h\n$b\n$f\n$g}

@muddyfish Edited and fixed. Thanks!

You can shorten more if you directly replace all foreach occurrences by lmap!

Tried to use your interp alias approach to shorten my version, but the shortest I could get when doing it was 398 :( http://rextester.com/live/NTVAV88033

My last try I got 395: lmap z {S R M N} w {set "regsub -all" "string map" split} {interp alias {} $z {} {*}$w};lmap y [N [S b [M [N {||||@|||@$@BS   @%@TAB  @&@CAPS @? @ENTER  @*@SHIFT   } @] [R {[^@]} "\1234567890-=$@%QWERTYUIOP[]\@&ASDFGHJKL;'?@ZXCVBNM,./" {||& ||}]]] @] z [N [S f [R {[^@|]} $b ]] @] w [N [S g [M {|| |/_  _|| _\|} [M {||| \|/} $f]]] @] x [N [M {\ _ / _ | \ } $g] @] {puts $x\n$y\n$z\n$w}`

You can save one char if you removed an unneeded space like in my last update!

aspect has created a new paste at http://paste.tclers.tk/4068 "golf in 358"

BTW, relatively to my last comment, if I test it on www.rextester.com I can remove the package require zlib line and things still run well!

And shorter using puts [zlib gu [binary d base64.That's 328 !.

— Em português e en castellano: EMPATE!

I've got you beaten by me!

1 byte less: https://tio.run/##TZBtT8IwFIW/71ecNEtEFCb4HuMHQBBUENf5us45DAySSQgbgdD2ty3ZH5tdg4lNbtOc89zTm5t8R3ke/QQLbMEpbPQl1uDxOAFZjsN4NUIliCICEifL2TyEQokEn82T8XKBIJoFMbiEuS1uXpbmWho6bwNOvmr145PTs/OLy6PKdZY2KYAsVWFZ6jSaxfvptW0778@9xyFzmceY9lqNIS3MBr3p3Hbv7h@u9rK0PXDa9q6ZdnsdR2d9vLVemoP@YdX6rxYTUkzh9sEZgw9LlQCDhEsRal0IJVk@4AsBnzEhd7LimLA0OYFrg7ufbC48LYz@GAFVUttZWmL0gMXl/SwVpeq@WsamYFiN1RUlPc9Tv3v6GItVEoOYU8McGebEMEMi8/wX

C (gcc), 378 342 330 327 bytes
-10 -3 bytes thanks to ceilingcat.
A first stab at it. The repeated g()'s suggests room for improvement.
Edit: There we go.
char*k[]={"eZXCVBNM,./e","cASDFGHJKL;'d","bQWERTYUIOP[]\\","`1234567890-=a","BS","TAB","CAPS","ENTER","SHIFT"},*s;f(w,i,j){for(i=16;i--;puts(""))for(s=k[i/4],j=i%4;*s;printf("%s%s%-*.*s%.2s",L" |"+(s++-k[i/4]?2:j<3),L"/||"+j,w,i&2?j^3?w>2?w:1:w+2:w,j^2?"___________":w>2?k[*s-93]:s,"\\||||| "+j*2))w=*s>96?"FFGFI"[*s-97]-64:2;}

Try it online!

Python 2, 672 bytes
Using a compressed zlib string:
print 'x\x9c\xad\xd3\xb9\x0e\x82@\x10\x80\xe1\x9e\xa7\xa0\xb3\xf1\xbe\x8d\xb1\x00\xbc\x0f<\xc0\x1b\xb3>\xc8<\xbc\xfc\x8bf\x8d\xed8\xc5\x17\x9a\xddd\xfe,\xbe\xc9\xc7\xd7b?<\x91\xa7/"\rhB\x0b\xda\xd0\x81.\xf4\xa0\x0f\x03\xa8C\x05F\x10&~>"\xf9]\xc6\x88\x16\x86\xbbj\xc6dZ\x98L<\xb7\xae\x9a|\xc74\x08\xed\xba\xb2\x873L\xe0\x00)\\\xe1\x08\x0b\xd8\xc2\x0e\xee\xf0\x80\xec\xd3\xabXW\x1d\xces\xeb\xaa\xc3\xb9^\x7fy_Q\xb0K\x8a`\x01$0\x86)\xcc`\x0eKX\xc1\x1a\x86P\xb2u\xe3tr\xf8\xee\xf5\xaf\xf7\xa5\x0e\xf6\xfb\xbet\xb1\xde\xbd\x92\xf9b\x9a\x16\x7f\x94\xdc\xe0\x02\x11\x9c\xec\xef\x061l\xa0\x0cU\xa8\xd9\xbc\xee\xb4\xeb\xa5\x8a\xf5\xd3K\x15\xcb\x9e~\x01r\xfc\xb9\xee'.decode('zlib')

That's 672 bytes, not 232 bytes.

Explain further, I did not understand you. @nneonneo

If you paste your code into a file, that file will be 672 bytes long. You appear to have counted your code with len("print 'x\x9c...'") which will unescape the \xs, resulting in an incorrect byte count. You could obtain a correct count by counting with len(r"print 'x\x9c...'") but the easiest solution, as always, is to see what your text editor or filesystem says.

Mathematica 323 bytes
Uncompress@"1:eJyt00luwjAUgGE2vUdYsWGeEeoiUGYIEKcTTWXEBXqBd3jy26CUYWe/xads8iT/sounv1gFL4VCoLNxxnyk9UZT5BiISAOa0II2dKALPejDAOpQgVcYqSAbEbtOa3GFuayraZ2mPmWyL5bnIZyxR0/CkQkhe/iECcSQwDe8wwK2sIMf+IV/IW0H56LXkJej+016E9LXlRyHO2VLhqDgDaYwgzksYQVrGELJZI+SSXxX0uOV9Jry2Y10q5iHVPPFNLGvUw7wBWP4ME8XIthAGapQM93zv29COlV8DOkrol10BmvF28U="

Boring and uncreative. The string is just the output of the built-in Compress command applied to the desired output.

@Downvoted please indicate what is wrong with my program.

Powershell, 249 242 bytes
"``1234567890-=Bs
Tab  QWERTYUIOP[]\
Caps  ASDFGHJKL;'Enter
Shift   ZXCVBNM,./Shift   "-split'
'|%{($u=($r=,''+($_-csplit'(.[a-z ]*)'-ne''|% t*per)+'')-replace'.','_')-join'__ _'
$r-join' |||'
$u-join'_|||'
$u-join'_\|/'}|%{-join$_[2..76]}

Ungolfed & Explained
The middot · uses instead spaces to to clarify the source string.
"``1234567890-=Bs···
Tab··QWERTYUIOP[]\
Caps··ASDFGHJKL;'Enter
Shift···ZXCVBNM,./Shift···"-split"`n"|%{        # split the string with rows by new line
$r=,''+($_-csplit'(.[a-z ]*)'-ne''|% t*per)+''  # split each row by key labels (any char plus small letters or spaces), 't*per' is shortcut for toUpper method
$u=$r-replace'.','_'                            # replace any char to _ to take an upper
$u-join'__ _'                                   # join labels and push 4 strings to pipe
$r-join' |||'
$u-join'_|||'
$u-join'_\|/'
}|%{
    -join$_[2..76]                              # return substring for each string
}

# $r =
# ["","`","1","2","3","4","5","6","7","8","9","0","-","=","BS   ",""]
# ["","TAB  ","Q","W","E","R","T","Y","U","I","O","P","[","]","\",""]
# ["","CAPS  ","A","S","D","F","G","H","J","K","L",";","'","ENTER",""]
# ["","SHIFT   ","Z","X","C","V","B","N","M",",",".","/","SHIFT   ",""]
# $u =
# ["","_","_","_","_","_","_","_","_","_","_","_","_","_","_____",""]
# ["","_____","_","_","_","_","_","_","_","_","_","_","_","_","_",""]
# ["","______","_","_","_","_","_","_","_","_","_","_","_","_____",""]
# ["","________","_","_","_","_","_","_","_","_","_","_","________",""]
# before substring:
# __ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ________ _
#  |||` |||1 |||2 |||3 |||4 |||5 |||6 |||7 |||8 |||9 |||0 |||- |||= |||BS    |||
# _|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||______|||
# _\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/______\|/
# __ ________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ _
#  |||TAB   |||Q |||W |||E |||R |||T |||Y |||U |||I |||O |||P |||[ |||] |||\ |||
# _|||______|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||
# _\|/______\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/
# __ _________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ________ _
#  |||CAPS   |||A |||S |||D |||F |||G |||H |||J |||K |||L |||; |||' |||ENTER |||
# _|||_______|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||______|||
# _\|/_______\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/______\|/
# __ ___________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___________ _
#  |||SHIFT    |||Z |||X |||C |||V |||B |||N |||M |||, |||. |||/ |||SHIFT    |||
# _|||_________|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||_________|||
# _\|/_________\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/_________\|/
# final output:
#  ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ________
# ||` |||1 |||2 |||3 |||4 |||5 |||6 |||7 |||8 |||9 |||0 |||- |||= |||BS    ||
# ||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||______||
# |/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/______\|
#  ________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
# ||TAB   |||Q |||W |||E |||R |||T |||Y |||U |||I |||O |||P |||[ |||] |||\ ||
# ||______|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__||
# |/______\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|
#  _________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ________
# ||CAPS   |||A |||S |||D |||F |||G |||H |||J |||K |||L |||; |||' |||ENTER ||
# ||_______|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||______||
# |/_______\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/______\|
#  ___________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___________
# ||SHIFT    |||Z |||X |||C |||V |||B |||N |||M |||, |||. |||/ |||SHIFT    ||
# ||_________|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||_________||
# |/_________\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/_________\|

Extra: keyboard with a space bar & right aligned labels, 278 bytes
I've added a couple of bytes to the regular expression to handle the space bar (old regexp (.[a-z ]*), new one ~|(.[a-z ]*)). That's one small step for the regexp, one giant leap for the solution: you can now display space bar and key labels aligned to the right (see SHIFT, CTRL and BS on the right side of the keyboard).
"``1234567890-=~   bs
Tab  QWERTYUIOP[]\
Caps  ASDFGHJKL;'Enter
Shift   ZXCVBNM,./~   shift
Ctrl  Alt ~$(' '*34)Alt ~  ctrl"-split'
'|%{($u=($r=,''+($_-csplit'~|(.[a-z ]*)'-ne''|% t*per)+'')-replace'.','_')-join'__ _'
$r-join' |||'
$u-join'_|||'
$u-join'_\|/'}|%{-join$_[2..76]}

Output:
 ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ________
||` |||1 |||2 |||3 |||4 |||5 |||6 |||7 |||8 |||9 |||0 |||- |||= |||   BS ||
||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||______||
|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/______\|
 ________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
||TAB   |||Q |||W |||E |||R |||T |||Y |||U |||I |||O |||P |||[ |||] |||\ ||
||______|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__||
|/______\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|
 _________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ________
||CAPS   |||A |||S |||D |||F |||G |||H |||J |||K |||L |||; |||' |||ENTER ||
||_______|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||______||
|/_______\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/______\|
 ___________ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___________
||SHIFT    |||Z |||X |||C |||V |||B |||N |||M |||, |||. |||/ |||   SHIFT ||
||_________|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||_________||
|/_________\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/_________\|
 _________ _______ _____________________________________ _______ _________
||CTRL   |||ALT  |||                                   |||ALT  |||  CTRL ||
||_______|||_____|||___________________________________|||_____|||_______||
|/_______\|/_____\|/___________________________________\|/_____\|/_______\|

///, 360 bytes
/f/!!//e/SHIFT   //d/\/\///c/ "db/
\|\|da/\\\|d@/#####d?/__d>/?\\\\a
c"d</aa
ad:/fffff!d&/ccccd%/ aaad#/?aaa?aaad"/??d!/?\\\\a\\\d&&&cc"b`%1%2%3%4%5%6%7%8%9%0%-%=%BS    <|@#?|||"?<\/:f">&&&cbTAB  %Q%W%E%R%T%Y%U%I%O%P%[%]%\\ <|"@#?|||?<\/":f>_&&&"bCAPS  %A%S%D%F%G%H%J%K%L%;%'%ENTER <|"_@#"?<\/"_:!">?_&&ccc"?_be%Z%X%C%V%B%N%M%,%.%\/%e <|""_|||@""_<\/"?_:""_\a

Try it online!

Wolfram Language (Mathematica), 293 bytes
c=##&@@(#|2&/@Characters@#)&
r=StringRiffle
p=StringPadRight
Print/@{j=p["",#2,"_"]&@@@#;(" __"<>#&/@j)<>" ",r[p@@@#,i={l="||","|||",l}],j~r~i,j~r~{"|/","\|/","\|"}}&/@{{c@"`1234567890-=","BS"|6},{"TAB"|6,c@"QWERTYUIOP[]\\"},{"CAPS"|7,c@"ASDFGHJKL;'","ENTER"|6},{h="SHIFT"|9,c@"ZXCVBNM,./",h}}

Try it online!
Relatively straightforward: encodes rows of keys as lists of (key name)|(key width)
c=##&@@(#|2&/@Characters@#)&    (*converts a string into (key)|2 s*)
r=StringRiffle
p=StringPadRight
 Print/@
  {j=p["",#2,"_"]&@@@#;
   (" __"<>#&/@j)<>" ",         (*top of the keys*)
   r[p@@@#,i={l="||","|||",l}], (*key names*)
   j~r~i,                       (*space under key names*)
   j~r~{"|/","\|/","\|"}            (*bottom of the keys*)
  }
 &/@
{
 {c@"`1234567890-=","BS"|6},
 {"TAB"|6,c@"QWERTYUIOP[]\\"},
 {"CAPS"|7,c@"ASDFGHJKL;'","ENTER"|6},
 {h="SHIFT"|9,c@"ZXCVBNM,./",h}
}

Perl 5 -MList::Util=pairmap, 313 bytes
pairmap{$_=$b;s/\|{3}/|-|/g;y/-/_/c;y/-/ /;s/./ /;chop;say;$_=$b;for$r($a=~/./g){s/\| /|$r/}say;y/|/_/c;say;s,\|_,/_,g;s/_\|/_\\/g;say}"`1234567890-=",($;="||  |")x13 ."||BS    ||","QWERTYUIOP[]\\",'||TAB   |'.$;x13 .'|',"ASDFGHJKL;'","||CAPS   |".$;x11 ."||ENTER ||","ZXCVBNM,./",($s='||SHIFT    |').$;x10 ."$s|"

Try it online!

Duocentehexaquinquagesimal, 3036 bytes
2Ôδuδÿôtõ¡¼Θ%ËÅтƶ¬HMdÆawçùSÂvíÓ'θg/["»Åø≠]nj‘®‘M9~¾ÉQüÝ–*9ζž«Â,LIû–Δ#]¹Ð1…Ñº.β`¯‚…àñY!∞·ŽÉ%(˜‰«xη²‘0ÂγXd.©ÅsÉ÷^oM-â®ι1Nà;´¨©ĆāócÒ₄§βV³ƒÈ¯¾“›'Û$€`þeƒi÷тßäºиRèÞÆÈ½εîÀŠ\sÅtó"eíi∞Ëζ₄ÙÌÕ_T¸¨ÈcyÏa#3->*Ý#üWë€›xÜàεqqFн;ā/Ñ‡"›¡¯¨]1ê²Ú`4ÜFzSÖ'∊/¼C‰ÞÙ†m’I¿¸{"в]иùиå;ßf@qZÖÐAΓ¸(ÙŒ‹Lãßk₁мΩè¾˜∞›ÑVãh¾;œвM[Ò¾æo‰ØΘ≠º©8|Ω1ε₁ǝΓθBƶb·hI¢¤¬ƒ‚-¶{∍α³h¯rāp¯†\ε ðþMŽU0ì₁‰4ýpW0zΩðàöŠ«ÍÏúиÿ,¸āIôê©Bn×DÖr¹‡ZSèΘ½Òì©Éƒ…åÔнlù¸ð£ùd₁Žζº©ûq’|q£pØÕ]Ë"ê74Wáƶε¥¬²Ú¬Σ8ì-‹иI˜¹U±+2eδòwεN+’{ćžz]LF—çÝ«—à!}„@uÆŒòβ3A|à2ΣÚªǝö-®θ¾ºнÞJ¦āò2Ćη"¨₅¡™ʒΛ!¬ºEî¦ú¼œG‰7NšŒ|∊–o Òθ“7{sÀÿ≠üTÂ\B7™YXÔµ0g9þs-+6»βˆÛç₁[γãqª ór¸1ʒi¿¡|Ê¨γ>ÉhβεX’“)ÁÿEŠaÅb?b6?ª˜oÝk™iŒmúÞðΓćq3ê-ƒÅáHA‰βĆjC’ê÷á
¼₅sqŒ¢œYnà₁<X/£NÀ0
—3âô&-â˜›`ÑC¡8ˆQêв˜äeØæé^δ2çªÕšât₆ʒÈ0á8®LaE₆ûAH6”§hΩqzã§1!î+hé¨ËΛú$₂ž‡Ð[1ÄDÅ©ε,8êβ₅Õ=ëgo∞vƒkü¤Dà^ßˆšjAøÚ3y₄αÔλà,üœ÷Ü”J8*òõÉi«‹‚Gè½/ǝ»/ÔÏm™Šfα…0Íþ®¶ιh–:öŒΘÙ₃ÇÌä1ÀðΣøƵH}º‹Θв´ʒ8ÎĀ>¨ÑŒÉ–¯hÌóOjB½ǝ…mĀ+àæ©ˆh;¼ƒΛʒìFá®3°é°-¯BÓ†Ç;ÎÛÜ(õ§°ζλ%{₁º]p₂ãý₅Ì#γIkÊößKšŒ%òÕÿ}₁p Såíóì<tç›æÍγ₃¶éûÂgÍV…eм”àúδ∍н;нä.“0nAx1yñ_=N6,∊‘\f²3[0¦₄,ù“h¯—ÂˆÅGŒ©ŽðZAαÙ·¾d¾À¿.c{šθ¿þ^ƵL‚àÜλÜá¹¤ºнžQâˆÀZÿƶ^ÿ»Δ¶1ùñgôǝ‘ĆŒт<=‚2ΩÄ™2-∍øuœ.yʒ®Û©]©6Uт€2™ε9₃≠ÞÖ‡¾Ï›Tλçá¿Ä¾ˆÜ∊QλGÆ^¦∊ÁåʒÍ³₅i{Õ₅#Î>hεX:₁₅ćy)‰?Á₃ˆêW-Ï²št‚îVÖвç±’1ËδgŽΣ}™¼‡þ‚÷üéʒË¿a™
™}&…Γ¿ÞÎη{₆sǝê?¤ÃçYŒõ¹ θÇ±øÕuóP}ÝùΓJ^êsZ>Aθ^&ƒ€¹4∞Ã@Y:Ë©-Ð≠¯AY>{W©”vEδ¡)Ć`(šð¦fиlGè₆ËÍ›Ω)Ë%šŠÂ¸м$Ü{·Á€‹¿p˜}₆\₃…"þYôµ&ü7нŠθþ¢¿Mµ*î<ƶмíë°!A§HAÊΓ6ĆÈê¡áÒ¶z%Î~ΛλCGðƶç®«þdGó<áKÇγQ‘V₅‡Ω>7m²àNCÁešØ“ï´žhÂÞºK5cX”ÛÛß×çÄÍÒx8¤›ã_Λõиâ8]µāÝн`rmbιoyøΩÈÏlÐâĀ„žÂäƶ₁δJËè?αò2à₃‘QtƵ$ËÿøΓ›C∞;xÔŸæ-<òÜz-{XüŸ'\D$Š'
N³S∞zƒ1õÅ›èǝVXzÀ₄LÄàJŒþ²ëB½5÷вékΓrª´^vαι7ít5т—ßŸ3¥ï*2õāǝLÀ+<¸Ω\ǝ$θõ∍º4¥ëqтTbœÑ[ǝδ§ζ^ Äиéù;zĆ^l≠]fgGā’¤QÔγÚ»Bÿ‹jçÅº₆þÆ'ε!ôšAñāžWÔm>Œ¤‹βÖ5óŸιûãΣη~¢ãêù…J4‡üвúw\^θm₂5,εƒ#ìŠCεiØA∍óåQôø'+ΓnBÔasGÏãâcLb1¹‰Ñ³™ΔŽscâ_‘÷ºΓ_™4~$ÀZ€Þñ$ƒ¾°}©ùœ1ΘÌD>8Λö”ƶ†_QØŠ¤ƶæf¡ïŽMË›-™‰FŠàç„ì:eηÇ4ŸLÿ›qÄ.-&@¹ʒβÃËāO™EÌ¤Ø~{öË‚∊¢₃т‚Î+Ïú#þgíŒn—¸±тþKŠyàöòêvn*ªвβWþM*ĀćÝ1V¸₆Rl÷qª"×—ÆƵ×₂’–∊åÑÌΩ#À¿!ø¿ƶÖÝ´÷/¦ε₃õ=¶³^нŸт₂&,θ—¡ǝ›ÅpgµjKx.c£λá=yΩaõSÒ[ΘÅ)®…CàŸË&C4é;Γ5ÚεyÈœîì₄K₄Ú&œÍ}Ωuò£δËÍγ₂m#{õ½Öç&ò∍Ó8£3¨7x8Ć®v½%x±×d>gÑ®¼м{EyÆP´ûM)λX½dàÉλVsÖq¡y¹·JG₆*≠[Ø¶^åŸ¤€K₅Ãa¶L‚Θ[Bć\Ïвǝw3'“R{₃\Eв‘1M°e`мjXÔfó)¢ïkθλ—ÉíÉo|½$₁p&™SÓδÏŸ*òaI.G¯1h2ŒB#hÐα±ÔWmм‹Ü¯@0g»íÀ²YÉ»ç9#ƒš,ÏÓjZ>Dé∍óFì™ηÙ0ØÕSαLíÍù†w,Γº¡t¾ ¥ŒCƶ‰B₄´×0*ŽΩ¡8т€úâóŽ› ‡Yćyηe“–š∊y$α]Yà7·Ñ?.Xh÷±F$8éCçÕ{ÔΘñˆÃÆ)…íú—(Ñ4àîÛ³Ì"âαÐå≠™V‹{àéC9н\fgδÝƵþ <W∊!|Ñć0Óc80¨Θ¿«_.ø†x D‰$ÑùmÆEÕΣ†.1Þ¥]м @›´áóÛ4ζ∊:1@>BTB)ˆß,„ÜkÌ¨c‹4xê*∍Òγ„¾eø9w#¹ÁF·³zê¡5¦è¬H]‚LÙvÔxbr ¤ôghÐr÷ǝ₁Ÿo#Nθ·Ù‹δ¸ÔØè«Âζ´ 2DVʒbÁï∊ƶdŽ.TΘ[¿pÂk¾ç¦¨Î>ä³hF-¤íŒe“½jG‚\8Øλεн∍èÝmºj²©ë¬àê[@9aˆÓôMêuMт∊yH'Ƶå∊F¼Ê„ÚoγË¢k—EÝUŠG´ʒÁìÀ–-Ýäƶ
β³ζмZìòÊ4´JM3«.ÕCÇõ©îÊŒ³ïO·ÕdÎ†„dδ"~˜¶€Æ†*ÿµ~†ζZÁ¼n₃ĆĆe5J÷;ò¹ô¡ìÂgΣYÞ»…=LÏxM—û'‘Aā£Iε®l¢¯ðcºí3‚iªs,HN’MY½’ƶ₂ŠcÍ¸kþã9–ý)˜ŸÌ¤z)ß∞3œH‘š₆ðEQâ_h¦0ºΔyćм5¡‘L5Ü„|
\]«Ú±"C¾èтÚт<;5D)/ÕðýćÊÙÔζÓ\Çq+“QP={ÊÒLÂиæïÚ₅¥£s½´\¡+ΩΘt†‹ε¿÷Ú[˜ìµβ.]в}Y_zÚ¢#?ïyS™úºb—Δ9Q<u7₅∞ùº’ý™.>àfMÃoY#‰ºƶ¢ΣÐ¶»øÓüć®>мKV>«©λÜĆ›%в’¦lËeÃ>Xãιβ.öāDŠ!°xëÆδ\α≠Ä«
ýÒªƶи®2Iê!9Ûš4N³f!vεв0 kÑ”λƶÇy}ß¹λ©b¨₅tóć¿Òθ3/Zsd∍∍{γ¯þýO±t!²ΘuÀ™û˜Θ¸Ç‹ζfý8G[2ΘÚ¦5ÌŒ_тWŠûΘ`'Ô∊™á!o‘в+±øαíζb<мû3p/Ô}N<‚ƵΔ%Lýmºçêη;äsÞs&€y©°x~KŸƒиß₃·<ǝθнÖγΣвX©(ΓÀý¨ιú{αΣт‚¾hY´=†×¾ÚNΛÈâò¸+s)(ǝæúnW₅ʒôk!ǝïœá—ÍíæΣÅ7£ηxjÑÖœyÒE°¬JÌs¼ˆíÝÁA{Pi†áÖ₂₅´Æe†,·õ[FK'u§<₃MŸï·ÙÞ<ê0+($qΘxZ!â„ô+8á₆2_ʒöyîÒµÀ₂₁Zl¶…ǝ¤â$¤»"Hd’

Try it online! Absolutely horrendous and enormous. But hey, it's a challenge out of the way.

05AB1E, 133 bytes
‘`¯¤¼Á®‹‘#žVžhÀš"-=
 []\ ;'
 ,./
"#)øεεD.u≠iS]ε˜ε¶‘»²®‹ ‡Á‘#¾è:©4U1V.ui•Aε/•¾èÌU•6©›•¾èV¼}'_X×ðì®ðY×«D„||ìĆDŠŠ'_XÍ×:D'/1ǝ¨'\«)}øJεĆu,

Try it online.
Explanation:
Step 1: Push the nested list of keyboard keys:
‘`¯¤¼Á®‹‘     # Push dictionary string "` TAB CAPS SHIFT"
         #    # Split it on spaces: ["`","TAB","CAPS","SHIFT"]
žV            # Push builtin ["qwertyuiop","asdfghjkl","zxcvbnm"]
  žh          # Push builtin "0123456789"
    À         # Rotate it once to "1234567890"
     š        # Prepend it to the keyboard list
"-=\n []\ ;'\n ,./\n"
              # Push this string
 #            # Split it on spaces as well: ["-=\n", "[]\", ";'\n", ",./\n"]
)             # Wrap everything on the stack into a list
 ø            # Zip/transpose; swapping rows/columns: [["`","1234567890","-=\n"],
              #  ["TAB","qwertyuiop","[]\"],["CAPS","asdfghjkl",";'\n"],["SHIFT",
              #  "zxcvbnm",",./\n"]]
εε            # Nested map over each inner string:
  D           #   Duplicate the current string
   .u≠i       #   Pop the copy, and if it's NOT an uppercase string:
       S      #    Convert it to a list of characters
]             # Close the if-statement and nested maps
ε             # Map over each inner list:
 ˜            #  Flatten it to a list of strings
  ε           #  Map over each inner string:
   ¶          #   Push a newline character "\n"
    ‘»²®‹ ‡Á‘ #   Push dictionary string "BS SHIFT  ENTER"
     #        #   Split it on spaces: ["BS","SHIFT","","ENTER"]
      ¾è      #   0-based modular index counter variable `¾` into it
        :     #   Replace the potential newline with this indexed string

Try just step 1 online.
Step 2: Convert it to the ASCII keyboard and output it:
   ©          #   Store this new string in variable `®` (without popping)
   4U         #   (Re)set variable `X` to 4
   1V         #   (Re)set variable `Y` to 1
   .ui        #   Pop, and if string `®` is uppercase:
      •Aε/•   #    Push compressed integer 667699
       ¾è     #    Index counter variable `¾` into it
         Ì    #    Increase it by 2
          U   #    Overwrite variable `X` with this
      •6©›•   #    Push compressed integer 433144
       ¾è     #    Index counter variable `¾` into it
         V    #    Overwrite variable `Y` with this
      ¼       #    Increase the counter variable `¾` by 1
     }        #   Close the if-statement
   '_X×      '#   Push a string of `X` amount of "_"
       ðì     #   And prepend a space " "
   ®          #   Push string `®`
    ðY×«      #   Append `Y` amount of spaces
        D     #   Duplicate this "®<spaces>" string
        „||ì  #   Prepend "||" to this copy
            Ć #   Enclose it; append its own first character "|"
   D          #   Duplicate this "||®<spaces>|" string
    ŠŠ        #   Triple-swap twice, so the duplicated "®<spaces>" is at the top
      '_XÍ×  '#   Push a string with `X-2` amount of "_"
           :  #   Replace the "®<spaces>" with this "_"-string in the "||®<spaces>|"
              #   copy
   D          #   Duplicate this "||_{X-2}|" string
    '/1ǝ     '#   Insert an "/" at 0-based index 1
        ¨'\« '#   Remove the last character "|", and append "\" instead
   )          #   Wrap all four strings into a list
  }           #  Close the inner map
   ø          #  Zip/transpose; swapping rows/columns
    J         #  Join each inner list together to a single string
     ε        #  Map over each string:
      Ć       #   Enclose; append its own first character "|"
       u      #   Convert any lowercase (keyboard) letters to uppercase
        ,     #   Pop and output this string with trailing newline

See this 05AB1E tip of mine (sections How to use the dictionary? and How to compress large integers?) to understand why ‘`¯¤¼Á®‹‘ is "` TAB CAPS SHIFT"; ‘»²®‹ ‡Á‘ is "BS SHIFT  ENTER"; •Aε/• is 667699; and •6©›• is 433144.


text:
Roll cake phrases
Roll cakes are delicious sweets made with a layer of sponge cake, a layer of cream (or icecream), rolled as a spiral, see Wikipedia.
Your task is to get a non-empty phrase string from standard input, strip the spaces out, and roll it as a roll cake starting from the center in right to left in a counterclockwise direction, while the spaces starts at the bottom of the first phrase character, from the center left to right, as in the following example.
Please note that the phrase will be the layer of sponge cake and the cream layer will be represented as empty spaces.
Input: Lorem ipsum dolor sit amet, consectetu adipiscing elit, sed do eiusmod

Output with spaces ' ' represented as _

ilegnicsip
t________i
,_srolod_d
s_i____m_a
e_t_oL_u_u
d_a_r__s_t
d_m_emip_e
o_e______t
e_t,consec
i____
usmod

Test cases
Input: Lorem ipsum dolor sit amet, consectetu adipiscing elit, sed do eiusmod

Output:

ilegnicsip
t        i
, srolod d
s i    m a
e t oL u u
d a r  s t
d m emip e
o e      t
e t,consec
i
usmod

Input: Sandbox for Proposed Challenges

Output:

soporp
e    r
d aS o
c n  f
h dbox
a
llenges

Input: Cake

Output:

aC
k
e

Input: it

Output:

ti

Rules:

This is code-golf so the shortest code wins.
Standard loopholes are forbidden.

http://codegolf.stackexchange.com/questions/75446/draw-spiral-words Related.

Related and related

Python 2, 202 200 bytes
-2 bytes thanks to LevitatingLion
c=[];s=n=0
a=input().replace(' ','')
#Calculate the ammount of rotations
l=len(a)
while s<l:s=n*(1+n)/2;n+=1
#Add trailing spaces to not break the rolling
a+=' '*(s-l)
#Add a cream layer on top and a cake layer on bottom of the cake and roll 90 degrees
for i in range(1,n):c=[' '*i]+zip(*c[::-1])+[a[:i]];a=a[i:]
#Finish the rolling to match the pattern
exec~i%4*'c=zip(*c[::-1]);'
#Serve the cake
for i in c:print''.join(i)

You can drop the parentheses around exec: exec~i%4*'c=zip(*c[::-1]);'. This saves two bytes

Befunge, 260 250 bytes
"'"::00p09p19p35*::10p29pv
 v`*84:~<0p041p031p020p93<
v_0`!#v_^*!p04+g04:p03%4+g03:p02%4+g02:!%g04:+1pp01+%2-1g03p\3+<
>00g:: :09g\`8+0\p::19g`8+1\p20g1-2%+00p10g:::29g\`8+2\p::39g`8^
9g\-\v>29g:39g\->\:50p09g:1
$$1+\:!#@_1-55+,^>
,gg05<:+1\-1_:$#\^#

Try it online!
The basic idea is that we build up the spiral in the lower half of the playfield, keeping tracking of the min and max coordinates as we go along. Once all the input has been processed, we iterate over the range of coordinates and write out the content that was saved.
Detailed Explanation
Note that the dx and dy values are in the range 0 to 3, corresponding to the relative offsets -1, 0, 1, 0. Updating the direction is thus done by adding 1, modulo 4. Converting to a relative offset is done by subtracting 1, modulo 2.
"'"::00p09p19p      Set x, minx, and maxx to 39.
35*::10p29p39p      Set y, miny, and maxy to 15.
020p130p            Set dx to 0 (relative offset -1) and dy to 1 (relative offset 0).
140p                Set the segment length to 1.
0                   Set the index to 0 (on the stack).

                    -- The main input loop start here --
~                   Read a character from stdin.
:48*`_              If it's greater than 32 (i.e. not whitespace or EOL)...
  00g:              Get the current value of x and make a duplicate.
  ::09g\`8+0\p      If it's less than minx, update minx.
  ::19g`8+1\p       If it's greater than maxx, update maxx.
  20g1-2%           Calculate (dx-1)%2, which converts dx into the range -1 to 1.
  +00p              Add that to x and save (leaving the original x on the stack).
  10g:              Get the currrent value of y and make a duplicate.
  ::29g\`8+2\p      If it's less than miny, update miny.
  ::39g`8+3\p       If it's greater than maxy, update maxy.
  30g1-2%           Calculate (dy-1)%2, which converts dy into the range -1 to 1.
  +10p              Add that to y and save (leaving the original y on the stack).
  p                 Store the character we read at the original x,y coordinates.
  1+                Increment the index by 1.
  :40g%!            Mod that with the current segment len; if zero it's time to turn.
  :20g+4%20p        Add the turn condition to the dx value, thus turning if needed.
  :30g+4%30p        Similarly add the turn condition to the dy value.
  :40g+40p          Also add it to the segment length, so it gets longer every turn.
  !*                Multiply the index by !turn, so it's reset to zero on every turn.
  ^                 Repeat the loop, reading another character.
0`!#v_^             If the char <= 32, we test for EOF and repeat the loop if not.

>                   If it is EOF, we start the output routine.
29g                 Initialise the y coordinate with miny.
:39g\-              Calculate maxy - miny to use as the height countdown.

                    -- The outer output loop starts here --
\:50p               Swap y to the top and save in a temporary variable.
09g                 Initialise the x coordinate with minx.
:19g\-              Calculate maxx - miny to use as our width countdown.
\                   Swap x to the top of the stack.

                    -- The inner output loop starts here --
  :50g              Take a copy of x and the y save in the temporary variable.
  g,                Read the character at those coordinate and write to stdout.
  \:_               Swap the width countdown to the top of the stack and break if zero.
  1-                Otherwise decrement the width countdown.
  \1+               Swap the x value back to the top and increment it.
  <                 Repeat the inner loop.

$$                  Clear the width countdown and x value from the stack.
1+                  Increment the y value.
\                   Swap the height countdown to the top of the stack.
:¬#@_               If it's zero, exit.
1-                  Otherwise decrement it.
55+,                Output a line break.
^                   Repeat the outer loop.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

sort: votes


text:
2D Dungeon Crawler
Your program has to take a multi-lined string, like this:
#############
#           #
#     p     #
#           #
#############

p is the player and # is a block.
Now under that in the terminal should be an input line saying:
How do you want to move?

If the player types l he has to walk left when there isn't a block, else, when there is a block, he can't go through and doesn't move of course, now the output in the terminal has to be updated (and the previous output cleared/overwritten):
#############
#           #
#    p      #
#           #
#############

He can type l for left, r for right, u for up and d for down.
The input will always be multiline, but won't always be padded with spaces into a perfect rectangle. In addition, the hashes can be anywhere in the string, and won't always be connected to each other.  For example:
##  ##
#  #
## p
     #

is a valid dungeon. (note the lack of trailing spaces on each line)
If the player goes outside of the string, he doesn't have to be displayed. But if he comes back later, he must be displayed again.
And the boundaries of "outside" the string are the length(longest_line) by number_of_lines rectangle, so even if one line isn't padded with spaces on the right, that location isn't considered out of bounds. Example using the earlier dungeon:
##  ##
#  #p
##
     #

The second line didn't have a space where the p is now, but that doesn't matter.
Finally, your program must loop forever taking input.
Test cases
Test case 1:
####
# p#
#
####

How do you want to move?
d

####
#  #
# p
####

Test case 2:
####
  p#
   #
####

How do you want to move?
l

####
 p #
   #
####

How do you want to move?
d

####
   #
 p #
####

How do you want to move?
l

####
   #
p  #
####

How do you want to move?
l

####
   #
   #
####

How do you want to move?
r

####
   #
p  #
####

Of course, these aren't complete. Your code should loop forever and clear the screen between each output.
Your output is allowed to prompt for input as How do you want to move?\n<input> or How do you want to move?<input> (i.e. you don't need the input on a blank line), and you don't need a empty line between the final line of the dungeon and the prompt. (they can't be on the same line however)
Standard loopholes are disallowed !
This is code-golf, so the shortest code in bytes wins!

Is it acceptable if the input is a letter followed by enter? Also, I suggest getting rid of having to print that string, which doesn't seem to add anything to the challenge

I think this is re-openable, but my suggestion is that the input prompt (for l, r, u, or d) can be anything, not just "How do you want to move"? It doesn't really affect the answers except for golfyness.

@EasterlyIrk : I wouldnt agree. Because in this case, the golfers will have to think about how to compress the string to save bytes.

@user7185318 Keep this in mind, basically stick with 1 problem per challenge.  Compressing the string is a completely separate problem then making a dungeon crawler, and thus probably shouldn't be tacked on to that challenge.

Yes, it is. You're right.

Is it acceptable if the player is displayed when they are out of bounds, or do they need to disappear?

Yes, it is. More is always better tahn less.

What if a language can't clear the terminal?

No problem. Print out new 'Dungeon'

Haskell :: 799 703 bytes
Hi
This is my first code-golf submission.
It reads the initial grid from a text file.
Golfed:
    import Data.List
    x=maximum
    n=minimum
    r=filter
    s=length
    pad i r=r++(' '<$[1..(i-s r)])
    f l=let{w=x.map s$l;h=s l}in r((/=' ').snd).zip(flip(,)<$>[h,h-1..]<*>[1..w]).(pad w=<<)$l
    sh b=let{t=x.map(snd.fst)$b;d=n.map(snd.fst)$b;l=n.map(fst.fst)$b;sr _ []=[];sr i xb@((x,c):b)|x==i=c:sr(i+1)b|1>0=' ':sr(i+1)xb}in putStr.unlines.map(sr l.sort).map(\r->[(x,c)|((x,y),c)<-b,y==r])$[t,t-1..d]
    x!b|x`elem`map fst b=b|1>0=(x,'p'):r((/='p').snd)b
    b?i=let((x,y):_)=[x|(x,'p')<-b]in(case i of{'r'->(x+1,y);'l'->(x-1,y);'u'->(x,y+1);'d'->(x,y-1);_->(x,y)})!b
    m b=do{putStrLn"How do you want to move?";i<-getChar;putStr"\ESC[2J";let{d=b?i};sh d;m d}
    main = do{l<-readFile"s.txt";let{s=f.lines$l};sh s;m s}

An arguably more readable version:
import Data.List (sort)

data Board = Board [((Int,Int),Char)]

fromList l =
    let width = maximum . map length $ l
        height = length l
        coords = zip
            [(x,y) | y <- [height,height-1..1], x <- [1..width]]
            (concat (map (pad width ' ') l))
        clean = filter (\((_,_),c) -> c /= ' ') coords
    in Board clean

instance Show Board where
    show (Board xs) =
        let top = maximum . map (\((_,y),_) -> y) $ xs
            bottom = minimum . map (\((_,y),_) -> y) $ xs
            left = minimum . map (\((x,_),_) -> x) $ xs
            rows = map (\r -> [(x,c) | ((x,y),c) <- xs, y == r]) [top,top-1..bottom]
            showrow _ [] = []
            showrow i xxs@((x,c):xs)
                | x == i = c : showrow (i+1) xs
                | otherwise = ' ' : showrow (i+1) xxs
        in unlines . map ((showrow left) . sort) $ rows

insert z (Board zs) = Board (z:zs)

remove y (Board xs) = Board [(x,c) | (x,c) <- xs, x /= y]

at x (Board xs) =
    let match = [c | (x',c) <- xs, x' == x]
        ifempty [] = ' '
        ifempty (c:_) = c
    in ifempty match

move from@(x1,y1) to@(x2,y2) cur@(Board zs)
    | to `elem` [x | (x,c) <- zs] = cur
    | otherwise =
        let c = at from cur
        in insert (to,c) . remove from $ cur

find c (Board b) = [(x,y) | ((x,y),c') <- b, c' == c]

main = do
    startlist <- readFile "start.txt"
    let start = fromList . lines $ startlist
    print start
    maingameloop start

maingameloop board = do
    putStrLn "Where would you like to move?"
    inp <- getChar
    putStr "\ESC[2J"
    let newboard = movePlayer board inp
    print newboard
    maingameloop newboard

movePlayer board inp =
    let (cur@(x,y):[]) = find 'p' board
    in case inp of
        'r' -> move cur (x+1,y) board
        'l' -> move cur (x-1,y) board
        'u' -> move cur (x,y+1) board
        'd' -> move cur (x,y-1) board
        _ -> board

pad :: Int -> a -> [a] -> [a]
pad i c cs = cs ++ replicate (i - length cs) c

Welcome to the site! I believe reading from a text file is normally allowed. You may also want to check out our tips for golfing in haskell.

Thanks @RedwolfPrograms! I changed some code to make it even more horrible.

MATLAB, 268 247 246 bytes
Probably not competitive, but it was fun. Golfed version:
function f(s);d=char(split(s,'\n'));[y,x]=ind2sub(size(d),find(d=='p'));while 1;d
c=uint8(input('How do you want to move?','s'))-100;v=y+~c-(c==17);w=x+(c==14)-(c==8);try;d(y,x)=' ';end;try;if'#'==d(v,w);v=y;w=x;end;d(v,w)='p';end;y=v;x=w;clc;end

Readable version:
function f(s)
% Split the string on newlines and convert to a padded char array
d = char(split(s,'\n'));

% Get the initial indices of p
[y,x] = ind2sub(size(d),find(d=='p'));

% Loop forever
while 1
    % Implicitly display the dungeon
    d

    % Get the ASCII of the user input, minus 100 (saves a few bytes in
    % the comparisons)
    c=uint8(input('How do you want to move?','s'))-100;

    % Get the new y from the ASCII
    v = y+~c-(c==17);

    % Get the new x from the ASCII
    w = x+(c==14)-(c==8);

    % Clear the player from the dungeon if they are in it
    try
        d(y,x)=' ';
    end

    % Check if new position is a #, and revert to old position if so
    try
        if '#'==d(v,w)
            v=y;w=x;
        end
        d(v,w)='p';
    end
    % Update x and y
    y=v;
    x=w;

    % Clear the screen
    clc;
end

The try blocks are to prevent the function from crashing on out of bounds errors. I'm sure that two of them is overkill, but I can't golf it down any better than that.
It's worth noting that MATLAB will expand the array downwards and to the right, but the player will disappear when moving to an 'unexplored' area for the first time. For example, if you move outside the dungeon's current boundaries to the right by one space, you will disappear, but next turn MATLAB will expand the array to include the new column (or row, if you are moving downwards). '#'==d(y,x) saves a byte compared to d(y,x)=='#', since you don't need a space between if and '#'

Nice answer ! I hope this time not something very short wins, here the common languages should have a chance too, because the bigger the challenge, the better are java etc. :)

Coffee-script: 580 Bytes
I've squeezed everything I could out of this particular algorithm and my tired brain. I need a holiday.
C=console
e='length'
N=null
f=(S)->
    x=y=X=Y=N
    q=(c,v)->
        X=[x+c,N][+(-1<x+c<w)]
        Y=[y+v,N][+(-1<y+v<h)]
        try L[y+v][x+c]!='#'catch
            1
    r=(s)->
        if (X||Y)
            return
        L[y]=((t=L[y].split '')[x]=s)
        L[y]=t.join ''
    while 1
        L=S.split '\n'
        [h,w]=[L[e],L[0][e]]
        x=[X,x][+(x?)]
        y=[Y,y][+(y?)]
        for k in[0..h*w-1]
            if L[k//h][k%w]=='p'
                x=k%w
                y=k//h
        C.clear()
        C.log S
        r(' ')
        switch prompt("How do you want to move?")
            when'l'
                q(-1,0)&&x--
            when'r'
                q(1,0)&&x++
            when'u'
                q(0,-1)&&y--
            when'd'
                q(0,1)&&y++
        r('p')
        S=L.join '\n'

nice solution, Lord Ratte

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Generate a map for a roguelike
Today, we'll be generating a map for a roguelike RPG!
Example Map:
##########
####    F#
####    ##
##    C#C#
#     ## #
# C   #E #
####  #  #
#        #
#P       #
##########

# are walls, P is the player's starting location, F is the finish that must be reached, C are coins that can be collected, and E are enemies that can be fought.
Map specifications:

Height and Width should both be between 10 and 39, inclusive. Height does not have to equal width.
The maps borders should be filled in with walls.
P should be placed in the bottom left corner.
F should be placed in the top right corner.
There should be between 1 and 3 enemies.
There should be between 2 and 4 coins.
There should be some amount of walls in the middle. There should be a path to get from P to Every C, E, and F, keeping in mind that the player cannot move diagonally.
Every possible combination should have some chance of occurring.

Rules

Fewest byte program wins.
Your program should not take any input.
Your program may not exit with an error (non-fatal output is STDERR is ok, but we can't have our rogue-like crash after map generation!)
A single trailing newline is allowed and trailing space is allowed.
No other output is allowed.

It's roguelike, just fyi.

Can you clarify "every possible combination should have an equal chance of occurring"? Do you literally mean that all the valid maps (in particular, all maps where P can reach all the C/E/Fs) must occur with equal probability? If so, it seems that the only possible algorithm is to generate maps uniformly at random and then check that P can reach everything, discarding invalid maps until that happens.

Can you also clarify - "There should be some amount of walls in the middle", what if I place only 2 walls all the time?

@GregMartin I'll change it too "Every possible layout should have a chance of occurring", not necessarily an equal chance.

@GurupadMamadapur Then there will be valid layouts that your algorithm has no chance of generating.

I think "some chance of occurring" is an improvement! Given that, I think you can delete "(You may assume your language's built in random number generator is uniformly random)"

#######~#PCCEF#~####### is the smallest possible?

@carusocomputing It has to be at least 10 by 10.

The tricky part is paving a way from P to F ... I guess that should be random too? (That´s what every possible layout implies for me.)

@Titus Every possible layout means every possible configuration of #, P, F, C, and E that fits the spec. So yes, the path can't be constant.

What about unreachable empty squares surrounded by walls? Is it a valid layout or should they be avoided altogether? (In other words: should each empty square be reachable?)

@Arnauld no, empty squares can be unreachable and count as separate layouts.

And can the player pass through coins and enemies? (by collecting / killing them)

@arnauld yes, he can.

Perl, 293 bytes
-9 bytes thanks to @Dom Hastings
{$==7+rand 30;@r=$"=();@a=((C)x4,(E)x3,("#")x1369,(" ")x1369);for$i(0..7+rand 30){$r[$i][$_]=splice@a,rand@a,1for 0..$=}$r[0][$=]=F;$r[-1][0]=P;$_=$r=join$/,$v="#"x($=+=3),(map"#@$_#",@r),$v;1while$r=~s/F(.{$=})?[^#F]/F$1F/s||$r=~s/[^#F](.{$=})?F/F$1F/s;$r!~/[CEP]/&&/C.*C/s&&/E/?last:redo}say

Add -E flag to run it:
perl -E '{$==7+rand 30;@r=$"=();@a=((C)x4,(E)x3,("#")x1369,(" ")x1369);for$i(0..7+rand 30){$r[$i][$_]=splice@a,rand@a,1for 0..$=}$r[0][$=]=F;$r[-1][0]=P;$_=$r=join$/,$v="#"x($=+=3),(map"#@$_#",@r),$v;1while$r=~s/F(.{$=})?[^#F]/F$1F/s||$r=~s/[^#F](.{$=})?F/F$1F/s;$r!~/[CEP]/&&/C.*C/s&&/E/?last:redo}say'

However, it takes a long time to run, so I recommend using this version instead:
perl -E '{${$_}=8+rand 30for"=","%";@r=$"=();@a=((C)x4,(E)x3,("#")x($v=rand $=*$%),(" ")x($=*$%-$v));for$i(0..$%-1){$r[$i][$_]=splice@a,rand@a,1for 0..$=-1}$r[0][$=-1]=F;$r[$%-1][0]=P;$_=$r=join$/,$v="#"x($=+=2),(map"#@$_#",@r),$v;1while$r=~s/F(.{$=})?[^#F]/F$1F/s||$r=~s/[^#F](.{$=})?F/F$1F/s;$r!~/[CEP]/&&/C.*C/s&&/E/?last:redo}say'

Try it online!
Explanation

{                     # enter a block (which is used as a loop)
    {$==7+rand 30;                   # randomly select the width of the map -2
                                     # (-2 because we don't include the borders yet)
    @r=$"=();                        # reset @r, and set $" to undef
    @a=(                             # create a list of the character that can be on the board
     (C)x4,                          #  4 coins 'C'
     (E)x3,                          #  3 enemies 'E'
     ("#")x1369,                     #  37*37 '#'
     (" ")x1369);                    #  37*37 spaces
    for$i(0..7+rand 30)                # create the 2D map (7+rand 30 is the height, which is generated just now)
      for$_(0..$=-1){
        $r[$i][$_]=                    # index [$i][$_] receives ...
           splice@a,rand@a,1           # .. a random character from the list previously generated
                                       # (the character is then removed from the list thanks to 'splice')
      }
    }
    $r[0][$=]=F;                       # add the finish cell
    $r[-1][0]=P;                       # add the start cell
    $_=$r=                             # here we generate a string representation of the map
          join$/,                      # join the following elements with newlines
            $v="#"x($=+=3),            # a first line of # only
            (map"#@$_#",@r),           # add a # to the beginning and the end of each line
            $v;                        # the last line of #

    1while                # the following regex will replace every accessible cell with a F
       $r=~s/F(.{$=})?[^#F]/F$1F/s  # a cell on the right or the bottom of a F cell is replaced
         ||                         # or
       $r=~s/[^#F](.{$=})?F/F$1F/s; # a cell on the left or the top of a F cell is replaced
    $r!~/[CEP]/         # if there is no C, E or P on the map (meaning they were all accessible)
     && /C.*C/s         #  and there are at least 2 coins
     && /E/ ?           #  and 1 enemy
      last:             # the the map is valid, we exit the loop
      redo              # else, start over
}
say                     # and print the board

It takes a long time to run, because the list from which we randomly pick the characters to put on the board (@a) contains 1369 whitespaces and #, and only 4 coins and 3 enemies. So if the size of the width and height are small, there are a lot of spaces and # compared to the coin and the enemies, so it's quite likely that a random map won't be valid. That's why the "optimized" version is faster: the list from which we pick the characters is just a little bigger than the map (the list is @a=((C)x4,(E)x3,("#")x($v=rand $=*$%),($")x($=*$%-$v)) : a random number $v of # (inferior to the size of the map), and size of the map - $v whitespaces).

I don't really know perl, but looking at the syntax highlighting you appear to have an unmatched quote in ($")x$=**2);. Out maybe the highlighting doesn't work right and that's a feature. Also, whitespace can be unreachable.

@Pavel $" is a legit Perl variable, but the syntax highlighting doesn't know about it, that's why it looks like that. Ok, I'll delete the comment about unreachable spaces.

PHP, 422 417 415 309 373 369 364 361 bytes
function w($p){global$r,$h,$w;for($q=$p;$r[$q]<A;)for($r[$p=$q]=" ";($q=$p+(1-(2&$m=rand()))*($m&1?:$w))%$w%($w-1)<1|$q/$w%$h<1;);}$r=str_pad("",($w=rand(10,39))*$h=rand(10,39),"#");$r[$w*2-2]=F;w($p=$q=$w*(--$h-1)+1);$r[$p]=P;for($c=rand(2,4);$i<$c+rand(1,3);$p=rand($w,$h*$w))if($r[$p]<A&&$p%$w%($w-1)){w($p);$r[$p]=EC[$i++<$c];w($p);}echo chunk_split($r,$w);

operates on a string without linebreaks; digs random paths between the extras.  Run with -r.
Note: The paths are created by walking in random directions. The choice of direction for every step will mostly generate maps that are wide open; and the example map is very unlikely to appear; but it is possible.
breakdown
// aux function: randomly walk away from $p placing spaces, stop when a special is reached
function w($p)
{global$r,$h,$w;
    for($q=$p;
        $r[$q]<A;                               // while $q is not special
    )
        for($r[$p=$q]=" ";                          // 3. replace with space
            ($q=$p+(1-(2&$m=rand()))*($m&1?:$w))    // 1. pick random $q next to $p
            %$w%($w-1)<1|$q/$w%$h<1;                // 2. that is not on the borders
        );
}

// initialize map
$r=str_pad("",
    ($w=rand(10,39))*$h=rand(10,39) // random width and height
    ,"#");                          // fill with "#"
$r[$w*2-2]=F;                       // place Finish
w($p=$q=$w*(--$h-1)+1);             // build path from Player position to F
// $h is now height -1 !
$r[$p]=P;                           // place Player

// place Coins ans Enemies
for($c=rand(2,4);$i<$c+rand(1,3);   // while $i has not reached no. of coins+no. of enemies
    $p=rand($w,$h*$w))              // pick a random position
    if($r[$p]<A&&$p%$w%($w-1))      // that is neither special nor out of bounds
    {
        w($p);                      // build path from there to another special
        $r[$p]=EC[$i++<$c];         // place this special
        w($p);      // additional path to allow special in the middle of a dead end tunnel
    }

// insert linebreaks and print
echo chunk_split($r,$w);

In your explanation you're generating height and width to 37, not to 39.

@Pavel fixed; thanks for noticing

Outputs it's own source code when I tried in on Try it online

@Pavel you need to surround the code with <?php .... ?>

Ok, I did that, and I noticed that the walls are generated in regular rectangular chunks. It should be able to generate something like the example map. It also doesn't always generate Es.

•Every possible combination should have some chance of occurring, there should be 1 to 3 Es, and 2 to 4 Cs. You might want to read the spec.

@Pavel no need for <?php tags (and no need for a file) if you use php -nr 'code'

@Pavel now complete and everything fixed.

C# (Visual C# Interactive Compiler), 730 bytes
var R=new Random();for(;;){char P='P',C='C',E='E',Q='#';int w=R.Next(8,37),h=R.Next(8,37),H=h,t,g=99,W,i,j,r;string l,s,p=new string(Q,w+2);var m=new List<string>();for(;H>0;H--){l="";for(W=w;W>0;W--){r=R.Next(999);l+=r<3?C:r<6?E:r<g?Q:' ';}m.Add(l);}m[0]=m[0].Substring(0,w-1)+'F';m[h-1]=P+m[h-1].Substring(1);s=String.Join("#\n#",m);t=s.Split(E).Length-1;if(t<1||t>3)continue;t=s.Split(C).Length-1;if(t<2||t>4)continue;while(g>0){g--;for(i=0;i<h;i++)for(j=0;j<w;j++)if(m[i][j]!=Q&&m[i][j]!=P&&(i>0&&m[i-1][j]==P)||(i<h-1&&m[i+1][j]==P)||(j>0&&m[i][j-1]==P)||(j<w-1&&m[i][j+1]==P))m[i]=m[i].Substring(0,j)+P+m[i].Substring(j+1,w-j-1);}if(String.Join("",m).Split(E,C,'F').Length>1)continue;Console.Write(p+"\n#"+s+"#\n"+p);break;}

Try it online!
Ungolfed:
var R = new Random();
for (;;)
{
    char P = 'P', C = 'C', E = 'E', poundSymbol = '#';
    int width = R.Next(8, 37), height = R.Next(8, 37), HeightTemp = height, testVariable, goThroughLoop = 99, WidthTemp, i, j, rand;
    string line, strMap, poundSymbolPadding = new string(poundSymbol, width + 2);

    var map = new List<string>(); //initialize map
    for (; HeightTemp > 0; HeightTemp--)
    {
        line = "";
        for (WidthTemp = width; WidthTemp > 0; WidthTemp--)
        {
            rand = R.Next(999);
            //add a character randomly.  Re-use the goThroughLoop variable here, which gives approx. 1 wall per 10 spaces.
            line += rand < 3 ? C : rand < 6 ? E : rand < goThroughLoop ? poundSymbol : ' ';
        }
        map.Add(line);
    }
    //add finish and player
    map[0] = map[0].Substring(0, width - 1) + 'F';
    map[height - 1] = P + map[height - 1].Substring(1);

    strMap = String.Join("#\n#", map);
    //check proper # of enemies, regenerate if invalid
    testVariable = strMap.Split(E).Length - 1;
    if (testVariable < 1 || testVariable > 3)
        continue;
    //check proper # of coins, regenerate if invalid
    testVariable = strMap.Split(C).Length - 1;
    if (testVariable < 2 || testVariable > 4)
        continue;
    //map out areas Player can access.  Iterates until all accessible places have been marked as such.
    while (goThroughLoop > 0)
    {
        goThroughLoop--;
        for (i = 0; i < height; i++)
            for (j = 0; j < width; j++)
                if (map[i][j] != poundSymbol && map[i][j] != P && ((i > 0 && map[i - 1][j] == P) || (i < height - 1 && map[i + 1][j] == P) || (j > 0 && map[i][j - 1] == P) || (j < width - 1 && map[i][j + 1] == P)))
                    //mark this space as accessible
                    map[i] = map[i].Substring(0, j) + P + map[i].Substring(j + 1, width - j - 1);
    }
    //if player cannot access all features (defeated enmies, collected coins, arrived at finish), regenerate map.
    if (String.Join("", map).Split(E, C, 'F').Length > 1)
        continue;

    //output our final map
    Console.Write(poundSymbolPadding + "\n#" + strMap + "#\n" + poundSymbolPadding);

    break;
}

Edit: saved 8 bytes, made it slightly less efficient by locking the player accessible test loop to 99 iterations.  I know it'll never really compete with the other answers here, but I'm having fun!

@GregMartin Now it's your turn to implement it in F#  ;-)

A simple modulation to the subdominant, no problem :)