Advertisement
Guest User

Untitled

a guest
Jul 7th, 2024
122
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.80 KB | Source Code | 0 0
  1. from adafruit_bus_device.i2c_device import I2CDevice
  2. from adafruit_hid.mouse import Mouse
  3. from adafruit_hid.keyboard import Keyboard
  4. from adafruit_hid.keycode import Keycode
  5.  
  6. import usb_hid
  7. import board
  8. import busio
  9. import digitalio
  10.  
  11. ledOn = False
  12.  
  13. led = digitalio.DigitalInOut(board.LED)
  14. led.direction = digitalio.Direction.OUTPUT
  15.  
  16. I2C_ADDRESS = 0xA
  17.  
  18. REG_LED_RED = 0x00
  19. REG_LED_GRN = 0x01
  20. REG_LED_BLU = 0x02
  21. REG_LED_WHT = 0x03
  22.  
  23. REG_LEFT = 0x04
  24. REG_RIGHT = 0x05
  25. REG_UP = 0x06
  26. REG_DOWN = 0x07
  27.  
  28. # i2c @ address 0xA
  29. m = Mouse(usb_hid.devices)
  30. kbd = Keyboard(usb_hid.devices)
  31. i2c = busio.I2C(board.GP21, board.GP20)
  32. device = I2CDevice(i2c, I2C_ADDRESS)
  33.  
  34. # variables for operation ofmouse/keyboard
  35. mSpeed = 7
  36. mPressed = False
  37. mReleased = False
  38. debounceDelay = 3
  39. holdDelay = 10
  40. timeSinceKeyScan = 0
  41.  
  42. # stores pressed keys each frame
  43. pressedKeys = set()
  44. # stores the current modifier
  45. currentMod = 0
  46. # stores which key forces right click
  47. rClickMod = -2
  48.  
  49. # stores where in the set for each key your time
  50. # pressed and keytype appears.
  51. timePressed = 2
  52. keyTypePos = 3
  53.  
  54. # stores which mouse button was pressed last
  55. lastMouseButtonPressed = Mouse.LEFT_BUTTON
  56.  
  57. # no enums in circuitpy, so I'm just using ints for keytype
  58. # 1 = printable, 2 = function, 3 = dead
  59.  
  60. # for keycodes, we can't use 0, as that's reserved, but
  61. # for dead keys, -1
  62. # for mod keys, -2 and below
  63.  
  64. # to reduce memory usage, we flip that value while finding which keys
  65. # to press, e.g. -1 = 1, -2 = 2, that way, we can access
  66. # the relevant keys from the set
  67. # only works if you fill out the matrix with all the keypresses you need however
  68. matrix_keys = [
  69.     [
  70.         (Keycode.Q, Keycode.POUND, 0, 1),
  71.         (Keycode.W, Keycode.ONE, 0, 1),
  72.         (Keycode.E, Keycode.TWO, 0, 1),
  73.         (Keycode.R, Keycode.THREE, 0, 1),
  74.         (Keycode.T, Keycode.NINE, 0, 1),
  75.         (Keycode.Y, Keycode.ZERO, 0, 1),
  76.         (Keycode.U, Keycode.MINUS, 0, 1),
  77.         (Keycode.I, Keycode.MINUS, 0, 1),
  78.         (Keycode.O, Keycode.EQUALS, 0, 1),
  79.         (Keycode.P, Keycode.TWO, 0, 1),
  80.     ],
  81.     [
  82.         (Keycode.A, Keycode.EIGHT, 0, 1),
  83.         (Keycode.S, Keycode.FOUR, 0, 1),
  84.         (Keycode.D, Keycode.FIVE, 0, 1),
  85.         (Keycode.F, Keycode.SIX, 0, 1),
  86.         (Keycode.G, Keycode.FORWARD_SLASH, 0, 1),
  87.         (Keycode.H, Keycode.SEMICOLON, 0, 1),
  88.         (Keycode.J, Keycode.SEMICOLON, 0, 1),
  89.         (Keycode.K, Keycode.QUOTE, 0, 1),
  90.         (Keycode.L, Keycode.QUOTE, 0, 1),
  91.         (Keycode.BACKSPACE, Keycode.BACKSPACE, 0, 1),
  92.     ],
  93.     [
  94.         (Keycode.ALT, Keycode.ALT, 0, 2),
  95.         (Keycode.Z, Keycode.SEVEN, 0, 1),
  96.         (Keycode.X, Keycode.EIGHT, 0, 1),
  97.         (Keycode.C, Keycode.NINE, 0, 1),
  98.         (Keycode.V, Keycode.FORWARD_SLASH, 0, 1),
  99.         (Keycode.B, Keycode.ONE, 0, 1),
  100.         (Keycode.N, Keycode.COMMA, 0, 1),
  101.         (Keycode.M, Keycode.PERIOD, 0, 1),
  102.         (Keycode.FOUR, Keycode.POUND, 0, 1),
  103.         (Keycode.RETURN, Keycode.RETURN, 0, 1),
  104.     ],
  105.     [
  106.         (-1, -1, 0, 3),
  107.         (Keycode.SHIFT, Keycode.SHIFT, 0, 2),
  108.         (-1, -1, 0, 3),
  109.         (Keycode.CONTROL, Keycode.CONTROL, 0, 2),
  110.         (Keycode.SPACEBAR, Keycode.SPACEBAR, 0, 1),
  111.         (Keycode.SPACEBAR, Keycode.SPACEBAR, 0, 1),
  112.         (-2, -2, 0, 2),
  113.         (Keycode.SHIFT, Keycode.SHIFT, 0, 2),
  114.         (-1, -1, 0, 3),
  115.         (-1, -1, 0, 3),
  116.     ],
  117. ]
  118.  
  119. # intensity of r,g,b,w LEDs from 0-100 e.g. set_leds(100,100,25,50)
  120. def set_leds(r, g, b, w):
  121.     device.write(bytes([REG_LED_RED, r & 0xFF]))
  122.     device.write(bytes([REG_LED_GRN, g & 0xFF]))
  123.     device.write(bytes([REG_LED_BLU, b & 0xFF]))
  124.     device.write(bytes([REG_LED_WHT, w & 0xFF]))
  125.  
  126.  
  127. def set_leds_purple():
  128.     set_leds(60, 0, 90, 20)
  129.  
  130.  
  131. def set_leds_orange():
  132.     set_leds(99, 63, 8, 0)
  133.  
  134.  
  135. def set_leds_yellow():
  136.     set_leds(100, 85, 6, 0)
  137.  
  138.  
  139. def set_leds_white():
  140.     set_leds(0, 0, 0, 100)
  141.  
  142. # read trackball input
  143. def i2c_rdwr(data, length=0):
  144.     device.write(bytes(data))
  145.  
  146.     if length > 0:
  147.         msg_r = bytearray(length)
  148.         device.readinto(msg_r)
  149.         return list(msg_r)
  150.     return []
  151.  
  152.  
  153. def read():
  154.     # Read up, down, left, right and switch data from trackball
  155.     left, right, up, down, switch = i2c_rdwr([REG_LEFT], 5)
  156.  
  157.     # this line resets the switch signal, so you can't hold it.
  158.     # mechanically, may be a better idea to do this,
  159.     # but I like to highlight stuff, so too bad
  160.     # switch = 129 == switch
  161.     return up, down, left, right, switch
  162.  
  163.  
  164. col_pins = []
  165. row_pins = []
  166.  
  167. # handy lil guide telling you where to solder your rows and columns
  168. keypad_columns = [
  169.     digitalio.DigitalInOut(board.GP6),
  170.     digitalio.DigitalInOut(board.GP7),
  171.     digitalio.DigitalInOut(board.GP8),
  172.     digitalio.DigitalInOut(board.GP9),
  173.     digitalio.DigitalInOut(board.GP10),
  174.     digitalio.DigitalInOut(board.GP11),
  175.     digitalio.DigitalInOut(board.GP12),
  176.     digitalio.DigitalInOut(board.GP13),
  177.     digitalio.DigitalInOut(board.GP14),
  178.     digitalio.DigitalInOut(board.GP16),
  179. ]
  180. keypad_rows = [
  181.     digitalio.DigitalInOut(board.GP2),
  182.     digitalio.DigitalInOut(board.GP3),
  183.     digitalio.DigitalInOut(board.GP4),
  184.     digitalio.DigitalInOut(board.GP5),
  185. ]
  186.  
  187. # we want the columns going in and pulling down,
  188. # and the rows going out
  189. def initPins():
  190.     for x in range(0, 10):
  191.         col_pins.append(keypad_columns[x])
  192.         col_pins[x].direction = digitalio.Direction.INPUT
  193.         col_pins[x].pull = digitalio.Pull.DOWN
  194.     for x in range(0, 4):
  195.         row_pins.append(keypad_rows[x])
  196.         row_pins[x].direction = digitalio.Direction.OUTPUT
  197.         row_pins[x].value = 0
  198.  
  199.  
  200. # scan the mouse
  201. def pollMouse():
  202.     # let's see what that thang doing
  203.     up, down, left, right, switch = read()
  204.  
  205.     # load up everything we're gonna change in this function
  206.     global lUnclickedTime
  207.     global mPressed
  208.     global ledOn
  209.     global mReleased
  210.     global lastMouseButtonPressed
  211.  
  212.     # if we're getting a switch signal
  213.     # (this code is only tested with the switch able to be held)
  214.     # flag setting is so we don't spam left click button, or spam left click release.
  215.     # this leaves it up to the OS as to what exactly the clicks do
  216.     if switch:
  217.         ledOn = True
  218.         if not mPressed:
  219.  
  220.             mButton = Mouse.LEFT_BUTTON
  221.  
  222.             if currentMod == rClickMod:
  223.                 mButton = Mouse.RIGHT_BUTTON
  224.  
  225.             m.press(mButton)
  226.             lastMouseButtonPressed = mButton
  227.             mPressed = True
  228.             mReleased = False
  229.     else:
  230.         if not mReleased:
  231.             m.release(lastMouseButtonPressed)
  232.             mPressed = False
  233.             mReleased = True
  234.  
  235.     # gonna do some smoothing later, afaik, right and
  236.     # left are per frame movements (sorry I say frame I'm a game dev)
  237.     # so theoretically, I should be able to create a
  238.     # target position, then move the mouse towards it
  239.     # kinda what acceleration already does, but may as well build it in
  240.     x = right - left
  241.     y = down - up
  242.     m.move(int(x * mSpeed), int(y * mSpeed), 0)
  243.  
  244. def scanKeys():
  245.     global timeSinceKeyScan
  246.     if timeSinceKeyScan < debounceDelay:
  247.         timeSinceKeyScan += 1
  248.         return
  249.  
  250.     timeSinceKeyScan = 0
  251.  
  252.     global ledOn
  253.     global pressedKeys
  254.     global repeatDelay
  255.    
  256.     for row in range(4):
  257.        
  258.         # set the row output high
  259.         row_pins[row].value = 1
  260.         for col in range(10):
  261.             # set the row output high
  262.             #row_pins[row].value = 1
  263.  
  264.             if matrix_keys[row][col][keyTypePos] == 3:
  265.                 continue
  266.  
  267.             keyVal = matrix_keys[row][col][0]
  268.             keyValMod1 = matrix_keys[row][col][1]
  269.             uptime = matrix_keys[row][col][timePressed]
  270.             keyType = matrix_keys[row][col][keyTypePos]
  271.  
  272.             # make sure to reset all pins that aren't on
  273.             if col_pins[col].value == 0:
  274.                 matrix_keys[row][col] = (keyVal, keyValMod1, 0, keyType)
  275.                 continue
  276.  
  277.             # next, lets cull anything that's been held,
  278.             # but not long enough to start repeating
  279.             if keyType == 1 and uptime < holdDelay and uptime > 0:
  280.                 matrix_keys[row][col] = (keyVal, keyValMod1, uptime + 1, keyType)
  281.                 continue
  282.  
  283.             ledOn = True
  284.  
  285.             # if it's a modifier key, let's send it to decide modifier
  286.             # otherwise, let's add the co-ordinates to the keypress set
  287.             if matrix_keys[row][col][0] < -1:
  288.                 decideModifier(matrix_keys[row][col][0])
  289.             else:
  290.                 pressedKeys.add((row, col))
  291.  
  292.             # if it hasn't yet been held, start incrementing the timer
  293.             if uptime < holdDelay and keyType != 2:
  294.                 matrix_keys[row][col] = (keyVal, keyValMod1, uptime + 1, keyType)
  295.         # reset row pin output level
  296.         row_pins[row].value = 0
  297.  
  298.  
  299. # we can have multiple modifiers pressed in any given frame,
  300. # I'm deciding by last pressed, but you can decide by value,
  301. # or write in a hierarchy as you wish
  302. # e.g. if newMod < currentMod:
  303. #           currentMod = newMod
  304. def decideModifier(newMod):
  305.     global currentMod
  306.     currentMod = newMod
  307.  
  308.  
  309. def flashLED():
  310.     global ledOn
  311.     led.value = ledOn
  312.     ledOn = False
  313.  
  314.  
  315. def pressKeys():
  316.     global pressedKeys
  317.     global currentMod
  318.  
  319.     keycodeSet = set()
  320.     # only adjust the modifier if we've actually pressed one
  321.     if currentMod != 0:
  322.         currentMod = abs(currentMod) - 1
  323.  
  324.     for i in pressedKeys:
  325.         row = i[0]
  326.         col = i[1]
  327.         keycodeSet.add(matrix_keys[row][col][currentMod])
  328.    
  329.     kbd.send(*keycodeSet)
  330.     pressedKeys.clear()
  331.     keycodeSet.clear()
  332.     currentMod = 0
  333.  
  334.  
  335. with device:
  336.     set_leds_purple()
  337.     initPins()
  338.     while True:
  339.         scanKeys()
  340.         pollMouse()
  341.         pressKeys()
  342.         flashLED()
  343.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement