g | x | w | all
Bytes Lang Time Link
117Perl 5 pla240911T175618ZXcali
061Uiua240912T203900Zjan
109JavaScript Node.js240910T122648Zl4m2
022Vyxal ḋ210822T111337Zemanresu
02705AB1E210822T141846Zovs
088Ruby210823T233418ZLevel Ri
nanPerl 5210823T125215ZDenis Ib
021Jelly210822T140317ZJonathan
100R210823T080056ZDominic
nanPython 3.8 prerelease210823T094532Zm90
113JavaScript ES6210822T135946ZArnauld
056Charcoal210822T123920ZNeil
023Jelly210822T200444ZNick Ken

Perl 5 -pla, 121 117 bytes

@emanresuA's suggestion saved 4 bytes

QWERTYUIOPASDFGHJKL_ZXCVBNM=~/$_/g;push@x,2**($y[@y]=0|"@-"/10)/4+"@-"%10}{$"='-';$\=19.05*sqrt eval"(@x)**2+(@y)**2"

Try it online!

Uiua, 61 characters

×4.76⌵/ℂ-∩(+×4⟜(⊂0ⁿ:2⊢)⊢⊚=↯3_10"QWERTYUIOPASDFGHJKL-ZXCVBNM")

Try it here!

Thanks to emanresu A for -4 due to their tip on the perl -pla answer!

Contains the apparently standard techniques of deliberate error and complex numbers (inspired by the Uiua tips page).

JavaScript (Node.js), 109 bytes

a=>b=>Math.hypot(g(a)-g(b,q=p),p-q)*4.7625
g=c=>8>>(p="QA ZWS XED CRF VTG BYH NUJ MIK ,OL .P".search(c))%4&12

Try it online!

Vyxal , 22 bytes

ƛk•$Þḟ÷Ȯ⇩E+";ƒ∆d19.05*

Try it Online!

I still don't particularly like having to include the full 19.05, but at least this is a lot shorter. Vyxal outputs symbolic expressions for irrationals by default, so the flag turns them into decimals.

ƛ           ;          # Over both characters
    Þḟ                 # Get the multidimensional index in
 k•$                   # [rows of qwerty keyboard]
          +            # Add to the x-coordinate
       Ȯ E             # 2 to the power of the y-coordinate
        ⇩              # Divided by 4
      ÷    "           # (and swap them, but that doesn't matter)
             ƒ∆d       # Take the difference
                19.05* # and multiply by 19.05

05AB1E, 33 28 27 bytes

-1 byte thanks to Kevin Cruijssen!

Builtins for multi-dimensional index and euclidean distance would be helpful. Takes input in lowercase.

vžVyδkZDŠkDŠÍo+‚}-nOt19.05*

Try it online!

Commented:

v               }   # iterate over each character y in the input
 žV                 # push ["qwertyuiop", "asdfghjkl", "zxcvbnm"]
   yδk              # for each row, find the index of the current char in it (-1 if not found)
      ZD            # get the maximum one (the only one not equal to -1) twice (call this x)
        Š           # rotate top 3 values on the stack (x [indices] x)
         k          # find the index of x in the indices (call this y)
          DŠ        # duplicate y and rotate top 3 values (y x y)
            Ío      # 2**(y-2)
              +     # add to x   (y x+2**(y-2))
               ‚    # pair up both values [y, x+2**(y-2)]

 -                  # take the element-wise differences
  nOt               # Euclidean norm (square, sum, square root)
     19.05*         # multiply by constant 19.05 (*1905/100 would be the same length with integer compression)

Ruby, 88 bytes

->a{p,q=a.map{|i|b=:_QAZWSXEDCRFVTGBYHNUJMIK_OL_P=~/#{i}/
b*4/3+-b%3*4i}
(p-q).abs*4.76}

Try it online!

Used a symbol instead of a string as suggested by Dingus. Also improved formula for converting b to a complex number (saved several bytes, although it requires another dummy character at the start of the string.)

Ruby, 95 bytes

->a{p,q=a.map{|i|b='QAZWSXEDCRFVTGBYHNUJMIK<OL>P'.index i
b/3*4+b%3*3/2+b%3*4i}
(p-q).abs*4.76}

Try it online!

I used a QAZ WSXorder because it splits into rows and columns by the application of b/3 and b%3, saving three bytes over the alternative b/10 and b%10. p and q contain the coordinates as complex numbers, expressed as integer multiples of a quarter of a key. At the end we multiply by 4.76 which is in approximation of 19.05/4 = 4.7625. The value 4.76*4 = 19.04 gives an error of 0.01mm between two adjacent keys on the same row, giving a maximum error of 0.09mm between P and Q which is within allowed limits.

Perl 5, 129 + 4 (-apl options) = 133 bytes

($x,$y,$u,$v)=map{$i=index+QWERTYUIOPASDFGHJKL_ZXCVBNM,$_;$==$i/10;$i%10+(0,1,3)[$=]/4,$=}@F;$_=19.05*sqrt(($x-$u)**2+($y-$v)**2)

Try it online!

Jelly,  25 24 23  21 bytes

-1 thanks to Nick Kennedy! (use of ) to avoid repeated mapping)

-2 thanks to emanresu A! (Accuracy is only required to be within \$0.1\$mm of the true value)

ØQœi×4:3+ɗ\)ạ/×4.76ÆḊ

A monadic Link that accepts a list of two upper-case characters and yields a floating-point number.

Try it online! Or see the test-suite.

How?

Finds horizontal and vertical distances measured in quarter-key lengths of \$\frac{19.05}{4} = 4.7625\$ then takes the norm of the vector (i.e. uses Pythagoras). Since \$4.76\$ is good enough* for requirements, that is used as the quarter-key length.

ØQœi×4:3+ɗ\)ạ/×4.76ÆḊ - Link: characters, [A, B]
           )          - for each (c in [A, B]):
ØQ                    -   Qwerty keyboard -> ["Q..P","A..L","Z..M"]
  œi                  -   first multi-dimensional index of c in Qwerty keyboard
    ×4                -   multiply by four
                          -> [row(c)×4, column(c)×4]
          \           -   cumulative reduce by:
         ɗ            -     last three links as a dyad:
       3              -       three
      :               -       (row(c)×4) integer divide (3)  i.e. 4->1; 8->2; 12->4
        +             -       add (column(c)×4)  -> [row(c)×4, column(c)×4+(row(c)×4:3)]
                           (i.e. quarter steps down and right from a point a quarter
                                 left of the top-left of Q required to reach the bottom
                                 right of each of [A, B])
             /        - reduce by:
            ạ         -   absolute difference -> [vertical, horizontal] quarter steps
              ×4.76   - multiply by 4.7625 -> [vertical, horizontal] distances
                   ÆḊ - vector norm -> distance between keys

* Here is a suite showing all values are within \$0.1\$mm of the actual values - checking that all possible pairs using a quarter-key length of \$4.76\$ are within \$0.1\$ of those calculated using a quarter-key length of \$4.7625\$. (All results are actually also within \$0.1\$mm of Matt Parker's \$2\$ decimal place values - see this)

R, 145 142 138 125 124 102 100 bytes

Edit: -4 bytes thanks to ovs

function(x,j=2-sapply(x,regexpr,'lo,kimjunhybgtvfrcdexswzaq'))dist(cbind(y<-j%%3,j%/%3+2^y/4))*19.05

Try it online!

Ungolfed

qwertydist=function(x){     # x = input = vector of two characters
 k='lo,kimjunhybgtvfrcdexswzaq'
                            # k = 26-character vector of keys of each keyboard column exept last (in reverse).
 j=2-sapply(x,regexpr,k)    # j = indices of x in reversed k, & offset by a fixed value so that the missing 'p' ends-up in the right place
 y<-j%%3                    # y = row of each key
 z=j%/%3+2^y/4              # z = col of each key, adjusted +.25 for row 1 & +.5 for row 2
 d=dist(cbind(y,z))*19.05   # d = euclidean distance between keys, in millimetres
}

Python 3.8 (pre-release), 108 97 bytes

lambda x,y:abs(p(x)-p(y))*4.76
p=lambda c:(a:='.LO,KIMJUNHYBGTVFRCDEXSWZAQ'.find(c))%3*4j+a--a//3

Try it online!

p maps a character to a complex number corresponding to its key's position, at a scale where the key size is 4; the magnitude of the difference of p of the given characters, rescaled, gives the answer.
find returning -1 when the substring is not found is used to handle P.

-2 using the suggestion of a decimal multiplier from emanresu A, taken one step further – with the value 4.76, the maximum error is slightly over 0.09, just within the limit.
-9 by transposing the keyboard and making some other changes with that.

JavaScript (ES6),  114  113 bytes

Saved 1 byte thanks to @Shaggy

Expects (a)(b).

a=>b=>Math.hypot((g=c=>(x="WERTYUIOPASDFGHJKLZXCVBNM".search(c))-[y=x>8,39,73][y+=x>17]/4)(a)-g(b,Y=y),y-Y)*19.05

Try it online!

Charcoal, 60 56 bytes

I×¹⁹·⁰⁵₂ΣE²X↨EEθ⌕”&⌈‽↶ ›I✂TFsG�¦ιAo⊟↧”λ⎇ι﹪λ³⊘⊘÷⊗⊗⊕λ³±¹¦²

Try it online! Link is to verbose version of code. Takes input as a string of two lower case letters. Explanation: The compressed string contains the letters in a staggered arrangement. The vertical offset is simply the index modulo 3, while the horizontal offset is computed by dividing the index by 3 and rounding to the nearest multiple of 0.25. Pythagoras is then used to compute the final result.

         E²                             Loop twice (horizontally/vertically)
              Eθ                        Loop over input
                ⌕...λ                   Find char indices in compressed string
             E       ⎇ι                 Extract either
                       ﹪λ³              Vertical offset
                          ⊘⊘÷⊗⊗⊕λ³      Horizontal offset
           X↨                     ±¹¦²  Take the squared difference
        Σ                               Take the sum
       ₂                                Take the square root
 ×¹⁹·⁰⁵                                 Multiply by literal 19.05
I                                       Cast to string for implicit print

Jelly, 23 bytes

ØQœi2*÷8Ʋ+¥\)ạ/ÆḊ×19.05

Try it online!

A monadic link taking a list of two characters and returning a float.