You can 3d-print a frame with keys attached to it:
Here an openscad file that I used for a portrait keyboard, I think you get the idea. The keys are a bit too tall, maybe 2 mm would be better. You may need a frame with holes, kind of spacer around the keys to hold this frame with keys, the it doesn't flex when you press a key. I do not seem to have the file (it is somewhere who knows where).
Code:
// all measurements in mm
// fully parametrized
//
nkeys_horiz = 6;
nkeys_vert = 7;
key_width = 8;
key_height = 5;
key_depth = 3; // z-axis
key_binder_width = 5;
key_binder_depth = 0.6;
key_border = 0.6;
keyrow_height = 12.7-1.27-1.27;
keyrow_step = 12.7;
border_width = 6;
border_height = 5;
border_depth = 1;
// horizontal key separator
sep_width = keyrow_step - 2 * key_border - key_width;
// double-length key
module enter_key()
{
translate ([key_border, key_border, 0])
{
cube ([ key_width+keyrow_step, key_height, key_depth]);
translate ([(key_width-key_binder_width) / 2, -key_border, 0]) cube ([ key_binder_width+keyrow_step, key_border, key_binder_depth]);
}
}
module key()
{
translate ([key_border, key_border, 0])
{
cube ([ key_width, key_height, key_depth]);
translate ([(key_width-key_binder_width) / 2, -key_border, 0]) cube ([ key_binder_width, key_border, key_binder_depth]);
}
}
module keyrow()
{
//sep_width = keyrow_step - 2 * key_border - key_width;
translate ([0, keyrow_height - 2 * key_border-key_height, 0])
{
for (x = [0:nkeys_horiz-1])
translate ([x*keyrow_step, 0, 0]) key();
if (nkeys_horiz > 1)
for (x = [0:nkeys_horiz-2])
translate ([x*keyrow_step + 2 * key_border + key_width, 0, 0]) cube ([sep_width, 2*key_border+key_height, border_depth]);
}
cube ([(nkeys_horiz-1)*keyrow_step+key_width+2*key_border, keyrow_height-key_height-2*key_border, border_depth]);
}
module enter_keyrow()
{
//sep_width = keyrow_step - 2 * key_border - key_width;
translate ([0, keyrow_height - 2 * key_border-key_height, 0])
{
for (x = [0:nkeys_horiz-1])
if (x == 0)
translate ([x*keyrow_step, 0, 0]) enter_key();
else
if (x != 1)
translate ([x*keyrow_step, 0, 0]) key();
if (nkeys_horiz > 1)
for (x = [0:nkeys_horiz-2])
if (x != 0)
translate ([x*keyrow_step + 2 * key_border + key_width, 0, 0]) cube ([sep_width, 2*key_border+key_height, border_depth]);
}
cube ([(nkeys_horiz-1)*keyrow_step+key_width+2*key_border, keyrow_height-key_height-2*key_border, border_depth]);
}
// keys 8x5
translate ([1*border_width, 0, 0])
{
// keys from bottom to top, row 5 is always enter key row
for (y = [0:nkeys_vert-1])
if (y == 4)
translate ([0, keyrow_height*y, 0]) enter_keyrow();
else
translate ([0, keyrow_height*y, 0]) keyrow();
// left side
translate ([-border_width, 0, 0]) cube ([border_width, nkeys_vert*keyrow_height+border_height, border_depth]);
// right side
translate ([nkeys_horiz*keyrow_step-sep_width, 0, 0]) cube ([border_width, nkeys_vert*keyrow_height+border_height, border_depth]);
// top
translate ([-border_width, keyrow_height*nkeys_vert, 0]) cube ([border_width+nkeys_horiz*keyrow_step-sep_width, border_height, border_depth]);
// display area
}