Dup Ver Goto 📝

Qt Keyboard To OSC

To
144 lines, 434 words, 3250 chars Page 'QtKeyboardSender' does not exist.

This opens a window and generates OSC messages of the form /kb/something/ACMSx for Alt-Ctrl-Meta-Shift-x where something is an arbitrary string to allow for multiple profiles. Naturally you could have the script look up the key combo and if it finds something, do some action instead. Also having the window larger and display the profile, possibly with some help text, all such things are easily possible.

Note one quirk: the modifiers are always prepended. So if you get + via the top row, you will get Splus, whereas if you get it via a keypad, you'll get plus. The main current target application is Reaper, where these OSC messages can be bound to actions.

It may also make sense to pass in an OSC client, rather than creating it in the class as we do. Indeed the 'client' needn't be an actual client, rather any object with a send_message method.

#!/usr/bin/env python
import sys
import os
import math
import random
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
from PySide6.QtNetwork import *
from pythonosc import udp_client
from icecream import ic; ic.configureOutput(includeContext=True)

app = QApplication([])

lookup = {
  "!": "bang",
  '"': "dquote",
  "£": "gbp",
  "$": "dollar",
  "%": "percent",
  "^": "caret",
  "&": "amp",
  "*": "asterisk",
  "(": "lparen",
  ")": "rparen",
  "-": "hyphen",
  "=": "equals",
  "_": "underscore",
  "+": "plus",
  "[": "lbracket",
  "]": "rbracket",
  "{": "lbrace",
  "}": "rbrace",
  ";": "semicolon",
  ":": "colon",
  "'": "quote",
  "@": "at",
  "#": "hash",
  "~": "tilde",
  ",": "comma",
  "<": "lt",
  ".": "period",
  ">": "gt",
  "/": "slash",
  "?": "question",
  "\\": "backslash",
  "|": "pipe",
  "`": "backquote",
  "¬": "neg",
  " ": "space",
  '\x01': "a",
  '\x02': "b",
  '\x03': "c",
  '\x04': "d",
  '\x05': "e",
  '\x06': "f",
  '\x07': "g",
  '\x08': "h",
  '\t': "i",
  '\n': "j",
  '\x0b': "k",
  '\x0c': "l",
  '\r': "m",
  '\x0e': "n",
  '\x0f': "o",
  '\x10': "p",
  '\x11': "q",
  '\x12': "r",
  '\x13': "s",
  '\x14': "t",
  '\x15': "u",
  '\x16': "v",
  '\x17': "w",
  '\x18': "x",
  '\x19': "y",
  '\x1a': "z",
}

class Kb(QWidget):
  def __init__(self,target="localhost",port=2900,profile="init"):
    super().__init__()
    self.target = target
    self.port = port
    self.osc_client = udp_client.SimpleUDPClient(target, port)
    self.move(20,20)
    self.resize(80,60)
    self.profile = profile

  def setProfile(self,profile):
    self.profile = profile

  def keyPressEvent(self,e):
    #ic(e,repr(e.text()))
    t = e.text().lower()
    if len(t) == 0:
      return
    if t in lookup:
      t = lookup[t]
    ms = e.modifiers().value
    av = Qt.AltModifier.value
    cv = Qt.ControlModifier.value
    mv = Qt.MetaModifier.value
    sv = Qt.ShiftModifier.value
    a = (av&ms) > 0
    c = (cv&ms) > 0
    m = (mv&ms) > 0
    s = (sv&ms) > 0
    if s:
      t = "S"+t
    if m:
      t = "M"+t
    if c:
      t = "C"+t
    if a:
      t = "A"+t

    addr = f"/kb/{self.profile}/{t}"
    self.osc_client.send_message(addr,[])
    print(t)

  def paintEvent(self,e):
    rect = self.rect()
    with QPainter(self) as p:
      p.fillRect(rect,Qt.black)

w = Kb()
w.show()

app.exec()