Skip to content

Commit

Permalink
kmosc is cli now to send osc
Browse files Browse the repository at this point in the history
  • Loading branch information
garethloot committed Mar 19, 2024
1 parent 014b769 commit f622023
Show file tree
Hide file tree
Showing 10 changed files with 143 additions and 74 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
Expand Down
7 changes: 2 additions & 5 deletions km-plugin/kmosc/Action.jxa
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ const address = app.systemAttribute('KMPARAM_Address')
const value = app.systemAttribute('KMPARAM_Value')
const valueType = app.systemAttribute('KMPARAM_ValueType')

const url = `kmosc://${host}:${port}${address}?value=${value}&valueType=${valueType}`
const command = `/Applications/KMOSC.app/Contents/MacOS/KMOSC send ${host} ${port} "${address}" ${valueType} ${value}`

// open a url in the default browser
try {
app.openLocation(url)
} catch (error) {}
app.doShellScript(command)
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "KMOSC",
"version": "0.0.2",
"version": "0.0.3",
"description": "Running Keyboards Maestro Macros with OSC",
"main": "./out/main/index.js",
"author": "Gareth Loot",
Expand Down Expand Up @@ -44,8 +44,10 @@
"@electron-toolkit/utils": "^3.0.0",
"@picocss/pico": "^2.0.3",
"@types/node-osc": "^6.0.3",
"commander": "^12.0.0",
"electron-updater": "^6.1.7",
"node-osc": "^9.1.0"
"node-osc": "^9.1.0",
"zod": "^3.22.4"
},
"devDependencies": {
"@electron-toolkit/eslint-config-prettier": "^2.0.0",
Expand Down
15 changes: 15 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 0 additions & 46 deletions src/main/OSCClient.ts

This file was deleted.

5 changes: 1 addition & 4 deletions src/main/OSCServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import { runMacro } from './macro'
import Preferences from './preferences'

const createOSCServer = (port: number): Server => {
const oscServer = new Server(port, '0.0.0.0', () => {
console.log('OSC Server is listening')
})
const oscServer = new Server(port, '0.0.0.0')

return oscServer
}
Expand All @@ -25,7 +23,6 @@ class OSCServer {
const [address, ...args] = msg
const macroName = this.preferences.slashRequired ? address : address.substring(1)
const parameters = args.join(',')
console.log(`Running macro: ${macroName} with parameters: ${parameters}`)
runMacro(macroName, parameters)
})
}
Expand Down
28 changes: 17 additions & 11 deletions src/main/index.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
import { app, ipcMain } from 'electron'
import { electronApp, optimizer } from '@electron-toolkit/utils'
import { optimizer } from '@electron-toolkit/utils'
import TrayMenu from './TrayMenu'
import { resolve } from 'path'
import Preferences from './preferences'
import OSCServer from './OSCServer'
import OSCClient from './OSCClient'
import { runCLI } from './runCLI'

if (process.defaultApp) {
if (process.argv.length >= 2) {
app.setAsDefaultProtocolClient('kmosc', process.execPath, [resolve(process.argv[1])])
const checkIfCalledViaCLI = (args): boolean => {
if (!app.isPackaged) return false
if (args && args.length > 1) {
return true
}
} else {
app.setAsDefaultProtocolClient('kmosc')
return false
}

app.whenReady().then(() => {
electronApp.setAppUserModelId('nl.garethloot.KMOSC')
const runApp = (): void => {
app.dock.hide()

const preferences = new Preferences()
const oscServer = new OSCServer(preferences)
new OSCClient()
new TrayMenu()

ipcMain.on('changePort', (_, arg) => {
Expand Down Expand Up @@ -49,4 +46,13 @@ app.whenReady().then(() => {
app.on('will-quit', () => {
oscServer.close()
})
}

app.whenReady().then(() => {
const cli = checkIfCalledViaCLI(process.argv)
if (cli) {
runCLI()
} else {
runApp()
}
})
29 changes: 29 additions & 0 deletions src/main/runCLI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { app } from 'electron'
import { sendOSCMessage } from './sendOSCMessage'
import { Command } from 'commander'

export const runCLI = (): void => {
const program = new Command()

program
.name('KMOSC')
.description('KMOSC CLI tool for sending OSC messages.')
.version(app.getVersion())
.command('send')
.argument('<host>')
.argument('<port>')
.argument('<address>')
.argument('<type>')
.argument('<message>')
.action((host, port, address, type, message) => {
if (!host || !port || !address || !type || !message) {
program.help()
process.exit(1)
} else {
sendOSCMessage(host, port, address, type, message)
app.quit()
}
})

program.parse()
}
74 changes: 74 additions & 0 deletions src/main/sendOSCMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Client, Message } from 'node-osc'
import { z } from 'zod'

const schema = z.object({
host: z
.string()
.ip({ message: 'Error: <host> must be a valid email address or localhost' })
.or(z.literal('localhost')),
port: z.coerce
.number()
.gt(1, { message: 'Error: <port> must be a number greater than 1' })
.refine((value) => !isNaN(value), {
message: 'Error: <port> must be a number greater than 1'
}),
address: z.string().startsWith('/', { message: 'Error: <address> must start with a /' }),
type: z.string().refine((value) => ['int', 'float', 'string', 'boolean'].includes(value), {
message: 'Error: <message> must be one of "int", "float", "string", or "boolean"'
}),
message: z.string().min(1, { message: 'Error: <message> must be a non-empty string' })
})

export const sendOSCMessage = (
host: string,
port: string,
address: string,
valueType: 'int' | 'boolean' | 'float' | 'string',
value: string
): void => {
const parsed = schema.safeParse({
host,
port,
address,
type: valueType,
message: value
})

if (!parsed.success) {
console.error(parsed.error.errors.forEach((error) => console.error(error.message)))
return
}

const message: Message = new Message(parsed.data.address)

switch (parsed.data.type) {
case 'int':
message.append(parseInt(parsed.data.message))
break
case 'float':
message.append(parseFloat(parsed.data.message))
break
case 'boolean':
if (parsed.data.message === 'false' || parsed.data.message === '0') {
message.append(false)
break
} else if (parsed.data.message === 'true' || parsed.data.message === '1') {
message.append(true)
break
}
break
case 'string':
message.append(parsed.data.message)
break
default:
return
}

const oscClient = new Client(parsed.data.host, Number(parsed.data.port))
oscClient.send(message, (error) => {
if (error) {
console.error('Error sending OSC message:', error)
}
oscClient.close()
})
}
5 changes: 0 additions & 5 deletions src/renderer/src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
<script lang="ts">
import { type PreferencesJSON } from '../../shared/types'
window.electron.ipcRenderer.on('log-item', (_, message) => {
console.log(message)
})
let preferences: PreferencesJSON
const getPreferences = (): void => {
window.electron.ipcRenderer.invoke('getPreferences').then((res: PreferencesJSON) => {
console.log(res)
preferences = res
})
}
Expand Down

0 comments on commit f622023

Please sign in to comment.