Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion zmk_studio_cli/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@

import typer

from . import behaviors, core, keymap
from . import behaviors, combos, core, keymap


def register(app: typer.Typer) -> None:
"""Register all commands with the app"""
app.add_typer(core.app)
app.add_typer(behaviors.app)
app.add_typer(keymap.app)
app.add_typer(combos.app)
39 changes: 39 additions & 0 deletions zmk_studio_cli/commands/combos/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright (c) 2025 The ZMK Contributors
# SPDX-License-Identifier: MIT

"""
ZMK Studio CLI combos subcommands.
"""

import typer

from .get_combos import combos_get_combos
from .add_combo import combos_add_combo
from .delete_combo import combos_delete_combo
from .set_binding import combos_set_binding
from .add_position import combos_add_position
from .remove_position import combos_remove_position
from .add_layer import combos_add_layer
from .remove_layer import combos_remove_layer
from .clear_layers import combos_clear_layers
from .set_slow_release import combos_set_slow_release
from .set_timeout import combos_set_timeout
from .set_req_prior_idle import combos_set_req_prior_idle

app = typer.Typer(name="combos")
app.command(name="get-combos")(combos_get_combos)
app.command(name="add-combo")(combos_add_combo)
app.command(name="delete-combo")(combos_delete_combo)
app.command(name="set-binding")(combos_set_binding)
app.command(name="add-position")(combos_add_position)
app.command(name="remove-position")(combos_remove_position)
app.command(name="add-layer")(combos_add_layer)
app.command(name="remove-layer")(combos_remove_layer)
app.command(name="clear-layers")(combos_clear_layers)
app.command(name="set-slow-release")(combos_set_slow_release)
app.command(name="set-timeout")(combos_set_timeout)
app.command(name="set-req-prior-idle")(combos_set_req_prior_idle)

@app.callback()
def combos() -> None:
"""ZMK Studio combos actions"""
65 changes: 65 additions & 0 deletions zmk_studio_cli/commands/combos/add_combo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Copyright (c) 2025 The ZMK Contributors
# SPDX-License-Identifier: MIT

"""
add-combo
"""

from typing import Annotated

import typer

from ...proto import studio_pb2 as studio
from ...rpc import rpc_get_response, rpc_handle_response, rpc_send_request


def combos_add_combo(
ctx: typer.Context,
behavior_id: Annotated[
int,
typer.Argument(
help="Behavior ID",
),
] = None,
param1: Annotated[
int,
typer.Argument(
help="Behavior 1st parameter",
),
] = None,
param2: Annotated[
int,
typer.Argument(
help="Behavior 1st parameter",
),
] = None,
key_position1: Annotated[
int,
typer.Argument(
help="Key position #1",
),
] = None,
key_position2: Annotated[
int,
typer.Argument(
help="Key position #1",
),
] = None,
) -> None:
"""Add a combo"""
ser = ctx.obj.ser
verbose = ctx.obj.verbose

request = studio.Request()
request.request_id = 1
request.combos.add_combo.binding.behavior_id = behavior_id
if param1:
request.combos.add_combo.binding.param1 = param1
if param2:
request.combos.add_combo.binding.param2 = param2

request.combos.add_combo.positions.append(key_position1)
request.combos.add_combo.positions.append(key_position2)

rpc_send_request(ser=ser, request=request, verbose=verbose)
rpc_handle_response(rpc_get_response(ser=ser, verbose=verbose))
42 changes: 42 additions & 0 deletions zmk_studio_cli/commands/combos/add_layer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright (c) 2025 The ZMK Contributors
# SPDX-License-Identifier: MIT

"""
add-layer
"""

from typing import Annotated

import typer

from ...proto import studio_pb2 as studio
from ...rpc import rpc_get_response, rpc_handle_response, rpc_send_request


def combos_add_layer(
ctx: typer.Context,
combo_id: Annotated[
int,
typer.Argument(
help="Combo identifier",
),
] = None,
layer: Annotated[
int,
typer.Argument(
help="Layer",
),
] = None,
) -> None:
"""Remove layer from a combo"""
ser = ctx.obj.ser
verbose = ctx.obj.verbose

request = studio.Request()
request.request_id = 1
request.combos.set_combo_layer_state.id = combo_id
request.combos.set_combo_layer_state.layer = layer
request.combos.set_combo_layer_state.enabled = True

rpc_send_request(ser=ser, request=request, verbose=verbose)
rpc_handle_response(rpc_get_response(ser=ser, verbose=verbose))
44 changes: 44 additions & 0 deletions zmk_studio_cli/commands/combos/add_position.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright (c) 2025 The ZMK Contributors
# SPDX-License-Identifier: MIT

"""
add-position
"""

from typing import Annotated

import typer

from ...proto import studio_pb2 as studio
from ...rpc import rpc_get_response, rpc_handle_response, rpc_send_request


def combos_add_position(
ctx: typer.Context,
combo_id: Annotated[
int | None,
typer.Argument(
help="Combo identifier",
),
] = None,
key_pos: Annotated[
int | None,
typer.Argument(
help="Key Position",
),
] = None,
) -> None:
"""Add key position to a combo"""
ser = ctx.obj.ser
verbose = ctx.obj.verbose

request = studio.Request()
request.request_id = 1
request.combos.set_combo_position_state.id = combo_id
request.combos.set_combo_position_state.position = key_pos
request.combos.set_combo_position_state.enabled = True

rpc_send_request(ser=ser, request=request, verbose=verbose)
rpc_handle_response(rpc_get_response(ser=ser, verbose=verbose))


34 changes: 34 additions & 0 deletions zmk_studio_cli/commands/combos/clear_layers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Copyright (c) 2025 The ZMK Contributors
# SPDX-License-Identifier: MIT

"""
clear-layers
"""

from typing import Annotated

import typer

from ...proto import studio_pb2 as studio
from ...rpc import rpc_get_response, rpc_handle_response, rpc_send_request


def combos_clear_layers(
ctx: typer.Context,
combo_id: Annotated[
int,
typer.Argument(
help="Combo identifier",
),
] = None,
) -> None:
"""Clear layers from a combo"""
ser = ctx.obj.ser
verbose = ctx.obj.verbose

request = studio.Request()
request.request_id = 1
request.combos.clear_combo_layers.id = combo_id

rpc_send_request(ser=ser, request=request, verbose=verbose)
rpc_handle_response(rpc_get_response(ser=ser, verbose=verbose))
33 changes: 33 additions & 0 deletions zmk_studio_cli/commands/combos/delete_combo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright (c) 2025 The ZMK Contributors
# SPDX-License-Identifier: MIT

"""
delete-combo
"""

from typing import Annotated

import typer

from ...proto import studio_pb2 as studio
from ...rpc import rpc_get_response, rpc_handle_response, rpc_send_request

def combos_delete_combo(
ctx: typer.Context,
combo_id: Annotated[
int | None,
typer.Argument(
help="Combo identifier",
),
] = None,
) -> None:
"""Delete combo by identifier"""
ser = ctx.obj.ser
verbose = ctx.obj.verbose

request = studio.Request()
request.request_id = 1
request.combos.delete_combo.id = combo_id

rpc_send_request(ser=ser, request=request, verbose=verbose)
rpc_handle_response(rpc_get_response(ser=ser, verbose=verbose))
24 changes: 24 additions & 0 deletions zmk_studio_cli/commands/combos/get_combos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright (c) 2025 The ZMK Contributors
# SPDX-License-Identifier: MIT

"""
get-combos
"""

import typer

from ...proto import studio_pb2 as studio
from ...rpc import rpc_get_response, rpc_handle_response, rpc_send_request


def combos_get_combos(ctx: typer.Context) -> None:
"""Get Combos"""
ser = ctx.obj.ser
verbose = ctx.obj.verbose

request = studio.Request()
request.request_id = 1
request.combos.get_combos = True

rpc_send_request(ser=ser, request=request, verbose=verbose)
rpc_handle_response(rpc_get_response(ser=ser, verbose=verbose))
42 changes: 42 additions & 0 deletions zmk_studio_cli/commands/combos/remove_layer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright (c) 2025 The ZMK Contributors
# SPDX-License-Identifier: MIT

"""
remove-layer
"""

from typing import Annotated

import typer

from ...proto import studio_pb2 as studio
from ...rpc import rpc_get_response, rpc_handle_response, rpc_send_request


def combos_remove_layer(
ctx: typer.Context,
combo_id: Annotated[
int,
typer.Argument(
help="Combo identifier",
),
] = None,
layer: Annotated[
int,
typer.Argument(
help="Layer",
),
] = None,
) -> None:
"""Remove layer from a combo"""
ser = ctx.obj.ser
verbose = ctx.obj.verbose

request = studio.Request()
request.request_id = 1
request.combos.set_combo_layer_state.id = combo_id
request.combos.set_combo_layer_state.layer = layer
request.combos.set_combo_layer_state.enabled = False

rpc_send_request(ser=ser, request=request, verbose=verbose)
rpc_handle_response(rpc_get_response(ser=ser, verbose=verbose))
42 changes: 42 additions & 0 deletions zmk_studio_cli/commands/combos/remove_position.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright (c) 2025 The ZMK Contributors
# SPDX-License-Identifier: MIT

"""
remove-position
"""

from typing import Annotated

import typer

from ...proto import studio_pb2 as studio
from ...rpc import rpc_get_response, rpc_handle_response, rpc_send_request


def combos_remove_position(
ctx: typer.Context,
combo_id: Annotated[
int,
typer.Argument(
help="Combo identifier",
),
] = None,
key_pos: Annotated[
int,
typer.Argument(
help="Key Position",
),
] = None,
) -> None:
"""Remove key position from a combo"""
ser = ctx.obj.ser
verbose = ctx.obj.verbose

request = studio.Request()
request.request_id = 1
request.combos.set_combo_position_state.id = combo_id
request.combos.set_combo_position_state.position = key_pos
request.combos.set_combo_position_state.enabled = False

rpc_send_request(ser=ser, request=request, verbose=verbose)
rpc_handle_response(rpc_get_response(ser=ser, verbose=verbose))
Loading