mirror of
https://github.com/hyprwm/hyprlock.git
synced 2026-05-05 12:27:59 +02:00
fix(fingerprint): prevent sensor timeout on long-running sessions
Introduces an inactivity timeout mechanism that pauses fingerprint verification after a configurable period (default: 30 seconds) when no user input is detected. This prevents device drivers from disconnecting or disabling the sensor during extended lock sessions. The verification automatically resumes when user activity is detected (mouse movement, clicks, or keyboard input). The sensor is properly released when paused and re-claimed when resuming. Fixes #702
This commit is contained in:
parent
ef3017f5ef
commit
cf560a619b
6 changed files with 96 additions and 1 deletions
|
|
@ -40,6 +40,8 @@ CFingerprint::CFingerprint() {
|
|||
m_sFingerprintReady = *FINGERPRINTREADY;
|
||||
static const auto FINGERPRINTPRESENT = g_pConfigManager->getValue<Hyprlang::STRING>("auth:fingerprint:present_message");
|
||||
m_sFingerprintPresent = *FINGERPRINTPRESENT;
|
||||
static const auto INACTIVETIMEOUT = g_pConfigManager->getValue<Hyprlang::INT>("auth:fingerprint:inactive_timeout");
|
||||
m_sInactiveTimeout = *INACTIVETIMEOUT;
|
||||
}
|
||||
|
||||
CFingerprint::~CFingerprint() {
|
||||
|
|
@ -96,10 +98,62 @@ bool CFingerprint::checkWaiting() {
|
|||
}
|
||||
|
||||
void CFingerprint::terminate() {
|
||||
// Clean up inactivity timer
|
||||
if (m_pInactivityTimer) {
|
||||
m_pInactivityTimer->cancel();
|
||||
m_pInactivityTimer.reset();
|
||||
}
|
||||
|
||||
if (!m_sDBUSState.abort)
|
||||
releaseDevice();
|
||||
}
|
||||
|
||||
void CFingerprint::setupInactivityTimer() {
|
||||
// Check if we should process activity
|
||||
if (m_sInactiveTimeout <= 0 || m_sDBUSState.abort || m_sDBUSState.done)
|
||||
return;
|
||||
|
||||
// Cancel existing inactivity timer
|
||||
if (m_pInactivityTimer) {
|
||||
m_pInactivityTimer->cancel();
|
||||
m_pInactivityTimer.reset();
|
||||
}
|
||||
|
||||
// Create new inactivity timer
|
||||
m_pInactivityTimer = g_pHyprlock->addTimer(std::chrono::milliseconds(m_sInactiveTimeout * 1000),
|
||||
[](ASP<CTimer> self, void* data) { ((CFingerprint*)data)->onInactivityTimeout(); }, this);
|
||||
}
|
||||
|
||||
void CFingerprint::onActivity() {
|
||||
// Resume scanning if paused
|
||||
if (!m_sDBUSState.verifying) {
|
||||
Debug::log(LOG, "fprint: activity detected, resuming verification");
|
||||
startVerify();
|
||||
}
|
||||
}
|
||||
|
||||
void CFingerprint::onInactivityTimeout() {
|
||||
// Check if we should proceed with timeout
|
||||
if (m_sDBUSState.abort || m_sDBUSState.done || !m_sDBUSState.verifying)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "fprint: inactivity timeout, pausing verification");
|
||||
|
||||
stopVerify();
|
||||
|
||||
releaseDevice();
|
||||
|
||||
// Clear the device proxy (destructive stop)
|
||||
m_sDBUSState.device.reset();
|
||||
|
||||
// Clear the prompt text to provide user feedback
|
||||
m_sPrompt = "";
|
||||
g_pHyprlock->enqueueForceUpdateTimers();
|
||||
|
||||
// Clear the inactivity timer
|
||||
m_pInactivityTimer.reset();
|
||||
}
|
||||
|
||||
std::shared_ptr<sdbus::IConnection> CFingerprint::getConnection() {
|
||||
return m_sDBUSState.connection;
|
||||
}
|
||||
|
|
@ -235,8 +289,11 @@ void CFingerprint::startVerify(bool isRetry) {
|
|||
if (isRetry) {
|
||||
m_sDBUSState.retries++;
|
||||
m_sPrompt = "Could not match fingerprint. Try again.";
|
||||
} else
|
||||
} else {
|
||||
m_sPrompt = m_sFingerprintReady;
|
||||
|
||||
setupInactivityTimer();
|
||||
}
|
||||
}
|
||||
g_pHyprlock->enqueueForceUpdateTimers();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ class CFingerprint : public IAuthImplementation {
|
|||
virtual std::optional<std::string> getLastPrompt();
|
||||
virtual void terminate();
|
||||
|
||||
void onActivity();
|
||||
|
||||
std::shared_ptr<sdbus::IConnection> getConnection();
|
||||
|
||||
private:
|
||||
|
|
@ -39,10 +41,13 @@ class CFingerprint : public IAuthImplementation {
|
|||
|
||||
std::string m_sFingerprintReady;
|
||||
std::string m_sFingerprintPresent;
|
||||
int m_sInactiveTimeout;
|
||||
|
||||
std::string m_sPrompt{""};
|
||||
std::string m_sFailureReason{""};
|
||||
|
||||
ASP<CTimer> m_pInactivityTimer;
|
||||
|
||||
void handleVerifyStatus(const std::string& result, const bool done);
|
||||
|
||||
bool createDeviceProxy();
|
||||
|
|
@ -50,4 +55,7 @@ class CFingerprint : public IAuthImplementation {
|
|||
void startVerify(bool isRetry = false);
|
||||
bool stopVerify();
|
||||
bool releaseDevice();
|
||||
|
||||
void onInactivityTimeout();
|
||||
void setupInactivityTimer();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -226,6 +226,7 @@ void CConfigManager::init() {
|
|||
m_config.addConfigValue("auth:fingerprint:ready_message", Hyprlang::STRING{"(Scan fingerprint to unlock)"});
|
||||
m_config.addConfigValue("auth:fingerprint:present_message", Hyprlang::STRING{"Scanning fingerprint"});
|
||||
m_config.addConfigValue("auth:fingerprint:retry_delay", Hyprlang::INT{250});
|
||||
m_config.addConfigValue("auth:fingerprint:inactive_timeout", Hyprlang::INT{30});
|
||||
|
||||
m_config.addConfigValue("animations:enabled", Hyprlang::INT{1});
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ void CSeatManager::registerSeat(SP<CCWlSeat> seat) {
|
|||
m_pPointer->setMotion([](CCWlPointer* r, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
|
||||
g_pHyprlock->m_vMouseLocation = {wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)};
|
||||
|
||||
g_pHyprlock->onMouseMove(g_pHyprlock->m_vMouseLocation);
|
||||
|
||||
if (!*HIDECURSOR)
|
||||
g_pHyprlock->onHover(g_pHyprlock->m_vMouseLocation);
|
||||
|
||||
|
|
|
|||
|
|
@ -552,6 +552,14 @@ void CHyprlock::repeatKey(xkb_keysym_t sym) {
|
|||
}
|
||||
|
||||
void CHyprlock::onKey(uint32_t key, bool down) {
|
||||
// Notify fingerprint of activity
|
||||
if (g_pAuth) {
|
||||
auto fpImpl = g_pAuth->getImpl(AUTH_IMPL_FINGERPRINT);
|
||||
if (fpImpl) {
|
||||
((CFingerprint*)fpImpl.get())->onActivity();
|
||||
}
|
||||
}
|
||||
|
||||
if (isUnlocked())
|
||||
return;
|
||||
|
||||
|
|
@ -660,6 +668,14 @@ void CHyprlock::onClick(uint32_t button, bool down, const Vector2D& pos) {
|
|||
if (!m_focusedOutput->m_sessionLockSurface)
|
||||
return;
|
||||
|
||||
// Notify fingerprint of activity
|
||||
if (g_pAuth) {
|
||||
auto fpImpl = g_pAuth->getImpl(AUTH_IMPL_FINGERPRINT);
|
||||
if (fpImpl) {
|
||||
((CFingerprint*)fpImpl.get())->onActivity();
|
||||
}
|
||||
}
|
||||
|
||||
const auto SCALEDPOS = pos * m_focusedOutput->m_sessionLockSurface->fractionalScale;
|
||||
const auto widgets = g_pRenderer->getOrCreateWidgetsFor(*m_focusedOutput->m_sessionLockSurface);
|
||||
for (const auto& widget : widgets) {
|
||||
|
|
@ -707,6 +723,16 @@ void CHyprlock::onHover(const Vector2D& pos) {
|
|||
m_focusedOutput->m_sessionLockSurface->render();
|
||||
}
|
||||
|
||||
void CHyprlock::onMouseMove(const Vector2D& pos) {
|
||||
// Notify fingerprint of activity
|
||||
if (g_pAuth) {
|
||||
auto fpImpl = g_pAuth->getImpl(AUTH_IMPL_FINGERPRINT);
|
||||
if (fpImpl) {
|
||||
((CFingerprint*)fpImpl.get())->onActivity();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CHyprlock::acquireSessionLock() {
|
||||
Debug::log(LOG, "Locking session");
|
||||
m_sLockState.lock = makeShared<CCExtSessionLockV1>(m_sWaylandState.sessionLock->sendLock());
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ class CHyprlock {
|
|||
void onKey(uint32_t key, bool down);
|
||||
void onClick(uint32_t button, bool down, const Vector2D& pos);
|
||||
void onHover(const Vector2D& pos);
|
||||
void onMouseMove(const Vector2D& pos);
|
||||
void startKeyRepeat(xkb_keysym_t sym);
|
||||
void repeatKey(xkb_keysym_t sym);
|
||||
void handleKeySym(xkb_keysym_t sym, bool compose);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue