# How the Shift Key Toggles Smart and Traditional English Mode in Hallelujah IM

> Learn how the Shift key toggles Hallelujah IM between smart and traditional English modes. Understand how keystrokes pass directly to macOS or buffer for conversion.

- Repository: [dongyuwei/hallelujahim](https://github.com/dongyuwei/hallelujahim)
- Tags: internals
- Published: 2026-02-28

---

**Pressing and releasing the Right Shift key toggles Hallelujah IM between Smart English mode, which passes keystrokes directly to macOS, and Traditional Chinese mode, which buffers characters for conversion.**

The hallelujahim input method for macOS implements a dedicated Right Shift shortcut that allows users to instantly switch between input behaviors without changing system input sources. This mechanism is controlled by the `_defaultEnglishMode` boolean flag in `src/InputController.mm`, determining whether the IME intercepts alphabetic keys or lets the operating system handle them directly.

## The Toggle Logic in InputController.mm

The shift toggle is implemented inside the `-handleEvent:client:` method in `src/InputController.mm`. This method receives both **key-down** events and **modifier-flag-changed** events, monitoring specifically for the release of the Right Shift key to trigger the mode switch.

The code validates a precise sequence of conditions before flipping the state:

```objc
// src/InputController.mm, lines 39-44
if (modifiers == 0 &&
    _lastEventTypes[1] == NSEventTypeFlagsChanged &&
    _lastModifiers[1] == NSEventModifierFlagShift &&
    event.keyCode == KEY_RIGHT_SHIFT &&
    !(_lastModifiers[0] & NSEventModifierFlagShift)) {

    _defaultEnglishMode = !_defaultEnglishMode;          // toggle flag

```

The logic verifies that:
- The current event reports **no active modifiers** (`modifiers == 0`)
- The **previous event was a Shift press** (`_lastModifiers[1] == NSEventModifierFlagShift`)
- The keyCode matches **Right Shift** (`KEY_RIGHT_SHIFT`, defined as `60`)
- **Left Shift is not currently held** (`!(_lastModifiers[0] & NSEventModifierFlagShift)`)

When all conditions are satisfied, the `_defaultEnglishMode` boolean is inverted. A value of `YES` activates Smart English mode, while `NO` restores Traditional Chinese conversion.

## Committing Pending Text When Enabling Smart English

When the toggle switches to Smart English mode (`_defaultEnglishMode` becomes `YES`), the IME immediately commits any pending Chinese composition to prevent data loss:

```objc
if (_defaultEnglishMode) {
    NSString *bufferedText = [self originalBuffer];
    if (bufferedText && bufferedText.length > 0) {
        [self cancelComposition];
        [self commitComposition:sender];             // flush pending Chinese text
    }
}

```

This ensures that buffered characters are inserted into the document before the IME stops intercepting subsequent keystrokes.

## How the Mode Flag Controls Input Processing

Later in the same `-handleEvent:client:` method, the `_defaultEnglishMode` flag determines processing for alphabetic key-down events:

```objc
// src/InputController.mm, lines 53-56
case NSEventTypeKeyDown:
    if (_defaultEnglishMode) {
        break;                // bypass the conversion pipeline
    }

```

- **Smart English mode (`YES`)**: Execution hits the `break` statement immediately, returning control to macOS. Characters appear directly without triggering candidate windows.
- **Traditional mode (`NO`)**: Execution continues into the conversion pipeline, where the IME buffers keystrokes and displays Chinese/English candidate suggestions.

## Why Only the Right Shift Key Works

The implementation explicitly restricts this shortcut to the **Right Shift key only** by checking `event.keyCode == KEY_RIGHT_SHIFT`. Left Shift uses a different keyCode and is intentionally excluded to prevent accidental toggles during normal typing when users hold Shift for capitalization.

This design choice ensures that standard capitalization habits (Left Shift) do not trigger unwanted mode switches, while keeping the toggle accessible via the less frequently used Right Shift key.

## Practical Usage and Mode Detection

When using Hallelujah IM, the Right Shift toggle operates as follows:

| Action | Result |
|--------|--------|
| Press **Right Shift** (release) | Switches to *Smart English* – alphabetic keys pass through directly. |
| Press **Right Shift** again | Switches back to *Traditional* – Chinese conversion resumes. |
| Type while in *Smart English* | Characters appear immediately without candidate windows. |
| Type while in *Traditional* | Characters buffer and trigger candidate selection. |

To programmatically check the current mode from within the controller, inspect the `_defaultEnglishMode` property:

```objc
- (void)checkCurrentMode {
    BOOL isSmartEnglish = _defaultEnglishMode;
    NSLog(@"Current mode: %@", isSmartEnglish ? @"Smart English" : @"Traditional Chinese");
}

```

## Summary

- **Right Shift release** toggles the `_defaultEnglishMode` flag in `src/InputController.mm` via the `-handleEvent:client:` method.
- **Smart English mode** bypasses the conversion pipeline entirely, letting macOS handle keystrokes directly without IME interception.
- **Traditional mode** activates the full IME pipeline with character buffering and candidate selection.
- The toggle specifically requires **Right Shift (keyCode 60)** to avoid conflicts with standard capitalization using Left Shift.
- When switching to Smart English, any pending Chinese text in the composition buffer is automatically committed before passthrough begins.

## Frequently Asked Questions

### What happens to unfinished Chinese text when I press Right Shift?

When you toggle into Smart English mode, Hallelujah IM automatically commits any pending composition. The code calls `[self commitComposition:sender]` to flush the buffer, ensuring your typed Chinese characters are inserted before the IME stops intercepting keys.

### Why doesn't Left Shift toggle the input mode?

The implementation explicitly checks for `event.keyCode == KEY_RIGHT_SHIFT` (value `60`). Left Shift uses a different keyCode and is intentionally excluded to prevent accidental mode switches during normal typing when users hold Shift for capitalization.

### How do I know which mode I'm currently in?

There is no built-in visual indicator in the provided source code, but you can detect the mode programmatically by checking the `_defaultEnglishMode` boolean in `InputController`. When `YES`, you are in Smart English mode; when `NO`, you are in Traditional Chinese conversion mode.

### Can I disable the Shift toggle functionality?

According to the source implementation in `src/InputController.mm`, the Shift toggle is hardcoded in the `-handleEvent:client:` method. To disable it, you would need to modify the source code and remove or comment out the conditional block that checks for `KEY_RIGHT_SHIFT` and toggles `_defaultEnglishMode`.