// HP 39gs and HP 40gs keypad overlay for newRPL usage // // Louis Mamakos // louie@transsys.com // $fn = 30; // yeah, give up doing colors in OpenSCAD since it's hard to // get them to propagate when doing a projection() operation // // color scheme by default attempts to emulate that of the HP 50gs. // // the background color is close, though the shift keys are different // // and there's only one shifted legend printed on the body of the // // stock 39gs and 40gs calculators. // // Have to think about the color scheme to be use with the HP 39gs // // blue-body calculator and what if anything to do about that // // background color being exposed behind the overlay. Maybe adapt // // the colors to assume a blue background? // // define colors for the keyboard body overlay. This is the space // // and labels around the keys. // // assumes print media is white and needs to be completely covered // // with ink. Need a slightly different strategy if printable // // colored vinyl media is available with a color that is usable // // as the background // color_background = "DarkSlateGray"; // background color of template // color_LS = [0.99, 0.99, 0.99]; // LEFT SHIFT legends - almost white // color_RS = "OrangeRed"; // RIGHT SHIFT legends // color_CANCEL = "Blue"; // Cancel label below ON key // color_HOLE = [1, 1, 1]; // holes are white // alpha_HOLE = 0; // make holes transparent // // define colors for keycaps and labels. // // rows mostly but not exclusively the same color // color_ALPHA = "Gold"; // Alphabet labels // label_font = "Arial Narrow:style=Regular"; key_matrix_size = [ 66, 100 ]; // simplistic hack - just center within larger rectangle with 5mm margins margins = 5; directional_diameter = 8.0; directionals = [ [ 50.5, 88.7 ], // up button [ 42.5, 82.2 ], // left button [ 58.5, 82.2 ], // right button [ 50.5, 75.7 ], // down button ]; // this is how far to pull in from the dimensions // of the holes for the size of the keycaps. This // dimension is from each edge keycap_shrink = 1.1; // 1.0 // extra margin for keycap size in the height direction // to provide a little bit of extra space for key travel // when key is depressed, and key rotates towards the top // of the calculator keycap_vertical_margin = 0.2; keycap = [ // increasing Y direction - starting from botton [10.5, 7.5], // row 1 - numeric keypad [10.5, 7.5], // row 2 - numeric keypad [10.5, 7.5], // row 3 - numeric keypad [10.5, 7.5], // row 4 - numeric keypad [10.5, 6.5], // row 5 - operation keys [10.5, 6.5], // row 6 - operation keys [10.5, 6.5], // row 7 - operation keys [ 8.0, 6.5], // row 8 - "setup"/menu 2 keys [ 8.0, 6.5], // row 9 - "setup"/menu 2 keys [ 8.0, 5.0], // row 10 - menu/function keys ]; // offset for each row of keys. This is the distance from the origin to // the lower edge of each key. The "ON" key lies at Y offset zero. row_y = [ 0, // ON row - lower edge row 10 at bottom 11.0, // RS row - lower edge row 9 to lower edge row 10 21.5, // LS row - 32.5, // ALPHA row 43.0, // V / EEX row 53.0, // Q / y^x row 62.5, // M / STO row 73.7, // J / HOME row 85.0, // G / SYMB row 96.5, // A / top "menu" key row - lower edge row 2 to lower edge row 1 ]; columns = [ // [ column_spaces, keys ] [5, 5], // ON/0 row (bottom) [5, 5], // SHIFT/1 row [5, 5], // ALPHA/4 row [5, 5], // ,/7 row [5, 5], // x^2 row [5, 5], // SIN/COS row [5, 5], // VARS/MATH row [6, 3], // HOME/APLET row [6, 3], // SYMB/PLOT row [6, 6] // soft F keys row (top) ]; // polygon verticies to attempt to follow the curve of // the keypad bezel. rounded corners would be nice.. kbd_frame = [ [-61.1/2, 0], [-68.0/2, 2.5], [-70.1/2, 5], [-71.6/2, 10], [-73.6/2, 20], [-75.3/2, 30], [-76.6/2, 40], [-77.5/2, 50], [-77.4/2, 60], [-76.7/2, 70], [-75.6/2, 80], [-74.0/2, 90], [-72.5/2,100], [-73.0/2,110], [73.0/2, 110], [72.5/2, 100], [74.0/2, 90], [75.6/2, 80], [76.7/2, 70], [77.4/2, 60], [77.5/2, 50], [76.6/2, 40], [75.3/2, 30], [73.6/2, 20], [71.6/2, 10], [70.1/2, 5], [68.0/2, 2.5], [61.1/2, 0], [-61.1/2, 0] ]; // some smoothing modules, from // http://forum.openscad.org/3d-offset-tp12100p12107.html module smooth(r=3) { $fn=30; offset(r=r) offset(r=-r) children(); } module fillet(r=3) { $fn=30; offset(r=-r) offset(r=r) children(); } // // 0,0 will be the bottom left corner of the keyboard overlay // module key(w, h) { square([w,h], center=false); } module rounded_key(x, y) { radius = 15; intersection() { square([x,y], center=false); translate([x/2,radius]) circle(r=radius, $fn=70); } } module border() { polygon(points=[ [0, 0], // lower left [key_matrix_size[0]+margins*2, 0], // lower right [key_matrix_size[0]+margins*2, key_matrix_size[1]+margins*2], //upper right [0, key_matrix_size[1]+margins*2], //upper left] [0, 0] // lower left ]); } module frame() { polygon(points=kbd_frame); } module dpad() { translate([margins, margins]) { for (hole = [0:3]) { translate(directionals[hole]) { circle(d=directional_diameter); } } // try to chop out the middle // translate([ directionals[1][0] + (directionals[2][0]-directionals[1][0])/2, // directionals[3][1] + (directionals[0][1]-directionals[3][1])/2 ]) // scale([2.,1.5]) // circle(d=directional_diameter*1); } } function yoffset(row, sum = 0) = (row == 0 ? row_spacing[row] : row_spacing[row] + yoffset(row-1, sum)); //render small rectanges intended for the tops of the keys. This should be refactored //to avoid duplicating all the code that iterates over the rows module keytops() { translate([margins, margins]) { // we do this for not all the rows of keys, as it seems unlikely that you'd // want labels for the top row (9) of "soft" keys and probably also the // next two rows as you can just ignore the labels printed for (row=[0:6]) { keyw = keycap[row][0]; // width of each key in this row key_positions = columns[row][0]-1; // number of key positions in this row translate([0, row_y[row]]) { for (col=[0:columns[row][1]-1]) { // loop over all actual keys, left to right // spacing defined by number of positions in [0] x = col * (key_matrix_size[0] - keyw)/key_positions; key_width = keycap[row][0] - keycap_shrink * 2; key_height = keycap[row][1] - keycap_shrink * 2; translate([x + keycap_shrink, keycap_shrink]) { rounded_key(key_width, key_height); } } } } } } module keypad_holes() { translate([margins, margins]) { for (row=[0:9]) { keyw = keycap[row][0]; // width of each key in this row key_positions = columns[row][0]-1; // number of key positions in this row translate([0, row_y[row]]) { for (col=[0:columns[row][1]-1]) { // loop over all actual keys, left to right // spacing defined by number of positions in [0] x = col * (key_matrix_size[0] - keyw)/key_positions; key_width = keycap[row][0]; key_height = keycap[row][1] + keycap_vertical_margin; translate([x, 0]) { if (row < 9) rounded_key(key_width, key_height); else key(key_width, key_height); } } } } } } // color("gray") square(key_matrix_size + [margins*2, margins*2], center=false); projection(cut=false) union() { linear_extrude(1) keytops(); difference() { intersection() { linear_extrude(1) border(); linear_extrude(2) translate([key_matrix_size[0]/2+margins,0,-0.5]) smooth(r=3) frame(); } translate([0, 0, -0.5]) linear_extrude(2) union() { keypad_holes(); dpad(); } } }