Compare commits

..

2 Commits

Author SHA1 Message Date
koreafood de5f09da95 수정 2026-06-26 08:58:20 +09:00
koreafood e970b7b04b feat: add cmd+b hotkey to auto-type stripped clipboard text
Add a new global Cmd+B hotkey that reads clipboard content, removes all hyphens,
and sequentially types the cleaned text into the currently focused application. Include
prerequisite checks for accessibility permissions and secure input state, error handling for
clipboard access and typing failures, and system hotkey conflict detection to avoid overriding
existing macOS shortcuts. Also add the project's git commit message guidelines in
.trae/rules/git-commit-message.md.
2026-06-26 08:56:18 +09:00
2 changed files with 124 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
---
alwaysApply: true
scene: git_message
---
한글로 작성
맨위에 한줄요약으로 시작
그 아래에 메시지 작성
+116
View File
@@ -188,6 +188,122 @@ hs.keycodes.inputSourceChanged(function() -- 입력기 전환이 일어날 때
showInputSourceHud() -- 한글과 영문 전환 결과에 맞는 중앙 표시를 즉시 띄웁니다.
end) -- 입력기 변경 콜백 등록을 마칩니다.
-- `cmd`+`b`로 클립보드 문자열에서 하이픈을 제거한 뒤 연속 자동 입력하는 기능 설정을 시작합니다.
local clipboardTypeHotkeyModifiers = { "cmd" } -- 자동 입력 기능에 사용할 수정 키 조합을 정의합니다.
local clipboardTypeHotkeyKey = "b" -- 자동 입력 기능에 사용할 기본 키를 정의합니다.
local clipboardTypeInterval = 0.12 -- 각 문자 입력 사이에 둘 짧은 지연 시간을 초 단위로 정의합니다.
local clipboardTypingInProgress = false -- 자동 입력이 이미 진행 중인지 추적해 중복 실행을 막습니다.
local clipboardTypeHotkey = nil -- 충돌 검사 후 실제로 바인딩된 단축키 객체를 저장합니다.
-- 문자열의 각 문자를 순서대로 담은 큐 테이블을 만드는 함수를 정의합니다.
local function buildCharacterQueue(text) -- 하이픈 제거 후 남은 모든 문자를 순차 전송하기 위한 준비 함수입니다.
local queue = {} -- 순서대로 전송할 문자 목록을 빈 테이블로 초기화합니다.
for _, codepoint in utf8.codes(text) do -- UTF-8 문자열을 코드포인트 단위로 안전하게 순회합니다.
queue[#queue + 1] = utf8.char(codepoint) -- 읽어온 문자를 그대로 큐 뒤에 추가합니다.
end -- 문자열 전체를 큐로 변환하는 반복을 마칩니다.
return queue -- 완성된 문자 큐를 호출한 곳에 반환합니다.
end -- 문자 큐 생성 함수 정의를 마칩니다.
-- 현재 환경에서 자동 키 입력을 수행할 수 있는지 선검사하는 함수를 정의합니다.
local function ensureClipboardTypingPrerequisites() -- 권한과 보안 입력 상태를 미리 확인해 실패를 줄입니다.
if not hs.accessibilityState() then -- 손쉬운 사용 권한이 없으면 키 이벤트 전송이 불가능하므로 먼저 처리합니다.
hs.accessibilityState(true) -- macOS 권한 허용 안내를 띄워 사용자가 바로 승인할 수 있게 돕습니다.
hs.alert.show("Hammerspoon 손쉬운 사용 권한이 필요합니다") -- 권한 필요 안내를 화면에 표시합니다.
return false -- 아직 자동 입력을 진행할 수 없으므로 실패를 반환합니다.
end -- 손쉬운 사용 권한 검사 분기 종료입니다.
if hs.eventtap.isSecureInputEnabled() then -- 보안 입력이 활성화된 앱에서는 키 이벤트 주입이 막힐 수 있으므로 점검합니다.
hs.alert.show("보안 입력이 켜져 있어 자동 입력을 실행할 수 없습니다") -- 현재 상태를 사용자에게 즉시 알립니다.
return false -- 안전하지 않은 상태에서는 자동 입력을 중단합니다.
end -- 보안 입력 상태 검사 분기 종료입니다.
return true -- 필요한 선행 조건이 모두 충족됐음을 반환합니다.
end -- 자동 입력 선행 조건 검사 함수 정의를 마칩니다.
-- 한 글자를 현재 포커스된 앱으로 전송하는 함수를 정의합니다.
local function postClipboardCharacter(character) -- 남아 있는 문자를 현재 포커스된 앱에 한 글자씩 안전하게 전송합니다.
hs.eventtap.keyStrokes(character, 0) -- 현재 포커스된 앱에 해당 문자를 한 글자씩 전달합니다.
end -- 단일 문자 전송 함수 정의를 마칩니다.
-- 문자 큐를 타이머 기반으로 순차 입력하는 함수를 정의합니다.
local function typeClipboardQueue(queue, index) -- 긴 입력 중에도 설정 전체가 멈추지 않도록 비동기식으로 처리합니다.
if not clipboardTypingInProgress then -- 외부 오류나 상태 변경으로 이미 종료됐다면 즉시 빠져나옵니다.
return -- 종료된 작업을 더 진행하지 않도록 여기서 함수를 마칩니다.
end -- 실행 상태 검사 분기 종료입니다.
if index > #queue then -- 마지막 문자까지 모두 전송했다면 정상 완료 처리를 진행합니다.
clipboardTypingInProgress = false -- 다음 실행을 위해 진행 중 상태를 해제합니다.
return -- 더 이상 전송할 문자가 없으므로 함수를 종료합니다.
end -- 입력 완료 여부 검사 분기 종료입니다.
local ok, errorMessage = pcall(postClipboardCharacter, queue[index]) -- 현재 문자를 안전하게 전송하고 예외를 가로챕니다.
if not ok then -- 문자 전송 중 런타임 오류가 발생한 경우를 처리합니다.
clipboardTypingInProgress = false -- 오류 발생 시에도 다음 실행을 위해 상태를 정상적으로 복구합니다.
hs.alert.show("자동 입력 중 오류가 발생했습니다") -- 사용자에게 실패 사실을 화면으로 알려줍니다.
hs.printf("Clipboard typing failed: %s", tostring(errorMessage)) -- 디버깅을 위해 콘솔에 구체적인 오류를 기록합니다.
return -- 오류 이후 추가 입력이 이어지지 않도록 즉시 종료합니다.
end -- 문자 전송 예외 처리 분기 종료입니다.
hs.timer.doAfter(clipboardTypeInterval, function() -- 다음 문자 입력을 짧은 지연 뒤 예약해 앱이 입력을 안정적으로 받게 합니다.
typeClipboardQueue(queue, index + 1) -- 다음 위치의 문자를 계속 순차적으로 전송합니다.
end) -- 다음 문자 예약 콜백 정의를 마칩니다.
end -- 문자 큐 순차 입력 함수 정의를 마칩니다.
-- 클립보드 내용을 읽어 하이픈 제거 후 연속 자동 입력 작업을 시작하는 함수를 정의합니다.
local function typeClipboardAsContinuousSequence() -- 실제 단축키가 눌렸을 때 호출될 메인 작업 함수입니다.
if clipboardTypingInProgress then -- 이전 자동 입력이 아직 끝나지 않았다면 중복 실행을 막습니다.
hs.alert.show("자동 입력이 이미 진행 중입니다") -- 재진입이 거부된 이유를 사용자에게 알려줍니다.
return -- 중복 실행은 허용하지 않고 함수를 종료합니다.
end -- 재진입 방지 분기 종료입니다.
if not ensureClipboardTypingPrerequisites() then -- 권한이나 보안 입력 상태가 적절한지 먼저 확인합니다.
return -- 선행 조건이 맞지 않으면 작업을 시작하지 않습니다.
end -- 선행 조건 검사 분기 종료입니다.
local clipboardReadOk, clipboardText = pcall(hs.pasteboard.getContents) -- 클립보드 문자열 읽기를 예외 안전하게 시도합니다.
if not clipboardReadOk then -- 클립보드 접근 자체에서 오류가 발생한 경우를 처리합니다.
hs.alert.show("클립보드 내용을 읽는 중 오류가 발생했습니다") -- 읽기 실패를 사용자에게 알립니다.
hs.printf("Clipboard read failed: %s", tostring(clipboardText)) -- 콘솔에 구체적인 오류 정보를 남깁니다.
return -- 읽기에 실패했으므로 자동 입력을 시작하지 않습니다.
end -- 클립보드 읽기 예외 처리 분기 종료입니다.
if type(clipboardText) ~= "string" or clipboardText == "" then -- 빈 문자열이거나 문자열이 아닌 경우는 유효한 입력 원본이 아닙니다.
hs.alert.show("클립보드에 입력할 텍스트가 없습니다") -- 사용자가 먼저 텍스트를 복사하도록 안내합니다.
return -- 유효한 내용이 없으므로 여기서 종료합니다.
end -- 클립보드 내용 유효성 검사 분기 종료입니다.
local transformedText = clipboardText:gsub("%-", "") -- 자동 포커스 이동을 활용할 수 있도록 모든 하이픈을 제거합니다.
local queue = buildCharacterQueue(transformedText) -- 하이픈이 제거된 문자열을 문자 단위 큐로 만들어 순차 입력 준비를 합니다.
if #queue == 0 then -- 하이픈 제거 후 결과가 실질적으로 비어 있으면 입력할 것이 없으므로 막습니다.
hs.alert.show("하이픈 제거 후 입력할 문자가 없습니다") -- 의미 없는 실행이 되지 않도록 사용자에게 알려줍니다.
return -- 입력 큐가 비어 있으므로 종료합니다.
end -- 하이픈 제거 결과 유효성 검사 분기 종료입니다.
clipboardTypingInProgress = true -- 실제 입력을 시작하기 전에 진행 중 상태를 활성화합니다.
local typingStartOk, typingStartError = pcall(typeClipboardQueue, queue, 1) -- 순차 입력 시작 자체도 예외 안전하게 감쌉니다.
if not typingStartOk then -- 시작 단계에서 예상치 못한 오류가 발생한 경우를 처리합니다.
clipboardTypingInProgress = false -- 시작 실패 시 진행 상태를 즉시 되돌립니다.
hs.alert.show("자동 입력 시작에 실패했습니다") -- 사용자에게 시작 실패를 알립니다.
hs.printf("Clipboard typing start failed: %s", tostring(typingStartError)) -- 콘솔에 실패 원인을 기록합니다.
end -- 자동 입력 시작 예외 처리 분기 종료입니다.
end -- 클립보드 연속 자동 입력 메인 함수 정의를 마칩니다.
-- 시스템 레벨에 이미 예약된 단축키와 충돌하는지 검사합니다.
local clipboardTypeSystemConflict = hs.hotkey.systemAssigned(clipboardTypeHotkeyModifiers, clipboardTypeHotkeyKey) -- macOS가 점유한 조합이면 바인딩을 피하기 위해 조회합니다.
if clipboardTypeSystemConflict then -- 시스템이 이미 이 단축키를 사용 중인 경우를 처리합니다.
hs.alert.show("cmd-b 단축키가 시스템에 이미 할당되어 있어 등록하지 않았습니다") -- 충돌 사실을 화면에 알립니다.
hs.printf("Skipped binding cmd-b due to system conflict: %s", hs.inspect(clipboardTypeSystemConflict)) -- 콘솔에 충돌 세부 정보를 남깁니다.
else -- 시스템 충돌이 없을 때만 안전하게 단축키를 등록합니다.
clipboardTypeHotkey = hs.hotkey.bind(clipboardTypeHotkeyModifiers, clipboardTypeHotkeyKey, function() -- 전역 단축키를 눌렀을 때 메인 작업을 실행합니다.
local hotkeyOk, hotkeyError = pcall(typeClipboardAsContinuousSequence) -- 단축키 콜백 전체를 예외 안전하게 감싸 강제 종료를 막습니다.
if not hotkeyOk then -- 콜백 바깥쪽에서 예상치 못한 오류가 터진 경우를 처리합니다.
clipboardTypingInProgress = false -- 오류 뒤 다음 실행이 가능하도록 상태를 정리합니다.
hs.alert.show("cmd-b 자동 입력 실행에 실패했습니다") -- 사용자에게 실행 실패를 알려줍니다.
hs.printf("cmd-b clipboard hotkey failed: %s", tostring(hotkeyError)) -- 콘솔에 실제 오류 메시지를 기록합니다.
end -- 단축키 콜백 예외 처리 분기 종료입니다.
end) -- 전역 단축키 바인딩 정의를 마칩니다.
end -- 시스템 단축키 충돌 여부에 따른 등록 분기를 마칩니다.
overrideOtherMouseDown:start() -- 보조 버튼 눌림 감시를 시작합니다.
overrideOtherMouseUp:start() -- 보조 버튼 떼기 감시를 시작합니다.
dragOtherToScroll:start() -- 보조 버튼 드래그 스크롤 감시를 시작합니다.