# LangOver - Keyboard Layout Converter for macOS

A menu bar utility that converts text between keyboard layouts with a global hotkey.

## 🎯 What This App Does

LangOver solves a common problem: you typed text in the wrong keyboard layout (e.g., you typed in English while your keyboard was set to Hebrew). Instead of retyping everything, press **Ctrl+Shift+Space** and LangOver will automatically convert the text to the correct layout.

**Example:**
- You type: `akuo` (while keyboard is on Hebrew layout)
- You press: **Ctrl+Shift+Space**
- LangOver converts it to: `שלום` (Hebrew for "hello")

## 📋 Requirements

- **macOS 13.0 (Ventura) or later**
- **Xcode 15.0 or later**
- **Accessibility permission** (the app will guide you through granting this)

---

## 🚀 Setup Instructions (Step-by-Step)

### Step 1: Open the Project in Xcode

1. Open **Xcode**
2. Open your existing project (LangToLang)
3. You should now see all the new files listed on the left side

---

### Step 2: Add the KeyboardShortcuts Package

This external library makes global hotkeys safe and easy to manage.

1. In Xcode, go to: **File → Add Package Dependencies...**
2. In the search box (top-right), paste this URL:
   ```
   https://github.com/sindresorhus/KeyboardShortcuts
   ```
3. Click **"Add Package"**
4. Select **"KeyboardShortcuts"** from the list
5. Click **"Add Package"** again

---

### Step 3: Configure the Project Settings

#### A. Change the App Name and Behavior

1. Click on the **blue project icon** at the very top of the file list (it says "LangToLang")
2. In the **General** tab:
   - Change **"Display Name"** to: `LangOver`
   - Under **"Deployment Info"**, set **"Minimum Deployment"** to: `macOS 13.0`

#### B. Add Required Capabilities

1. Click the **"Signing & Capabilities"** tab (next to General)
2. Click **"+ Capability"** button (top-left of the main panel)
3. Add: **"App Sandbox"**
4. In the App Sandbox section that appears, check: ✓ **Accessibility**
5. Click **"+ Capability"** again
6. Add: **"Hardened Runtime"**

#### C. Configure Info.plist

1. In the file list on the left, find and click **"Info.plist"**
2. Right-click anywhere in the property list → **"Open As" → "Source Code"**
3. **Replace all the content** with the Info.plist file I created (already done in the files above)
4. **Important**: We need to set the app as a "menu bar only" app:
   - In the file list, click on the **blue project icon** again
   - Click on the **"Info"** tab
   - Click the **"+" button** next to "Custom macOS Application Target Properties"
   - Add a new property:
     - **Key**: `Application is agent (UIElement)`
     - **Type**: Boolean
     - **Value**: YES

---

### Step 4: Update the Main App File

The existing app file needs to be replaced with our new one.

1. In the file list, find a file called something like **"LangToLangApp.swift"** (the one with `@main`)
2. **Delete it** (right-click → Delete → Move to Trash)
3. Our new **LangOverApp.swift** will be the main entry point

---

### Step 5: Build and Run

1. In Xcode, select **"My Mac"** as the destination (top-left, next to the play button)
2. Click the **▶️ Play button** (or press Cmd+R)
3. The app should build and run

#### What to Expect:

1. **First Launch Dialog**: You'll see a window showing all detected keyboard layouts
   - All keyboards are pre-selected
   - You can uncheck any, but must keep at least 2
   - Click **"Continue"**

2. **Accessibility Permission Alert**: You'll see a dialog asking for permission
   - Click **"Open System Settings"**
   - In System Settings, find **"LangOver"** in the Accessibility list
   - Toggle the switch to **ON**

3. **Menu Bar Icon**: Look at the top-right of your screen
   - You should see a new icon (looks like "abc")
   - Click it to see the menu

---

## 🎮 How to Use LangOver

### Converting Text

1. **In any app** (Mail, Notes, Word, browser, etc.):
   - Type some text in the wrong keyboard layout
   - **Either**:
     - Select the text you want to convert, OR
     - Just place your cursor at the end of the text
   - Press **Ctrl+Shift+Space**
   - The text will be converted instantly!

### Menu Bar Controls

Click the **LangOver icon** in the menu bar to access:

- **Enable/Disable**: Pause the hotkey listener temporarily
- **Current keyboard pair**: Shows which layouts you're converting between (e.g., "U.S. ↔ Hebrew")
- **Preferences**: Open settings to change keyboards, hotkey, or startup behavior
- **Quit**: Close the app

### Preferences Window

Click **"Preferences"** in the menu to:

- ✅ **Select Keyboards**: Check/uncheck which keyboard layouts to use (minimum 2)
- ⌨️ **Change Hotkey**: Click the recorder and press your preferred key combination
- 🚀 **Start at Login**: Toggle whether LangOver starts when you log in

---

## 🔧 Technical Details

### File Structure

```
LangOver/
├── LangOverApp.swift          // App entry point
├── AppDelegate.swift          // Menu bar, hotkey, lifecycle
├── Settings.swift             // UserDefaults storage
├── KeyboardLayout.swift       // Keyboard model
├── KeyboardDetector.swift     // Detects installed keyboards
├── LayoutConverter.swift      // Text conversion logic
├── AccessibilityService.swift // Reads/writes text in other apps
├── HotkeyService.swift        // Global hotkey management
├── FirstLaunchView.swift      // First-run keyboard selection
├── PreferencesView.swift      // Settings window
└── ContentView.swift          // Unused (kept for future use)
```

### How It Works

1. **Global Hotkey**: Uses the `KeyboardShortcuts` library to listen for Ctrl+Shift+Space
2. **Accessibility API**: Uses macOS Accessibility APIs (`AXUIElement`) to:
   - Read selected text from any app
   - Read text from cursor to line break
   - Replace text with converted version
3. **Text Conversion**: Pure character mapping (no AI, no internet)
   - Detects if text is English or Hebrew
   - Maps each character to its equivalent on the other layout
   - Example: "a" on Hebrew keyboard → "ש"

### Supported Layouts (MVP)

Currently supports **English ↔ Hebrew** bidirectional conversion.

**To add more layouts:**
1. Open `LayoutConverter.swift`
2. Add new conversion functions (like `convertEnglishToRussian`)
3. Update the character mapping dictionaries

---

## 🔒 Privacy & Security

- ✅ **100% Local**: All text conversion happens on your Mac
- ✅ **No Network**: The app never connects to the internet
- ✅ **No Logging**: Your typed text is never stored or logged
- ✅ **Open Source**: All code is visible and auditable

---

## ⚠️ Troubleshooting

### "Hotkey doesn't work"

1. Check if Accessibility permission is granted:
   - Open **System Settings → Privacy & Security → Accessibility**
   - Make sure **LangOver** is in the list and toggled **ON**
2. Check if the app is enabled:
   - Click the menu bar icon
   - Make sure it says **"Disable"** (meaning it's currently enabled)

### "Can't replace text in certain apps"

Some apps (especially web browsers with certain fields) don't allow text replacement via Accessibility APIs. This is a security feature of macOS. LangOver will beep to indicate it couldn't replace the text.

### "App doesn't appear in menu bar"

1. Make sure you set `LSUIElement` to `YES` in Info.plist
2. Try restarting the app
3. Check the top-right corner of your screen (it might be hidden under the notch on newer Macs)

### "Build errors about missing imports"

Make sure you added the **KeyboardShortcuts** package (see Step 2 above).

---

## 🎨 Customization Ideas

### Change the Menu Bar Icon

In `AppDelegate.swift`, find this line:
```swift
let image = NSImage(systemSymbolName: "textformat.abc", accessibilityDescription: "LangOver")
```

Replace `"textformat.abc"` with any SF Symbol name, like:
- `"globe"`
- `"keyboard"`
- `"character.textbox"`

### Change the Default Hotkey

In `Settings.swift`, find this line:
```swift
static let toggleConversion = Self("toggleConversion", default: .init(.space, modifiers: [.control, .shift]))
```

Change `.space` to another key like:
- `.keyL` (for the L key)
- `.f1` (for F1 key)

Change modifiers like:
- `[.command, .shift]` (for Cmd+Shift)
- `[.option, .command]` (for Opt+Cmd)

---

## 📦 Building for Distribution

To share the app with others:

1. **Archive the app**:
   - In Xcode: **Product → Archive**
   - Wait for the archive to complete
   - Click **"Distribute App"**
   - Choose **"Copy App"**

2. **Notarize** (optional, but recommended):
   - This requires an Apple Developer account ($99/year)
   - Notarization makes macOS trust your app

3. **Create a DMG**:
   - Use a tool like **create-dmg** or **Disk Utility**
   - Include instructions about granting Accessibility permission

---

## 📚 Next Steps

### Adding More Keyboard Layouts

1. Open `LayoutConverter.swift`
2. Add new mapping dictionaries for your language pair
3. Update the `convert()` function to handle the new layouts

Example for English ↔ Russian:
```swift
private static func convertEnglishToRussian(_ text: String) -> String {
    let mapping: [Character: Character] = [
        "q": "й", "w": "ц", "e": "у", // etc...
    ]
    return String(text.map { mapping[$0] ?? $0 })
}
```

### Adding a Settings Shortcut

To open preferences with a hotkey:
1. Add another `KeyboardShortcuts.Name` in `Settings.swift`
2. Register it in `AppDelegate.swift`
3. Connect it to `showPreferences()`

---

## 🙋 Support

If you encounter issues:

1. Check **Xcode's Console** (View → Debug Area → Show Debug Area) for error messages
2. Verify all files are added to the target (select a file → File Inspector → Target Membership)
3. Clean the build folder: **Product → Clean Build Folder**
4. Restart Xcode

---

## 📝 License

This code is provided as-is for personal use. Feel free to modify and distribute.

---

**Congratulations! 🎉 You now have a fully functional keyboard layout converter app!**
