Keyboard: move common code to mixin (atreus21, keypad)

This commit is contained in:
Guillaume Collic 2021-02-14 13:33:57 +01:00 committed by Florian Festi
parent ec8abee265
commit 0d4d4f308b
3 changed files with 147 additions and 112 deletions

View File

@ -4,13 +4,14 @@ from copy import deepcopy
from boxes import Boxes, Color, holeCol, restore, boolarg from boxes import Boxes, Color, holeCol, restore, boolarg
from boxes.edges import FingerJointSettings from boxes.edges import FingerJointSettings
from .keyboard import Keyboard
class Atreus21(Boxes): class Atreus21(Boxes, Keyboard):
"""Generator for a split atreus keyboard.""" """Generator for a split atreus keyboard."""
ui_group = 'Misc' ui_group = 'Misc'
btn_size = 15.6 btn_size = 15.6
btn_outer = btn_size + 3.4 half_btn = btn_size / 2
border = 6 border = 6
row_offsets=[3, 6, 11, 5, 0, btn_size * .5] row_offsets=[3, 6, 11, 5, 0, btn_size * .5]
@ -82,73 +83,36 @@ class Atreus21(Boxes):
corner = [90, b] corner = [90, b]
self.polyline(*([x, corner, y, corner] * 2)) self.polyline(*([x, corner, y, corner] * 2))
self.moveTo(0, b) self.moveTo(0, b)
def half(self, cb=None, reverse=False): def half(self, hole_cb=None, reverse=False):
row_offsets=self.row_offsets row_offsets=self.row_offsets
row_keys=self.row_keys row_keys=self.row_keys
scheme = list(zip(row_offsets, row_keys)) scheme = list(zip(row_offsets, row_keys))
if reverse:
scheme.reverse()
for offset, keys in scheme:
self.moveTo(0, offset)
self.key_row(keys, cb)
self.moveTo(self.btn_outer)
self.moveTo(0, -offset)
total_moved_rows = len(row_offsets) * (self.btn_outer)
self.moveTo(total_moved_rows * -1, 0)
def key_row(self, n, hole_cb=None):
"""Callback for the key holes."""
if hole_cb == None: if hole_cb == None:
hole_cb = self.key hole_cb = self.key
for _ in range(n): self.moveTo(self.half_btn, self.half_btn)
hole_cb() self.apply_callback_on_columns(
self.moveTo(0, -n * (self.btn_outer)) hole_cb,
scheme,
self.STANDARD_KEY_SPACING,
reverse,
)
self.moveTo(-self.half_btn, -self.half_btn)
def support(self): def support(self):
btn = [11.6, (-90, 2)] * 4 self.outer_hole()
self.set_source_color(Color.BLUE)
self.moveTo(0, 2, 90)
self.polyline(*btn)
self.moveTo(-2, 0, 270)
self.moveTo(0, self.btn_outer)
self.set_source_color(Color.BLACK)
def hotplug(self): def hotplug(self):
self.moveTo(7.8 , 7.8) self.pcb_holes()
self.hole(0, 0, d=4)
self.hole(1.27 * -3, 1.27 * 2, d=2.9)
self.hole(1.27 * 2, 1.27 * 4, d=2.9)
# pcb mounts
self.hole(1.27 * -4, 0, d=1.7)
self.hole(1.27 * 4, 0, d=1.7)
self.moveTo(-7.8, -7.8)
self.moveTo(0, self.btn_outer)
def key(self): def key(self):
self.set_source_color(Color.BLUE) self.castle_shaped_plate_cutout()
# draw clock wise to work with burn correction
btn_half_side = [0.98, 90, 0.81, -90, 3.5, -90, 0.81, 90, 2.505]
btn_full_side = [*btn_half_side, 0, *btn_half_side[::-1]]
btn = [*btn_full_side, -90] * 4
self.moveTo(0.81, 0.81, 90)
self.polyline(*btn)
self.moveTo(0, 0, 270)
self.moveTo(-0.81, -0.81)
self.moveTo(0, self.btn_outer)
self.set_source_color(Color.BLACK)
# get case sizes # get case sizes
def _case_x_y(self): def _case_x_y(self):
x = len(self.row_offsets) * self.btn_outer - 4 x = len(self.row_offsets) * self.STANDARD_KEY_SPACING - 4
y = sum([ y = sum([
max(self.row_keys) * self.btn_outer, # total button sizes max(self.row_keys) * self.STANDARD_KEY_SPACING, # total button sizes
max(self.row_offsets), # offset of highest row max(self.row_offsets), # offset of highest row
-4, -4,
]) ])

View File

@ -0,0 +1,105 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2021 Guillaume Collic
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class Keyboard:
"""
Code to manage Cherry MX compatible switches and Kailh hotswap socket.
"""
STANDARD_KEY_SPACING = 19
SWITCH_CASE_SIZE = 15.6
def __init__(self):
pass
def pcb_holes(self):
grid_unit = 1.27
main_hole_size = 4
pcb_mount_size = 1.7
led_hole_size = 1
pin_hole_size = 2.9
def grid_hole(x, y, d):
self.hole(grid_unit * x, grid_unit * y, d=d)
# main hole
grid_hole(0, 0, main_hole_size)
# switch pins
grid_hole(-3, 2, pin_hole_size)
grid_hole(2, 4, pin_hole_size)
grid_hole(-4, 0, pcb_mount_size)
grid_hole(4, 0, pcb_mount_size)
def apply_callback_on_columns(self, cb, columns_definition, spacing, reverse=False):
if reverse:
columns_definition = list(reversed(columns_definition))
for offset, nb_keys in columns_definition:
self.moveTo(0, offset)
for _ in range(nb_keys):
cb()
self.moveTo(0, spacing)
self.moveTo(spacing, -nb_keys * spacing)
self.moveTo(0, -offset)
total_width = len(columns_definition) * spacing
self.moveTo(-1 * total_width)
def outer_hole(self, radius=2, centered=True):
"""
Draws a rounded square big enough to go around a whole switch (15.6mm)
"""
half_size = Keyboard.SWITCH_CASE_SIZE / 2
if centered:
self.moveTo(-half_size, -half_size)
# draw clock wise to work with burn correction
straight_edge = Keyboard.SWITCH_CASE_SIZE - 2 * radius
polyline = [straight_edge, (-90, radius)] * 4
self.moveTo(0, radius, 90)
self.polyline(*polyline)
self.moveTo(0, 0, 270)
self.moveTo(0, -radius)
self.moveTo(0)
if centered:
self.moveTo(half_size, half_size)
def castle_shaped_plate_cutout(self, centered=True):
"""
This cutout shaped like a castle enables switch modding and rotation.
More information (type 4) on https://geekhack.org/index.php?topic=59837.0
"""
half_size = Keyboard.SWITCH_CASE_SIZE / 2
if centered:
self.moveTo(-half_size, -half_size)
# draw clock wise to work with burn correction
btn_half_side = [0.98, 90, 0.81, -90, 3.5, -90, 0.81, 90, 2.505]
btn_full_side = [*btn_half_side, 0, *btn_half_side[::-1]]
btn = [*btn_full_side, -90] * 4
self.moveTo(0.81, 0.81, 90)
self.polyline(*btn)
self.moveTo(0, 0, 270)
self.moveTo(-0.81, -0.81)
if centered:
self.moveTo(half_size, half_size)

View File

@ -4,13 +4,16 @@ from copy import deepcopy
from boxes import Boxes, boolarg from boxes import Boxes, boolarg
from boxes.edges import FingerJointSettings from boxes.edges import FingerJointSettings
from .keyboard import Keyboard
class Keypad(Boxes): class Keypad(Boxes, Keyboard):
"""Generator for keypads with mechanical switches.""" """Generator for keypads with mechanical switches."""
ui_group = 'Box' ui_group = 'Box'
btn_size = 15.6 btn_size = 15.6
triangle = 25. space_between_btn = 4
box_padding = 10
triangle = 25.0
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@ -45,8 +48,8 @@ class Keypad(Boxes):
def _get_x_y(self): def _get_x_y(self):
"""Gets the keypad's size based on the number of buttons.""" """Gets the keypad's size based on the number of buttons."""
x = self.btn_x * (self.btn_size) + (self.btn_x - 1) * 4 + 20 x = self.btn_x * (self.btn_size) + (self.btn_x - 1) * self.space_between_btn + 2*self.box_padding
y = self.btn_y * (self.btn_size) + (self.btn_y - 1) * 4 + 20 y = self.btn_y * (self.btn_size) + (self.btn_y - 1) * self.space_between_btn + 2*self.box_padding
return x, y return x, y
def render(self): def render(self):
@ -69,10 +72,10 @@ class Keypad(Boxes):
self.rectangularWall(x, h, "GFEF", callback=[self.wallx_cb], move="left up") self.rectangularWall(x, h, "GFEF", callback=[self.wallx_cb], move="left up")
# keypad lids # keypad lids
self.rectangularWall(x, y, "ffff", callback=[self.support_hole], move="right") self.rectangularWall(x, y, "ffff", callback=self.to_grid_callback(self.support_hole), move="right")
self.rectangularWall(x, y, "ffff", callback=[self.key_hole], move="up") self.rectangularWall(x, y, "ffff", callback=self.to_grid_callback(self.key_hole), move="up")
if self.top2_enable: if self.top2_enable:
self.rectangularWall(x, y, "ffff", callback=[self.hotplug]) self.rectangularWall(x, y, "ffff", callback=self.to_grid_callback(self.hotplug))
# screwable # screwable
tr = self.triangle tr = self.triangle
@ -87,64 +90,27 @@ class Keypad(Boxes):
callback=[None, lambda: self.hole(trh, trh, d=d1)] callback=[None, lambda: self.hole(trh, trh, d=d1)]
) )
def to_grid_callback(self, inner_callback):
scheme = [(0, self.btn_y)]*self.btn_x
def callback():
# move to first key center
key_margin = self.box_padding + self.btn_size / 2
self.moveTo(key_margin, key_margin)
self.apply_callback_on_columns(
inner_callback, scheme, self.btn_size + self.space_between_btn
)
return [callback]
def hotplug(self): def hotplug(self):
"""Callback for the key stabelizers.""" """Callback for the key stabelizers."""
# draw clock wise to work with burn correction self.pcb_holes()
btn = [11.6, (-90, 2)] * 4
s = self.btn_size
self.moveTo(10, 10)
for _ in range(self.btn_y):
for _ in range(self.btn_x):
self.moveTo(7.8 , 7.8)
self.hole(0, 0, d=4)
self.hole(1.27 * -3, 1.27 * 2, d=2.9)
self.hole(1.27 * 2, 1.27 * 4, d=2.9)
# pcb mounts
self.hole(1.27 * -4, 0, d=1.7)
self.hole(1.27 * 4, 0, d=1.7)
self.moveTo(-7.8, -7.8)
self.moveTo(s + 4)
#self.moveTo(1.27 * -2, 1.17 * 3)
#self.moveTo(1.27 * 2, 1.17 * -3)
self.moveTo(self.btn_x * (s + 4) * -1, s + 4)
def support_hole(self): def support_hole(self):
"""Callback for the key stabelizers.""" self.outer_hole()
# draw clock wise to work with burn correction
btn = [11.6, (-90, 2)] * 4
s = self.btn_size
self.moveTo(10, 10)
for _ in range(self.btn_y):
for _ in range(self.btn_x):
self.moveTo(0, 2, 90)
self.polyline(*btn)
self.moveTo(0, 0, 270)
self.moveTo(s + 4, -2)
self.moveTo(self.btn_x * (s + 4) * -1, s + 4)
def key_hole(self): def key_hole(self):
"""Callback for the key holes.""" self.castle_shaped_plate_cutout()
# draw clock wise to work with burn correction
btn_half_side = [0.98, 90, 0.81, -90, 3.5, -90, 0.81, 90, 2.505]
btn_full_side = [*btn_half_side, 0, *btn_half_side[::-1]]
btn = [*btn_full_side, -90] * 4
s = self.btn_size
self.moveTo(10, 10)
for _ in range(self.btn_y):
for _ in range(self.btn_x):
self.moveTo(0.81, 0.81, 90)
self.polyline(*btn)
self.moveTo(0, 0, 270)
self.moveTo(-0.81, -0.81)
self.moveTo(s + 4)
self.moveTo(self.btn_x * (s + 4) * -1, s + 4)
# stolen form electronics-box # stolen form electronics-box
def wallx_cb(self): def wallx_cb(self):