package service import java.util.concurrent.TimeUnit import org.slf4j.LoggerFactory import ch.qos.logback.classic.Level import ch.qos.logback.classic.Logger object SystemSleepPreventer { private var process: Process? = null fun checkAndRequestAccessibility() { if (!hasAccessibilityPermission()) { println("⚠️ [System] 접근성 권한이 없습니다. 설정창을 엽니다.") openAccessibilitySettings() } else { println("✅ [System] 접근성 권한이 확인되었습니다.") } } /** * 실제로 가벼운 이벤트를 발생시켜 권한 유무를 확인하는 함수 */ private fun hasAccessibilityPermission(): Boolean { return try { // System Events에 이름을 묻는 아주 가벼운 명령을 실행합니다. val process = Runtime.getRuntime().exec( arrayOf("osascript", "-e", "tell application \"System Events\" to get name") ) // 권한이 없으면 팝업이 뜨며 대기할 수 있으므로, 아주 짧은 타임아웃을 줍니다. val exited = process.waitFor(1500, java.util.concurrent.TimeUnit.MILLISECONDS) if (!exited) { // 타임아웃 발생 시, 시스템이 권한 승인 팝업을 띄우고 대기 중일 확률이 높습니다. process.destroyForcibly() return false } // 에러 스트림을 읽어 권한 거부 관련 메시지가 있는지 확인합니다. val errorStream = process.errorStream.bufferedReader().readText() val isDenied = errorStream.contains("not allowed") || process.exitValue() != 0 !isDenied } catch (e: Exception) { println("⚠️ [Permission] 체크 중 오류 발생: ${e.message}") false } } private fun openAccessibilitySettings() { try { Runtime.getRuntime().exec(arrayOf( "open", "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility" )) } catch (e: Exception) { e.printStackTrace() } } /** * 맥의 절전 모드 및 디스플레이 취침을 방지하는 명령 실행 */ fun start() { val os = System.getProperty("os.name").lowercase() val arch = System.getProperty("os.arch").lowercase() val isWin = os.contains("win") val root = LoggerFactory.getLogger("Exposed") as Logger root.level = Level.ERROR if (!isWin) { checkAndRequestAccessibility() } if (process?.isAlive == true) return if (!isWin) { try { // -i: 시스템 절전 방지, -d: 디스플레이 취침 방지, -m: 디스크 유휴 상태 방지 val command = listOf("caffeinate", "-i", "-d", "-m") process = ProcessBuilder(command).start() println("☕ [System] caffeinate 실행됨: 앱이 켜져 있는 동안 절전 모드가 방지됩니다.") } catch (e: Exception) { println("⚠️ [System] caffeinate 실행 실패: ${e.message}") } } } /** * 모니터를 즉시 잠자기 모드로 전환 */ fun sleepDisplay() { try { // pmset을 이용해 디스플레이를 즉시 끔 Runtime.getRuntime().exec("pmset displaysleepnow") println("🌙 [System] 오후 6시 30분: 모니터를 잠자기 모드로 전환합니다.") } catch (e: Exception) { println("⚠️ 모니터 잠자기 실패: ${e.message}") } } /** * 마우스 움직임을 시뮬레이션하거나 디스플레이 깨우기 명령 실행 */ fun wakeDisplay() { try { // caffeinate를 다시 실행하여 깨우거나, // 쉘 명령어로 키 입력을 시뮬레이션하여 화면을 깨움 Runtime.getRuntime().exec( arrayOf("caffeinate", "-u", "-t", "3600") ) // Runtime.getRuntime().exec(arrayOf("osascript", "-e", "tell application \"System Events\" to key code 123")) println("☀️ 오전 8시: 모니터를 깨웁니다.") } catch (e: Exception) { println("⚠️ 모니터 깨우기 실패: ${e.message}") } } /** * 앱 종료 시 프로세스 함께 종료 */ fun stop() { process?.destroy() // 프로세스가 강제 종료되지 않을 경우를 대비해 0.5초 대기 후 강제 종료 if (process?.waitFor(500, TimeUnit.MILLISECONDS) == false) { process?.destroyForcibly() } println("🛑 [System] caffeinate 종료됨: 시스템 절전 설정이 정상화됩니다.") } }