From fb5faafbc91c7779a7cae88bfe16652be6220df2 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Sun, 11 Sep 2022 10:19:16 +0200 Subject: keybinds --- client-web/source/chat.ts | 14 ++++------- client-web/source/index.ts | 2 ++ client-web/source/keybinds.ts | 27 ++++++++++++++++++++ client-web/source/menu.ts | 2 +- client-web/source/user/local.ts | 56 ++++++++++++++++++----------------------- readme.md | 11 +++++++- 6 files changed, 70 insertions(+), 42 deletions(-) create mode 100644 client-web/source/keybinds.ts diff --git a/client-web/source/chat.ts b/client-web/source/chat.ts index bafed73..70f8cd2 100644 --- a/client-web/source/chat.ts +++ b/client-web/source/chat.ts @@ -8,6 +8,7 @@ import { User } from "./user/mod.ts"; export class Chat extends OverlayUi { messages: HTMLElement controls: HTMLElement + send_el: HTMLInputElement constructor(public room: Room) { const send = document.createElement("input") @@ -20,6 +21,7 @@ export class Chat extends OverlayUi { super(ediv({ class: "chat" }, messages, controls)) this.messages = messages this.controls = controls + this.send_el = send send.onkeydown = (ev) => { if (ev.code == "Enter") { @@ -49,15 +51,9 @@ export class Chat extends OverlayUi { reader.readAsDataURL(blob); } } - document.body.addEventListener("keydown", ev => { - // TODO is there a proper solution? - if (ev.target instanceof HTMLInputElement && !(ev.target.type == "button")) return - if (ev.code == "Enter") { - this.shown = !this.shown - if (this.shown) send.focus() - ev.preventDefault() // so focused buttons dont trigger - } - }) + } + focus() { + this.send_el.focus() } send(msg: ChatMessage) { diff --git a/client-web/source/index.ts b/client-web/source/index.ts index f3c5adc..f9f7a5e 100644 --- a/client-web/source/index.ts +++ b/client-web/source/index.ts @@ -1,6 +1,7 @@ /// import { ediv, OVERLAYS } from "./helper.ts"; +import { setup_keybinds } from "./keybinds.ts"; import { log, LOGGER_CONTAINER } from "./logger.ts" import { BottomMenu, MenuBr } from "./menu.ts"; import { load_params, PREFS } from "./preferences/mod.ts"; @@ -38,6 +39,7 @@ export async function main() { const conn = await (new SignalingConnection().connect(room_name)) const r = new Room(conn) + setup_keybinds(r) r.on_ready = () => { new BottomMenu(r).shown = true new MenuBr().shown = true diff --git a/client-web/source/keybinds.ts b/client-web/source/keybinds.ts new file mode 100644 index 0000000..311b55a --- /dev/null +++ b/client-web/source/keybinds.ts @@ -0,0 +1,27 @@ +import { Room } from "./room.ts" + + +export function setup_keybinds(room: Room) { + let command_mode = false + document.body.addEventListener("keydown", ev => { + // TODO is there a proper solution? + if (ev.target instanceof HTMLInputElement && !(ev.target.type == "button")) return + if (ev.repeat) return + if (ev.code == "Enter") { + room.chat.shown = !room.chat.shown + if (room.chat.shown) room.chat.focus() + ev.preventDefault() // so focused buttons dont trigger + } + if (ev.code == "Space") { + command_mode = true + ev.preventDefault() // so focused buttons dont trigger + return + } + if (command_mode) { + if (ev.code == "KeyM") room.local_user.publish_track(room.local_user.create_mic_track()) + if (ev.code == "KeyC") room.local_user.publish_track(room.local_user.create_camera_track()) + if (ev.code == "KeyS") room.local_user.publish_track(room.local_user.create_screencast_track()) + } + command_mode = false + }) +} diff --git a/client-web/source/menu.ts b/client-web/source/menu.ts index 5aeeed5..25a5d9c 100644 --- a/client-web/source/menu.ts +++ b/client-web/source/menu.ts @@ -50,7 +50,7 @@ export class BottomMenu extends OverlayUi { if (prefs.shown) prefs_button.classList.add("active") else prefs_button.classList.remove("active") } - + super(ediv({ class: "bottom-menu" }, chat_toggle, prefs_button, room.local_user.create_controls())) } } diff --git a/client-web/source/user/local.ts b/client-web/source/user/local.ts index c58af2a..9b34dba 100644 --- a/client-web/source/user/local.ts +++ b/client-web/source/user/local.ts @@ -28,22 +28,10 @@ export class LocalUser extends User { ROOM_CONTAINER.removeChild(this.el) } - async add_initial_tracks() { - if (PREFS.microphone_enabled) this.publish_track(await this.create_mic_track()) - if (PREFS.camera_enabled) this.publish_track(await this.create_camera_track()) - if (PREFS.screencast_enabled) this.publish_track(await this.create_screencast_track()) - } - - publish_track(t: TrackHandle) { - this.room.remote_users.forEach(u => u.peer.addTrack(t.track)) - this.add_track(t) - t.addEventListener("ended", () => { - this.room.remote_users.forEach(u => { - u.peer.getSenders().forEach(s => { - if (s.track == t.track) u.peer.removeTrack(s) - }) - }) - }) + add_initial_tracks() { + if (PREFS.microphone_enabled) this.publish_track(this.create_mic_track()) + if (PREFS.camera_enabled) this.publish_track(this.create_camera_track()) + if (PREFS.screencast_enabled) this.publish_track(this.create_screencast_track()) } chat(message: ChatMessage) { @@ -65,23 +53,29 @@ export class LocalUser extends User { mic_toggle.value = "Microphone" camera_toggle.value = "Camera" screen_toggle.value = "Screencast" - - const create = async (_e: HTMLElement, tp: Promise) => { - log("media", "awaiting track") - let t; - try { t = await tp } - catch (_) { log("media", "request failed") } - if (!t) return - log("media", "got track") - this.publish_track(t) - } - - mic_toggle.addEventListener("click", () => create(mic_toggle, this.create_mic_track())) - camera_toggle.addEventListener("click", () => create(camera_toggle, this.create_camera_track())) - screen_toggle.addEventListener("click", () => create(screen_toggle, this.create_screencast_track())) - + mic_toggle.addEventListener("click", () => this.publish_track(this.create_mic_track())) + camera_toggle.addEventListener("click", () => this.publish_track(this.create_camera_track())) + screen_toggle.addEventListener("click", () => this.publish_track(this.create_screencast_track())) return ediv({ class: "local-controls" }, mic_toggle, camera_toggle, screen_toggle) } + async publish_track(tp: Promise) { + log("media", "awaiting track") + let t!: TrackHandle; + try { t = await tp } + catch (_) { log("media", "request failed") } + if (!t) return + log("media", "got track") + + this.room.remote_users.forEach(u => u.peer.addTrack(t.track)) + this.add_track(t) + t.addEventListener("ended", () => { + this.room.remote_users.forEach(u => { + u.peer.getSenders().forEach(s => { + if (s.track == t.track) u.peer.removeTrack(s) + }) + }) + }) + } async create_camera_track() { log("media", "requesting user media (camera)") diff --git a/readme.md b/readme.md index 943b9a6..03b2158 100644 --- a/readme.md +++ b/readme.md @@ -46,6 +46,15 @@ If you use this project or have any suggestions, please [contact me](https://met Because of a current compiler bug, the nightly rustc crashes during codegen - use the stable channel instead. +## Keybinds + +| Keybind | Action | +| ------- | -------------------- | +| `RET` | Toggle chat | +| `SPC M` | Add microphone track | +| `SPC C` | Add camera track | +| `SPC S` | Add screencast track | + ## Parameters Some configuration parameters can be added like query params but **after** the section. (e.g `/room#mymeeting?username=alice`) @@ -55,7 +64,7 @@ Booleans can be either `1`, `true`, `yes` or their opposites. I convenience func | Option name | Type | Default | Description | | -------------------------- | ------- | ----------- | -------------------------------------------------------------------- | | `username` | string | `"guest-…"` | Username | -| `warn_redirect` | boolean | `false` | Internal option that is set by a server redirect. | +| `warn_redirect` | boolean | `false` | Internal option that is set by a server redirect. | | `image_view_popup` | boolean | `true` | Open image in popup instead of new tab | | `microphone_enabled` | boolean | `false` | Add one microphone track on startup | | `screencast_enabled` | boolean | `false` | Add one screencast track on startup | -- cgit v1.2.3-70-g09d2