title: Qt Keyboard To OSC tags: python qt osc 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. ```py #!/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() ```