Java2D on X11 (and so under XWayland) truncates its scale to a whole
number, drawing 150 % at 100 %. On Linux, pin Java2D to 1 and hand the
full factor to FlatLaf, taken from XSETTINGS Xft/DPI, KWin's Xwayland
scale or GDK_SCALE, or chosen in Options → Design.
The client's own sizes now go through UIScale: borders, gaps, dialog and
row sizes, icons (rendered at the scaled size, so they stay crisp),
custom-painted components and font sizes in the HTML views.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Avatars are fetched from the server's file repository as /avatar_<id>,
verified against client_flag_avatar and cached on disk; animated GIFs play in
the info panel. Self > Set avatar... uploads or removes our own picture within
the server's size limit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The official client keeps what a myTeamSpeak account synchronises as protobuf
Item_Data blobs in the ProtobufItems table of settings.db. Decode them, adopt
them on first run when we have no identity yet, and offer a re-import from
Manage Bookmarks and Identities. The settings.db reader moves from contacts to
a new teamspeak package.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mirrors the TeamSpeak 3 client's Contacts: clients can be filed as friend,
blocked or neutral from their context menu or by dragging them into the
Contacts window, given a custom and phonetic nickname, shown under either
name or both, and per contact muted automatically, ignored in server/channel
or private chat and pokes, have their away message hidden and whispers
allowed or denied. Friends are green and blocked clients red in the tree
(optional), new contacts start from per-type defaults ("Set Defaults"), and
the global whisper policy lives in Options -> Contacts. "Change Volume..."
adds a per-client dB gain that a contact entry remembers.
Contacts are stored in ~/.ts3jclient/contacts.txt using the exact record
format the official client keeps in the Contacts table of its settings.db
(field names and codes recovered from the binary), so entries move between
the two verbatim. A small read-only pure-Java SQLite reader imports the
official client's list on first run and on demand, without a driver.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reimplements the official client's ban list: a searchable table of the
server's bans with Add / Remove / Edit, an own-ban filter and highlight,
choosable columns, and the Add/Edit dialog whose IP and name patterns
can be read as IPv4/IPv6 wildcards, fixed strings or regular expressions
(translated to the regexes banadd takes exactly as the official client
does). Editing is add-then-delete, since the protocol has no banedit.
The ban list is read from the notifybanlist burst that answers banlist,
like channelpermlist. The menu item is only shown where the server grants
b_client_ban_list.
Also fixes ServerModel numbering permissions from 0 instead of 1, which
had every selfPermissionValue() lookup reading the neighbouring
permission — including the group-assignment menus.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A message-only window registers the keyboard and mouse with
RIDEV_INPUTSINK, so every key and button arrives as WM_INPUT whether or
not the client is in front. Raw input only observes, where a
WH_KEYBOARD_LL hook sits in the path of the system input queue and can
swallow a keystroke; it also reports the side buttons and both edges of
every key, which push-to-talk needs.
Keyboard codes stay in each platform's own numbering — X keycodes on
X11, set-1 scan codes with the E0/E1 escape folded into the high byte on
Windows — since that is what the input API reports and the key-naming
call expects. Bindings are per-machine either way, as TeamSpeak's own
per-OS keydefs are. Mouse buttons are unified on the X numbering, so
"Mouse 4" means the same thing on both.
The RAWINPUT decoding lives in its own class so it can be tested off
Windows; the window and its pump have not been run on Windows yet.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The bundled TS3 Linux binary dlopens libX11 and libXi and drives
XIQueryVersion/XISelectEvents/XGetEventData — XInput2 raw events, with no
trace of the RECORD extension anywhere in its tree. That is the better
choice for us too: XInput2 is core input, present on any remotely modern
server, where RECORD is a debugging extension that is sometimes disabled
or left out of the build. Both are passive, so the keystroke still
reaches the focused window either way.
XRecordInputHook stays as the fallback behind it. Raw events also explain
why TS3's hotkeys work under KWin's Wayland session despite it using no
Wayland API at all: it runs on Xwayland, and KWin's legacy X11 app
support forwards the keys.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bindings are captured system-wide rather than only while the window has
focus: X11's RECORD extension where the X server sees every key, and a
/dev/input reader as the Wayland fallback. Any key can act as a modifier,
mouse buttons included, as TS3 allows.
The action catalogue, its three categories and the "advanced actions"
split are reverse-engineered from the original client; actions this
client cannot perform are listed but greyed out. Push-to-talk becomes one
of these hotkeys, so the old focus-bound pushToTalkKey setting is gone and
the Voice Activation button edits that binding instead.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Icon packs are read in TeamSpeak's own format — a zip (or unpacked folder)
of SVG/PNG art plus a settings.ini mapping icon keys to files — so the packs
of an installed client and the ones from its add-on site work unchanged.
Legacy packs without that mapping (default.zip) are resolved by their file
naming convention instead, picking the resolution closest to the drawn size.
The pack draws the tree, toolbar, menus, context menus, file browser and the
default group icons; a pack's FALLBACK option decides whether what it lacks
comes from default.zip, and anything still missing falls back to the icons
the client draws itself. Options → Design picks the pack and shows a viewer
of everything in it.
Vector art is rasterised with JSVG, and the pack search roots are shared
with the sound packs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds TeamSpeak-format sound packs: a folder of waves plus a settings.ini
mapping actions to play()/say() entries, with ${clientType} and friends
resolved per event. Packs are found in the client's own sound folder, an
installed TS3 client and a folder of the user's choosing, so the official
packs work unchanged.
Each action can be switched off or marked important; important actions are
the only ones still played while the speakers are muted, as in TS3. The new
Notifications options page lists them by category, greys out what the active
pack has no sound for, and previews on double-click.
Sounds are decoded, resampled and mixed onto a single playback line that is
only open while something plays, so overlapping events never fight over the
device.
Fires the events from the protocol layer, following TeamSpeak's own
distinctions: reason ids separate switched/moved/kicked/banned/timed out,
and visibility decides appears/disappears/stays.
Also fixes a ts3j trap in the process: a field an event never carried reads
back as an empty string, so the existing "e.get(x) != null" checks were
always true. That made a partial clientupdate (someone muting) announce a
stopped recording, and it let a nickname-only update reset another client's
mute/away flags and talk power, or a channel edit blank the channel name.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bind libopus through java.lang.foreign downcall handles instead of JNA:
the ctl functions are linked with firstVariadicArg(2), and the encoder and
decoder each own a shared Arena holding the handle plus reusable native
PCM/packet buffers, so the hot path only allocates the returned packet.
The library is resolved by system SONAME first, falling back to a bundled
copy extracted from the JAR. Only the Windows x86-64 build is packaged by
default now (-Dnatives.all restores all platforms), since every other
platform ships libopus through its package manager.
Requires Java 26.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Manage several TeamSpeak identities like the official client instead of
using one auto-generated identity file.
- IdentityStore/IdentityEntry keep each identity as a TeamSpeak-format INI
in ~/.ts3jclient/identities, so files interchange with the TS3 client;
supports create, import, export, rename, remove and a cancellable
security-level search. A legacy identity.ini is migrated in on first load.
- Settings hold the default identity; bookmarks may pin their own, falling
back to the default when unset.
- TeamspeakConnection now connects with the identity it is handed.
- Swing: Tools -> Identities manager, plus an identity drop-down in the
connect and bookmark forms.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Swing desktop client (core/desktop/swing Maven modules) built on the
ts3j protocol library, included as a submodule. Native Opus voice with
voice-activation detection, push-to-talk, and audio pre-processing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>