Ubuntu에서 한국 POE(패스 오브 엑자일) 설치 + G HUB 없이 마우스 매크로 구현하기

저는 Ubuntu Desktop을 메인 OS로 사용하고 있는데, 게임을 하나 즐기고 싶어졌습니다. 바로 Path of Exile (패스 오브 엑자일, POE) — 한국 서비스는 카카오(다음)가 맡고 있습니다. 문제는 공식 클라이언트가 Windows 전용이라는 것. 거기다 G HUB 같은 마우스 소프트웨어도 Windows 전용이라 오토클리커도 직접 만들어야 했습니다.

삽질을 꽤 했지만 결국 완전히 돌아가는 환경을 만들었고, 이 글에 그 과정을 정리합니다.

✅ 완성된 구성

  • Lutris + Wine-GE-8-26으로 카카오 POE 실행
  • fakeDaumgameStarter.py로 Kakao CDN 인증 자동 처리
  • Awakened PoE Trade, Path of Building 동시 실행
  • pynput + xdotool 기반 오토클리커 (G HUB 없이)

🛠 기술 스택

  • OS: Ubuntu 24.04 Desktop
  • 게임 런처: Lutris
  • Wine: wine-ge-8-26-x86_64 (GE Custom 빌드)
  • 인증 우회: Python 3 스크립트 (fakeDaumgameStarter.py)
  • 매크로: pynput (버튼 감지) + xdotool (클릭 발생)

📋 왜 이렇게 복잡한가? — 카카오 CDN 인증 구조

일반적인 Steam POE와 달리, 한국 카카오 버전은 카카오 웹 로그인 → 게임 시작 → daumgamestarter:// 프로토콜 핸들러 순서로 실행됩니다.

이 핸들러가 daumgamestarter://poe|env|launcher|token1|token2 형태의 URL을 받아 카카오 CDN(poe.gdn.gamecdn.net)에서 토큰을 검증한 뒤 게임을 실행합니다. 토큰 없이 CDN에 접근하면 403이 반환되고, 이 경우 게임 내에서 Corrupt data from patching server 오류가 발생합니다.

📌 Wine 버전 문제, winhttp/TLS 설정 문제가 아닙니다. 항상 웹 로그인으로 토큰을 획득해야 합니다.

📁 Step 1: Lutris 및 Wine-GE 설치

먼저 Lutris를 설치합니다. (터미널 단축키 : Ctrl + Alt + T)

Bash
sudo apt install lutris

Wine GE Custom 빌드는 일반 Wine보다 게임 호환성이 훨씬 좋습니다. GitHub Releases에서 wine-ge-8-26-x86_64를 다운로드하고 압축을 풉니다.

Bash
mkdir -p ~/.local/share/lutris/runners/wine/
tar -xf wine-ge-8-26-x86_64.tar.xz -C ~/.local/share/lutris/runners/wine/

📁 Step 2: POE 설치

Lutris에서 수동으로 Wine 게임을 추가합니다.

  • Wine runner: wine-ge-8-26-x86_64 선택
  • WINEPREFIX: /home/사용자명/Games/path-of-exile
  • Architecture: win64

카카오 POE 설치 파일은 아래 CDN에서 직접 다운로드할 수 있습니다.

Bash
http://poe.gdn.gamecdn.net/kg_live/Game/poe/Install/PathOfExile_Setup.exe

Wine으로 Setup.exe를 실행하면 기본 경로에 설치됩니다. 설치 후 실행 파일은 drive_c/Daum Games/Path of Exile/PathOfExile_KG.exe (73MB 짜리)를 사용합니다. x64_KG 버전(529KB)은 stub이라 실제 실행 불가입니다.

Winetricks로 필수 컴포넌트도 설치합니다.

Bash
WINEPREFIX=/home/사용자명/Games/path-of-exile winetricks riched20 usp10

Lutris 실행 파일을 클릭해서 왼쪽 상담 + 버튼을 통해서 직접 검색 및 설치고 가능!

🐍 Step 3: fakeDaumgameStarter.py 작성

Linux에는 daumgamestarter:// 프로토콜 핸들러가 없습니다. 대신 이 Python 스크립트가 그 역할을 대신합니다. 웹 로그인 후 발급된 URL을 인수로 받아 토큰을 파싱하고 Wine으로 POE를 실행합니다.

Bash
#!/usr/bin/python3
import sys, os, subprocess

POE_PATH = "drive_c/Daum Games/Path of Exile/"
POE_CLIENT = POE_PATH + "PathOfExile_KG.exe"

def parse_url(url):
    without_proto = url[18:]  # 'daumgamestarter://' 제거
    parts = without_proto.split("|")
    if len(parts) == 1:
        parts = without_proto.split("%7C")  # URL 인코딩된 경우
    return parts

def run_poe(data):
    poe_root = "/home/사용자명/Games/path-of-exile/"
    wine_path = "/home/사용자명/.local/share/lutris/runners/wine/wine-ge-8-26-x86_64/bin/wine"

    env = os.environ.copy()
    env["WINEPREFIX"] = poe_root
    env["WINEFSYNC"] = "1"
    env["WINEESYNC"] = "1"

    # token1 = data[3], token2 = data[4]
    cmd = [wine_path, poe_root + POE_CLIENT,
           "--waitforpreload", "--nologo", "--nodx9ex", "--gc2",
           "--kakao", data[3], data[4]]
    subprocess.check_call(cmd, env=env, cwd=poe_root + POE_PATH)

def main():
    if len(sys.argv) < 2:
        print("Usage: fakeDaumgameStarter.py 'daumgamestarter://poe|env|launcher|token1|token2'")
        return
    parsed = parse_url(sys.argv[1])
    if parsed[0] == "poe":
        run_poe(parsed)

if __name__ == "__main__":
    main()

🌐 Step 4: xdg-open 프로토콜 핸들러 등록

daumgamestarter:// URL이 브라우저에서 클릭되면 자동으로 스크립트가 실행되도록 등록합니다.

~/.local/share/applications/daumgamestarter.desktop 파일을 생성합니다.

Python
[Desktop Entry]
Name=Daum Game Starter (POE)
Exec=/usr/bin/python3 /home/사용자명/Games/path-of-exile/fakeDaumgameStarter.py %u
Type=Application
MimeType=x-scheme-handler/daumgamestarter;
NoDisplay=true

이후 아래 명령으로 등록합니다.

Python
xdg-mime default daumgamestarter.desktop x-scheme-handler/daumgamestarter
update-desktop-database ~/.local/share/applications/

🚀 Step 5: 실행 방법

  1. 브라우저에서 https://poe.game.daum.net 접속
  2. 카카오 로그인 후 게임 시작 클릭
  3. 브라우저가 daumgamestarter://poe|...|token1|token2 URL을 감지
  4. 등록된 핸들러가 fakeDaumgameStarter.py를 자동 실행
  5. Wine으로 PathOfExile_KG.exe --kakao token1 token2 실행

📌 브라우저에서 “외부 앱 열기” 팝업이 뜨면 허용을 눌러야 합니다. Firefox 기준으로 about:config에서 network.protocol-handler.expose.daumgamestarterfalse로 설정하면 매번 물어봅니다.


🖱 G HUB 없이 마우스 매크로 만들기

로지텍 G HUB는 Linux를 지원하지 않습니다. 하지만 Python으로 충분히 대체할 수 있습니다. 핵심은 pynput으로 버튼을 감지하고, xdotool로 클릭을 발생시키는 것입니다.

⚠️ 중요한 함정: pynputmouse_ctrl.click()은 X11 이벤트 체인 외부에서 synthetic event를 생성하기 때문에 Ctrl, Shift 등 modifier가 전달되지 않습니다. xdotool을 사용해야 정상적으로 동작합니다.

필요한 패키지 설치

Python
pip install pynput
sudo apt install xdotool

버튼 이름 먼저 확인하기 (detect_button.py)

G502 같은 멀티버튼 마우스는 사이드 버튼이 Button.x1, Button.x2가 아니라 Button.button8 같은 이름으로 잡힐 수 있습니다. 먼저 확인합니다.

Python
#!/usr/bin/env python3
from pynput import mouse, keyboard

def on_mouse_click(x, y, button, pressed):
    if pressed:
        print(f"[MOUSE] {button}  (이름: {button.name})")

def on_key_press(key):
    print(f"[KEYBOARD] {key}")

with mouse.Listener(on_click=on_mouse_click) as m, 
     keyboard.Listener(on_press=on_key_press) as k:
    m.join()

오토클리커 본체 (auto_clicker.py)

특정 버튼을 누르고 있는 동안 좌클릭을 반복합니다. 랜덤 간격을 줘서 패턴 감지를 회피합니다.

Python
#!/usr/bin/env python3
import time, random, threading, subprocess
from pynput import mouse, keyboard
from pynput.mouse import Button

# ── 설정 ────────────────────────────────────────
TRIGGER_TYPE = "mouse"   # "mouse" 또는 "key"
TRIGGER      = Button.button8  # detect_button.py로 확인한 버튼 이름

MIN_MS = 80   # 최소 클릭 간격 (밀리초)
MAX_MS = 130  # 최대 클릭 간격 (밀리초)
# ────────────────────────────────────────────────

_clicking = False
_lock = threading.Lock()

def _click_loop():
    while True:
        with _lock:
            if not _clicking:
                return
        # xdotool 사용 — modifier(Ctrl 등) 정상 전달됨
        subprocess.run(['xdotool', 'click', '1'], check=False)
        time.sleep(random.uniform(MIN_MS / 1000, MAX_MS / 1000))

def _start():
    global _clicking
    with _lock:
        if _clicking:
            return
        _clicking = True
    threading.Thread(target=_click_loop, daemon=True).start()

def _stop():
    global _clicking
    with _lock:
        _clicking = False

def on_mouse_click(x, y, button, pressed):
    if TRIGGER_TYPE == "mouse" and button == TRIGGER:
        _start() if pressed else _stop()

def on_key_press(key):
    if TRIGGER_TYPE == "key" and key == TRIGGER:
        _start()

def on_key_release(key):
    if TRIGGER_TYPE == "key" and key == TRIGGER:
        _stop()

print(f"오토클리커 실행중 | 트리거: [{TRIGGER_TYPE}] {TRIGGER} | 간격: {MIN_MS}~{MAX_MS}ms")
print("Ctrl+C로 종료")

m = mouse.Listener(on_click=on_mouse_click)
k = keyboard.Listener(on_press=on_key_press, on_release=on_key_release)
m.start()
k.start()

try:
    m.join()
except KeyboardInterrupt:
    _stop()
    m.stop()
    k.stop()

💡 POE 실행 시 자동 시작

fakeDaumgameStarter.py에서 POE 실행 시 오토클리커도 함께 띄우고, POE 종료 시 같이 종료되도록 연동할 수 있습니다.

Python
import subprocess

# POE 실행 전
auto_proc = subprocess.Popen(['python3', '/path/to/auto_clicker.py'])

# POE 실행 (blocking)
subprocess.check_call(poe_cmd, env=env)

# POE 종료 후 자동 클리너
auto_proc.terminate()

💡 자주 발생하는 오류 해결

  • “Corrupt data from patching server” → 카카오 토큰 없이 실행한 것. 반드시 웹 로그인 후 게임 시작 버튼 클릭으로 토큰을 받아야 함.
  • 화면이 검게만 나옴WINEFSYNC=1 WINEESYNC=1 환경변수 확인
  • 한글이 깨짐winetricks cjkfonts 또는 Windows 한글 폰트 복사
  • 오토클리커가 Ctrl+클릭이 안 됨 → pynput click 대신 xdotool 사용 필수
  • xdotool click이 전경 앱에 전달 안 됨DISPLAY=:0 환경변수 설정 확인

🏁 마치며

처음엔 “그냥 Windows 깔면 되지” 싶었지만, 한 번 세팅해두니 Ubuntu에서도 POE를 아무 불편함 없이 즐기고 있습니다. 카카오 CDN 인증 구조만 이해하면 나머지는 생각보다 단순합니다.

G HUB 대신 Python 스크립트로 매크로를 만드는 것도 오히려 더 자유롭게 커스텀할 수 있어서 만족스럽습니다. pynput + xdotool 조합은 POE 외에도 다양한 Linux 게임 자동화에 그대로 활용할 수 있습니다.

비슷한 환경에서 시도하시는 분들께 이 글이 도움이 되길 바랍니다. 🎮