Skip to content

feat: add forbidden characters to @ConfigEditorText#72

Open
Knixxx wants to merge 4 commits intoNotEnoughUpdates:v4from
Knixxx:v4
Open

feat: add forbidden characters to @ConfigEditorText#72
Knixxx wants to merge 4 commits intoNotEnoughUpdates:v4from
Knixxx:v4

Conversation

@Knixxx
Copy link

@Knixxx Knixxx commented Mar 14, 2026

Summary

the problem:
while coding myself i noticed that the @ConfigEditorText annotation does check for the presence of a '§' within the textfield and blocks it accordingly, but only if it was typed by hand. if it is pasted, the clipboard content simply gets written as it is.

you can see the behavior in TextFieldComponent:

// ...
KeyboardConstants.keyV -> if (context.renderContext.isLogicalCtrlDown) {
    writeText(IMinecraft.INSTANCE.copyFromClipboard(), context.width)
    return true
}
// ...

that means, if we would like to copy a '§' and paste it inside of a textfield it would just get placed and you can use color codes inside of the textfield.

image
Figure 1: Example of Color Codes inside a TextField

this behavior is not intended, as it could potentially cause bugs, if we would like to read from our text variable, where the content gets stored and build something off of that (e.g. we want to write the content of the textfield in the chat).

therefore i added forbidden as a parameter to @ConfigEditorText.

public @interface ConfigEditorText {
    /**
     * @return set forbidden characters as a string, e.g. "§z" for '§' and 'z' to disable them from being allowed to write inside the text field
     */
    String forbidden() default "§";
}

its purpose is to block any given characters from being pasted in the textfield.
following i modified the writeText method in TextFieldComponent as follows:

fun writeText(s: String, width: Int) {
    val filteredString = s.filter { it !in forbiddenChars }

    if (filteredString.isEmpty() && s.isNotEmpty()) return
    // ...
}

we filter the text, that's to be written and remove all forbidden characters. if the string is empty after filtering, we just cancel the event. there is an exception though, if we press backspace, the writeText method gets called with an empty string already, and thus we don't want to cancel the event (s has to be not empty, otherwise the writeText method proceeds).
after filtering we use filteredString to set our text, instead of s:
e.g.:

// prior:
text.set(safeSubString(t, 0, cursor) + s + safeSubString(t, cursor))

// after: 
text.set(safeSubString(t, 0, cursor) + filteredString + safeSubString(t, cursor))

this prevents pasting forbidden chars, but to prevent typing them i modified the CharTyped event branch as follows:

// ...
else if (event is KeyboardEvent.CharTyped) {
    val it = event.char

    if (it < ' ' || it.code == 127) return false

    // consume event, so we don't write into the searchbar the moment we type a forbidden char
    if (forbiddenChars.contains(it)) return true

    writeText(it + "", context.width)
    return true
} else {
    return false
}

i consciously consume the event, if we type a forbidden character, so we don't always focus the searchbar, as soon as we type one. we just stay inside of the textfield.
i removed the hardcoded version of the previously cancellation of the '§' character:

// ...
if (it >= ' ' && it != '§' && it.code != 127) {
    writeText(it + "", context.width)
    anyWritten = true
}
// ...

and replaced it with the standard forbidden character (which gets checked as well by default):

String forbidden() default "§";

now the user has the option to set forbidden character itself, and the standard forbidden one is really forbidden.

to present this i added to the TestCategoryA:

// ...
@ConfigOption(name = "Text Box", desc = "Lets you put strings.")
@ConfigEditorText(forbidden = "§z")
var customText: Property<String> = Property.of("abc")
// ...

the forbidden character '§' and 'z'.
notice, that when you set forbidden character yourself, the default one ('§') gets overridden and is not forbidden anymore by default. (you have to add it manually again, if still needed).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant