How to Select Candidates Using Number Keys 1‑9, Enter, and Space in Hallelujah IM
Hallelujah IM selects candidates by mapping digit keys 1‑9 to indices in the _candidates array, then commits the chosen word immediately with commitComposition: (Space) or commitCompositionWithoutSpace: (Enter).
The open‑source input method dongyuwei/hallelujahim provides a streamlined typing experience where users generate phonetic or abbreviated candidates and finalize them with minimal keystrokes. Understanding the keyboard interaction model in src/InputController.mm reveals how the engine translates number pad selections into committed text.
Candidate Generation in ConversionEngine
Before selection can occur, the system must populate the candidate list. The ConversionEngine class in src/ConversionEngine.mm (lines 182‑200) generates suggestions via the getCandidates: method.
The pipeline lower‑cases the input buffer, expands user‑defined substitutions, queries the Marisa trie for prefix matches, and sorts results by frequency. When the trie returns no matches, the engine falls back to spell‑checker and phonex suggestions. The resulting array is stored in _candidates, a mutable array exposed to the controller.
Number Key Selection (1‑9) Logic
When the candidate window is visible (isCandidatesVisible), the onKeyEvent: method intercepts digit keys ('0'‑'9') in src/InputController.mm (lines 153‑168).
The controller calculates the target index using zero‑based arithmetic:
if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:ch]) {
if (isCandidatesVisible) {
int pressedNumber = characters.intValue;
NSString *candidate;
int pageSize = 9;
if (_currentCandidateIndex <= pageSize) {
candidate = _candidates[pressedNumber - 1];
} else {
candidate = _candidates[pageSize * (_currentCandidateIndex / pageSize - 1)
+ (_currentCandidateIndex % pageSize) + pressedNumber - 1];
}
[self cancelComposition];
[self setComposedBuffer:candidate];
[self setOriginalBuffer:candidate];
[self commitComposition:sender];
return YES;
}
}
The selected candidate replaces the composition buffer and is committed instantly.
Pagination Handling
The logic distinguishes between single‑page and multi‑page lists. When _currentCandidateIndex exceeds the pageSize of 9, the index calculation offsets by the current page (pageSize * (page‑1)) to ensure digit keys map correctly across pagination boundaries.
Committing Candidates with Enter and Space
After a candidate is chosen—or when the user accepts the raw buffer without selecting from the list—two keys handle finalization differently.
Enter Key Behavior
Pressing Enter (KEY_RETURN) commits the composition without appending a trailing space. This is useful when the user already typed a separator or wants to continue typing immediately after the word.
// src/InputController.mm – lines 106‑112
if (keyCode == KEY_RETURN && hasBufferedText) {
[self commitCompositionWithoutSpace:sender];
}
Space Key Behavior
Pressing Space (KEY_SPACE) commits the composition with a trailing space (default behavior), allowing rapid entry of multiple words.
// src/InputController.mm – lines 98‑104
if (keyCode == KEY_SPACE && hasBufferedText) {
[self commitComposition:sender];
}
Complete Selection Flow
The end‑to‑end candidate selection pipeline works as follows:
- Input buffering –
onKeyEvent:appends keystrokes tooriginalInputand triggers[sharedCandidates updateCandidates]. - List population – The
candidates:method invokes[engine getCandidates:originalInput]and stores the result in_candidates. - Window display –
[sharedCandidates show:kIMKLocateCandidatesBelowHint]renders the list. - Digit selection – While
isCandidatesVisibleis true, keys 1‑9 map to_candidatesindices and immediately commit viacommitComposition:. - Finalization – Enter or Space handles cases where the user accepts the buffer without explicit candidate selection, differing only in whitespace handling.
Summary
src/ConversionEngine.mmgenerates ranked candidates using trie lookups, frequency sorting, and fallback spell‑checking.src/InputController.mmmanages the UI state, intercepts digit keys 1‑9, and maps them to the_candidatesarray with pagination‑aware index math.- Number keys 1‑9 commit the selected candidate immediately, replacing the composition buffer.
- Enter (
KEY_RETURN) finalizes text without trailing spaces, while Space (KEY_SPACE) appends a space after commitment. - The default page size is 9 candidates, and the selection logic adjusts indexing when multiple pages exist.
Frequently Asked Questions
How does Hallelujah IM handle candidate pagination?
When more than 9 candidates exist, the controller tracks _currentCandidateIndex and calculates the effective index as pageSize * (page‑1) + pressedNumber‑1. This ensures digits 1‑9 consistently map to the visible slice of the _candidates array regardless of which page is displayed.
What happens when I press Enter vs Space?
Pressing Enter invokes commitCompositionWithoutSpace:, inserting the candidate without trailing whitespace. Pressing Space invokes commitComposition:, which inserts the candidate followed by a space. Both actions clear the composition buffer and hide the candidate window.
Where is the candidate selection logic implemented?
The primary selection logic resides in src/InputController.mm within the onKeyEvent: method (lines 153‑168). Candidate generation occurs in src/ConversionEngine.mm via getCandidates: (lines 182‑200). These files define the complete pipeline from keystroke to committed text.
Can I customize the number of candidates shown per page?
The source code defines pageSize as a fixed integer (9) within the digit‑key handling block in src/InputController.mm. Modifying this constant requires recompiling the project, as the value is hardcoded for the 1‑9 number key mapping.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →