/** * $RCSfile: ,v $ * $Revision: $ * $Date: $ * Copyright (C) 2004-2011 Jive Software. All rights reserved. * This plugin is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.jivesoftware.sparkimpl.plugin.idle; import java.awt.AWTEvent; import java.awt.EventQueue; import java.awt.MouseInfo; import java.awt.PointerInfo; import java.awt.Toolkit; import java.awt.event.KeyEvent; import java.util.Timer; import java.util.TimerTask; import org.jivesoftware.Spark; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.spark.SparkManager; import org.jivesoftware.spark.plugin.Plugin; import org.jivesoftware.spark.util.StringUtils; import org.jivesoftware.spark.util.log.Log; import org.jivesoftware.sparkimpl.settings.local.LocalPreferences; import org.jivesoftware.sparkimpl.settings.local.SettingsManager; import com.sun.jna.platform.win32.Kernel32; import com.sun.jna.platform.win32.User32; import com.sun.jna.platform.win32.WinUser; import com.sun.jna.platform.win32.WinDef.HMODULE; import com.sun.jna.platform.win32.WinDef.LRESULT; import com.sun.jna.platform.win32.WinDef.WPARAM; import com.sun.jna.platform.win32.WinUser.HHOOK; import com.sun.jna.platform.win32.WinUser.KBDLLHOOKSTRUCT; import com.sun.jna.platform.win32.WinUser.LowLevelKeyboardProc; import com.sun.jna.platform.win32.WinUser.MSG; public class UserIdlePlugin extends TimerTask implements Plugin { private final int CHECKTIME = 2; private double x = 0; private double y = 0; private boolean hasChanged = false; private int counter = 0; private LocalPreferences pref = SettingsManager.getLocalPreferences(); private Presence latestPresence; private KeyHook keyHook; @Override public boolean canShutDown() { return false; } @Override public void initialize() { Timer timer = new Timer(); // Check all 5 secounds timer.schedule(this, (1000 * 10), (1000 * CHECKTIME)); if (Spark.isWindows()) { keyHook = new KeyHook(); keyHook.initKeyHook(); } else { addGlobalListener(); } } @Override public void shutdown() { } @Override public void uninstall() { if (Spark.isWindows()) { keyHook.quitKeyHook(); } } private void setIdle() { latestPresence = SparkManager.getWorkspace().getStatusBar() .getPresence(); if ((latestPresence.getMode() == Presence.Mode.available) || latestPresence.getMode() == Presence.Mode.chat) { Presence presence = new Presence(Presence.Type.available, StringUtils.modifyWildcards(pref.getIdleMessage()), 1, Presence.Mode.away); SparkManager.getSessionManager().changePresence(presence); } } private void setOnline() { SparkManager.getSessionManager().changePresence(latestPresence); } @Override public void run() { if (pref.isIdleOn()) { PointerInfo info = MouseInfo.getPointerInfo(); // DecimalFormat format = new DecimalFormat("0.00"); // System.out.println(format.format(info.getLocation().getY()).toString() // + "-" + 7.24288464E8 + "-" + (info.getLocation().getY() == // 7.24288464E8)); // System.out.println(format.format(info.getLocation().getX()).toString() // + "-" + 7.24288464E8 + "-" + (info.getLocation().getX() == // 7.24288464E8)); int automaticIdleTime = (pref.getIdleTime() * 60) / CHECKTIME; // Windows Desktop Lock if (Spark.isWindows()) { if (info != null) { if (info.getLocation().getX() > 50000000 || info.getLocation().getY() > 50000000) { if (!hasChanged) { Log.debug("Desktop Locked .. "); hasChanged = true; setIdle(); y = info.getLocation().getY(); x = info.getLocation().getX(); } } } else { if (!hasChanged) { Log.debug("Desktop Locked .. "); hasChanged = true; setIdle(); y = -1; x = -1; } } } // Default Idle if (info != null) { if (x == info.getLocation().getX() && y == info.getLocation().getY()) { if (counter > automaticIdleTime) { if (!hasChanged) { setIdle(); } hasChanged = true; } counter++; } else { if (hasChanged) { setOnline(); hasChanged = false; } counter = 0; } y = info.getLocation().getY(); x = info.getLocation().getX(); } } } private void addGlobalListener() { EventQueue e = Toolkit.getDefaultToolkit().getSystemEventQueue(); e.push(new EventQueue() { @Override protected void dispatchEvent(AWTEvent event) { if (event instanceof KeyEvent) { counter = 0; if (hasChanged) { setOnline(); hasChanged = false; } } super.dispatchEvent(event); } }); } private void userActive() { counter = 0; if (hasChanged) { setOnline(); hasChanged = false; } } /** Sample implementation of a low-level keyboard hook on W32. */ class KeyHook { private HHOOK hhk; private LowLevelKeyboardProc keyboardHook; private Thread thread; public void initKeyHook() { thread = new Thread(new Runnable() { @Override public void run() { final User32 lib = User32.INSTANCE; HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null); keyboardHook = new LowLevelKeyboardProc() { public LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT info) { if (nCode >= 0) { switch (wParam.intValue()) { // case WinUser.WM_KEYUP: case WinUser.WM_KEYDOWN: // case WinUser.WM_SYSKEYUP: case WinUser.WM_SYSKEYDOWN: // do active userActive(); } } return lib.CallNextHookEx(hhk, nCode, wParam, info.getPointer()); } }; hhk = lib.SetWindowsHookEx(WinUser.WH_KEYBOARD_LL, keyboardHook, hMod, 0); // This bit never returns from GetMessage int result; MSG msg = new MSG(); while ((result = lib.GetMessage(msg, null, 0, 0)) != 0) { if (result == -1) { System.err.println("error in get message"); break; } else { System.err.println("got message"); lib.TranslateMessage(msg); lib.DispatchMessage(msg); } } lib.UnhookWindowsHookEx(hhk); } }); thread.start(); } @SuppressWarnings("deprecation") public void quitKeyHook() { final User32 lib = User32.INSTANCE; lib.UnhookWindowsHookEx(hhk); thread.stop(); } } }