From e622c95666ed1a1bca5f38078b5b19bfe3c1f911 Mon Sep 17 00:00:00 2001 From: thiflict <121az348@gmail.com> Date: Wed, 15 Apr 2026 10:35:59 +0500 Subject: [PATCH] =?UTF-8?q?#2:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D0=BE=D1=82=D1=81=D0=BB=D0=B5=D0=B6=D0=B8?= =?UTF-8?q?=D0=B2=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B4=D0=BB=D0=B8=D0=BD=D1=8B?= =?UTF-8?q?=20=D0=BD=D0=B0=D0=B6=D0=B0=D1=82=D0=B8=D0=B9=20=D0=BA=D0=BD?= =?UTF-8?q?=D0=BE=D0=BF=D0=BA=D0=B8.=20=D0=AD=D1=82=D0=BE=20=D0=BD=D1=83?= =?UTF-8?q?=D0=B6=D0=BD=D0=BE=20=D0=B4=D0=BB=D1=8F=20=D0=BE=D1=82=D0=BA?= =?UTF-8?q?=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=81=D0=B0=D0=BC?= =?UTF-8?q?=D0=B1=D1=8B=20=D0=B8=20=D1=80=D0=B0=D0=B7=D0=BC=D0=BE=D0=BD?= =?UTF-8?q?=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D1=84?= =?UTF-8?q?=D0=BB=D0=B5=D1=88=D0=BA=D0=B8.=20(=D1=81=D0=BF=D1=83=D1=81?= =?UTF-8?q?=D1=82=D1=8F=20=D0=B4=D0=B2=D0=B0=20=D1=87=D0=B0=D1=81=D0=B0=20?= =?UTF-8?q?=D1=81=D1=82=D1=80=D0=B0=D0=B4=D0=B0=D0=BD=D0=B8=D0=B9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/ButtonListener.kt | 109 ++++++++++++++++++++++++------ src/main/kotlin/Main.kt | 21 +++++- 2 files changed, 106 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/ButtonListener.kt b/src/main/kotlin/ButtonListener.kt index 4aa9077..fd38e1e 100644 --- a/src/main/kotlin/ButtonListener.kt +++ b/src/main/kotlin/ButtonListener.kt @@ -7,11 +7,11 @@ import java.io.BufferedReader import java.io.InputStreamReader import java.util.concurrent.atomic.AtomicBoolean -// Событие клика по кнопке class ButtonClickEvent +class ButtonLongPressEvent -// Слушатель событий клика typealias ButtonClickListener = (ButtonClickEvent) -> Unit +typealias ButtonLongPressListener = (ButtonLongPressEvent) -> Unit class ButtonListener( private var process: Process? = null, @@ -19,63 +19,128 @@ class ButtonListener( private var isListening: AtomicBoolean = AtomicBoolean(false), private var listenerJob: Job? = null ) { - private val clickListeners = mutableListOf() + private val longPressListeners = mutableListOf() + + var shortPressThresholdMs: Long = 100 + var longPressThresholdMs: Long = 1000 + + private var pressStartTime: Long = 0 fun addClickListener(listener: ButtonClickListener) { clickListeners.add(listener) } + fun removeClickListener(listener: ButtonClickListener) { + clickListeners.remove(listener) + } + + fun addLongPressListener(listener: ButtonLongPressListener) { + longPressListeners.add(listener) + } + + fun removeLongPressListener(listener: ButtonLongPressListener) { + longPressListeners.remove(listener) + } + private fun notifyClick() { + println("=== [CLICK] Короткое нажатие ===") val event = ButtonClickEvent() clickListeners.forEach { it.invoke(event) } } + private fun notifyLongPress() { + println("=== [LONG] Длинное нажатие ===") + val event = ButtonLongPressEvent() + longPressListeners.forEach { it.invoke(event) } + } + fun startListening(onStateChange: ((Boolean) -> Unit)? = null): Boolean { if (isListening.get()) { return currentButtonState.get() } + startListeningInternal(onStateChange) + return currentButtonState.get() + } + + private fun startListeningInternal(onStateChange: ((Boolean) -> Unit)? = null) { try { val cmd = listOf("gpiomon", "--chip=0", "$BUTTON") val processBuilder = ProcessBuilder(cmd) .redirectErrorStream(true) - // Сохраняем процесс в поле process = processBuilder.start() isListening.set(true) listenerJob = CoroutineScope(Dispatchers.IO).launch { - // Используем process, который теперь не null val reader = BufferedReader(InputStreamReader(process!!.inputStream)) var line: String? - while (reader.readLine().also { line = it } != null) { - println(if (isDebug) "$line" else "") - when { - line?.contains("rising") == true -> { - currentButtonState.set(true) - onStateChange?.invoke(true) - println(if (isDebug) "Кнопка нажата" else "") - // Генерируем событие клика при нажатии - notifyClick() - } - line?.contains("falling") == true -> { - currentButtonState.set(false) - onStateChange?.invoke(false) - println(if (isDebug) "Кнопка разжата" else "") - // Убрана проверка на разжатие для генерации события + try { + while (reader.readLine().also { line = it } != null) { + println(if (isDebug) "$line" else "") + when { + line?.contains("rising") == true -> { + currentButtonState.set(true) + onStateChange?.invoke(true) + pressStartTime = System.currentTimeMillis() + println(if (isDebug) "Кнопка нажата, время: $pressStartTime" else "") + } + line?.contains("falling") == true -> { + val pressDuration = System.currentTimeMillis() - pressStartTime + currentButtonState.set(false) + onStateChange?.invoke(false) + println(if (isDebug) "Кнопка отпущена, длительность: ${pressDuration}ms" else "") + + // Определяем тип нажатия по длительности + when { + pressDuration >= longPressThresholdMs -> { + println(if (isDebug) "Длинное нажатие (${pressDuration}ms)" else "") + notifyLongPress() + } + pressDuration >= shortPressThresholdMs -> { + println(if (isDebug) "Короткое нажатие (${pressDuration}ms)" else "") + notifyClick() + } + else -> { + println(if (isDebug) "Слишком короткое нажатие (${pressDuration}ms) - игнорируем" else "") + } + } + } } } + } catch (e: Exception) { + println("Ошибка чтения процесса: ${e.message}") } + val exitCode = process!!.waitFor() - println(if (isDebug) "Процесс завершён ($exitCode)" else "") + println("Процесс завершён ($exitCode)") isListening.set(false) + + // Автоматически перезапускаем прослушивание, если оно должно быть активно + if (isListening.get()) { + println("Перезапуск прослушивания...") + delay(100) + startListeningInternal(onStateChange) + } } } catch (e: Exception) { e.printStackTrace() isListening.set(false) } - return currentButtonState.get() + } + + fun stopListening() { + isListening.set(false) + listenerJob?.cancel() + process?.destroy() + process = null + } + + fun restartListening(onStateChange: ((Boolean) -> Unit)? = null) { + stopListening() + Thread.sleep(200) + startListening(onStateChange) } } \ No newline at end of file diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index b7eb689..3a720f5 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -27,7 +27,7 @@ object DebugMode { // Состояния системы enum class SystemState { - IDLE, SCANNING, CLEAN, INFECTED, ERROR, INIT + IDLE, SCANNING, CLEAN, INFECTED, ERROR, INIT, SAMBA } class USBVirusScanner { @@ -159,6 +159,11 @@ class USBVirusScanner { yellowLed.setValue(0) blinkLed(redLed, 500) } + SystemState.SAMBA -> { + blinkLed(greenLed, 1000) + blinkLed(yellowLed, 1000) + redLed.setValue(0) + } } } } @@ -316,7 +321,7 @@ class USBVirusScanner { try { // Проверяем установлен ли ClamAV - val checkProcess = ProcessBuilder("which", "clamscan").start() + val checkProcess = ProcessBuilder("which", "clamdscan").start() val checkExitCode = checkProcess.waitFor() if (checkExitCode != 0) { @@ -538,9 +543,20 @@ fun main(args: Array) { scanner.initialize() val buttonListener = ButtonListener() + + buttonListener.shortPressThresholdMs = 100 + buttonListener.longPressThresholdMs = 1000 + buttonListener.addClickListener { event -> scanner.startScan() } + + buttonListener.addLongPressListener { event -> + println(if (isDebug) "ДЛИННОЕ НАЖАТИЕ МЯУ" else "") + println("TODO(\"Добавить отключение samba и размонтирование флешки\")") + + } + buttonListener.startListening() println(if (isDebug) """ @@ -564,4 +580,5 @@ fun main(args: Array) { scanner.shutdown() exitProcess(1) } + } \ No newline at end of file