Desk Clarity

Everyday document & browser help

Writer character spacing macro: adjust the left character and check rounding

By ON Lab · Sources checked November 8, 2026

For repeated character-spacing changes at a Writer caret, change the spacing property of the single character immediately to its left. Reading the current value and adding a step is different from repeatedly setting a fixed value. Check the application's numeric readback too: our native test showed small rounding drift after opposite adjustments.

A reader's recorded macro always set the same spacing. The discussion eventually narrowed the range to the left character, because selecting both letters also affected spacing after the right one. We tested an original guarded helper with a native Writer view cursor, including paragraph starts, selected text, neighboring properties and repeated numeric updates.

What the native test actually changed

Our original body text was We To, followed by a second paragraph. We placed the caret between W and e. The helper created an independent text cursor selecting only W, read its CharKerning value and requested the next value.

After the first two decreasing calls, W's readback changed while e's CharKerning remained zero. The helper did not change the body's text. W's previously assigned bold weight and color were retained. This checks property scope, not a visual measurement of the font or every following glyph position.

We used LibreOffice 26.8.2.2 on macOS 27.2 arm64, with an isolated profile and native view-cursor calls. We did not test actual keyboard assignment, graphical dialog clicks, headers, footnotes or complex Unicode grapheme movement. The reader's environment was LibreOffice 26.2.1.2 on Windows 10.

Use requested steps, not an assumed point size

Writer's current release source maps CharKerning through a conversion between hundredths of a millimetre and integer twips. A requested step of 20 in this property is 0.20 mm, not 20 points. Do not assume that a similarly named parameter in a recorded dispatch macro has an interchangeable numeric unit.

The conversion also means a requested value and its readback need not be identical. Starting from an observed zero, our test gave these results:

Request applied to current readbackW readback afterwards
Add −20−19
Add −20 again−39
Add +20−19
Add +20 again2

Thus two opposite pairs did not return the inspected property to exactly zero. Explicitly restoring zero did read back zero in our fixture. Treat incremental changes as live adjustments and inspect the result; do not promise exact numeric reversibility by pressing the opposite shortcut the same number of times.

A helper restricted to a collapsed caret

Review the code in a separate Basic module and test it on a disposable Writer copy through your normal trusted-macro workflow. The two small wrappers supply opposite requested steps. The helper deliberately rejects selected text rather than applying a single value across a mixed selection.

Sub DecreaseBeforeCaret
 Dim status As String
 status = AdjustLeftCharacter(ThisComponent, -20)
 If status <> "changed" Then MsgBox status
End Sub

Sub IncreaseBeforeCaret
 Dim status As String
 status = AdjustLeftCharacter(ThisComponent, 20)
 If status <> "changed" Then MsgBox status
End Sub

Function AdjustLeftCharacter(doc As Object, stepValue As Long) As String
 Dim vc As Object, tc As Object, oldValue As Long, newValue As Long
 AdjustLeftCharacter = "unsupported document or position"
 If Not doc.supportsService("com.sun.star.text.TextDocument") Then Exit Function
 vc = doc.CurrentController.getViewCursor()
 If Not vc.isCollapsed() Then
  AdjustLeftCharacter = "place a caret, not a selection"
  Exit Function
 End If
 tc = vc.Text.createTextCursorByRange(vc)
 If tc.isStartOfParagraph() Then
  AdjustLeftCharacter = "no character before this paragraph position"
  Exit Function
 End If
 If Not tc.goLeft(1, True) Then Exit Function
 If tc.String = "" Then Exit Function
 If Not tc.getPropertySetInfo().hasPropertyByName("CharKerning") Then Exit Function
 If tc.getPropertyState("CharKerning") = 2 Then
  AdjustLeftCharacter = "ambiguous character spacing"
  Exit Function
 End If
 oldValue = CLng(tc.CharKerning)
 newValue = oldValue + stepValue
 If newValue < -32768 Or newValue > 32767 Then
  AdjustLeftCharacter = "spacing is outside the supported short range"
  Exit Function
 End If
 tc.CharKerning = CInt(newValue)
 AdjustLeftCharacter = "changed"
End Function

The numeric property-state value 2 means an ambiguous value. The helper also checks that the optional property exists and that the requested value fits the property's signed-short range. Those guards do not establish that extreme spacing is useful or visually acceptable; choose a modest step for the actual text.

Why the paragraph-start check matters

A blind move left can fail at the start of a document or reach a preceding paragraph boundary. The helper checks the paragraph position before selecting a character. In our native controls, it refused both the start of the first paragraph and the start of the second, and the second paragraph's first character retained its original spacing.

A nonempty selection was also rejected. In the range-boundary control, the helper refused an out-of-range request and retained the existing readback. These are bounded tests of the original ASCII body fixture, not proof for every script, field, embedded object or text container.

Assign the wrappers only after checking the action

Writer's official keyboard customization guide describes selecting a function or macro, a shortcut and the assignment scope. After the two wrapper actions work as intended on a copy, assign them through that interface and verify the actual keys in your version.

The native test exercised the helper directly. It did not establish that a particular key is free on your operating system, that an assignment was saved, or that a shortcut works in a different document context. Check the resulting character's spacing and the character to its right after using the key.

Keep the caret at the intended gap for repeated adjustments. A collapsed caret at a different location selects a different preceding character. A selected range is outside this helper's contract and returns a message instead of silently flattening its spacing values.

Keep a before-and-after check

  1. Start with a short copy containing the intended letter pair and a nearby pair that should retain its own spacing property.
  2. Record the initial value and the caret position.
  3. Run one decreasing action, inspect the range, and repeat once to confirm it accumulates.
  4. Try the opposite action and check the actual numeric readback.
  5. Test the paragraph start and a selection to confirm the refusal behavior.
  6. Save the working copy, reopen it and inspect the visible result before applying the method to a larger document.

This is manual character spacing through a character property. It does not edit a font's automatic pair-kerning table, and the native property test does not judge whether a particular pair looks right. Preserve a source copy when exact restoration matters, especially because the observed conversions can produce small numeric drift.

Sources