• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 750
  • Last Modified:

Detecting inactivity

I'm currently implementing a small chat /instant messenger application for our company's internal use.  I'm 90% done with the exception of "detecting inactivity".  I somehow need to detect keyboard and mouse inactivity while my chat application is running in the background.  If there is no activity for say 10 minutes, my chat application should switch to away mode...

How can I detect keyboard and mouse inactivity while my application is not the active one?  I'm programming in Java...
0
asimalp
Asked:
asimalp
  • 13
  • 7
  • 4
  • +2
5 Solutions
 
krakatoaCommented:
>>  I'm programming in Java...

You've come to the right place then. ;)

Put a timer loop on a listener pair, and make it report when it's up.
0
 
krakatoaCommented:
But don't forget - or rather, please consider first of all - that automatic detection of such things may not always be what the client wants. What happens if a user spills coffee over his trousers and is cleaning it up, so cant type, but still wants to see what the tohers say. If an away icon appears for him, then it could have undesireable consequences.
0
 
CEHJCommented:
You could 'mirror' the event queue. Implement a mouse/keyboard listener that add enqueues the 'events' (it doesn't have to be the events themselves) onto a queue. These events would be dequeued. When the queue is empty you set off a Timer that increments a counter. The timer is cancelled as soon as more events are enqueued. If the counter reaches a certain value - then you know there's been no activity for some time.
0
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

 
krakatoaCommented:
IOW - think carefully before proxying-away the users rights.
0
 
CEHJCommented:
In fact it's easier than that - you can hook the real event queue:

http://java.sun.com/j2se/1.4.2/docs/api/java/awt/Toolkit.html#addAWTEventListener(java.awt.event.AWTEventListener, long)
0
 
objectsCommented:
You can't, (without the use of JNI of course)
0
 
CEHJCommented:
You'll probably find that the following is sufficient as the parameter to that function:

AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK
0
 
Tommy BraasCommented:
Just like objects said, you can't do what you want without using JNI, at least not if your application is supposed play nice with the other applications.

You need to hook into the operating system event queue, using native code, in order to achieve your goal.
0
 
krakatoaCommented:
You may make a timer, and that timer routine's clock gets reset to zero if the keystroke or mouse listener has fired, otherwise it implements or prompts the inactivity - away - flag to be set, then sleeps.
0
 
CEHJCommented:
The bit that's been decribed by some people here as impossible without native code access is actually the easy bit. Here it is:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/**
 *  Hook the AWT event queue
 *
 * @author     Administrator
 * @created    19 February 2004
 */
public class F extends JFrame  implements AWTEventListener, ActionListener {

      private void setGui() {
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JButton button = new JButton("Click me");
            button.addActionListener(this);
            JPanel buttonPanel = new JPanel();
            buttonPanel.add(button);
            Container c = getContentPane();
            c.add(buttonPanel);
            Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK );
            setSize(200, 200);
      }
      
      public void eventDispatched(AWTEvent event) {
            System.out.println("AWTEvent heard: " + event.paramString());
      }

      public void actionPerformed(ActionEvent event) {
            System.out.println("ActionEvent heard: " + event.paramString());
      }
      
      public static void main(String[] args) {
            F f = new F();
            f.setGui();
            f.setVisible(true);
      }
}


0
 
krakatoaCommented:
>> Detecting inactivity

I hope the question's title is not indicative of the questioner's intent! If that makes sense ;)
0
 
asimalpAuthor Commented:
Dear krakatoa, CEHJ, objects and orangehead911,

Thank you very much for all your comments.  I definetely wasn't expecting such feedback especially over the weekend.  Sorry for my "inactivity" on the issue.  I just noticed all your messages.

krakatoa and CEHJ.  I tried using listeners, however listeners only work within the boundaries of my active Java Application.  My main problem is to detect inactivity when the user is actually working on some other applications.  You know messenger applications like ICQ and AIM...  They spend most of their time in the background until the user starts chatting with someone.  The chat application that I'm implementing will be automatically linked to our company's live tech support line.  If there are no tech people using their computers, then the live tech support system should automatically turn off.  So we basically don't want to have any accidents in which one of our customers send us a message, and we miss it...

objects and orangehead911.  I think you are on the right track about the use of JNI.  This is what I was suspecting to begin with; however I have no idea as to how I can use JNI?  This chat application will be working on Windows and Mac OS X.  Any ideas as to how I can hook into the operating system event queue?

Thank you very much!

Asim
0
 
Tommy BraasCommented:
I haven't personally hooked into the system event loop, but it should be failry straight forward.

This might be a good starting point for Mac OS X:
http://developer.apple.com/documentation/CoreFoundation/EventsOtherInput-date.html

Here's something possibly useful for Windows:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msaa/msaaccrf_87ja.asp
0
 
CEHJCommented:
I don't quite follow this. You seem to want to detect inactivity in the entire system, in which case you *will* need to use native code, and in Windows, this will probably centre around SetWindowsHookEx.

This is not such a good idea for several reasons:

a. hooking into Windows message queues is potentially troublesome if you get it wrong, can slow the system down and face it, would be troublesome if you got it right anyway
b. Surely if they're not using your app, then they're inactive anyway? OK - you could say the system may be quiet and they're doing other work. That's fine, but wouldn't it be better to give them a 'dead man's handle' hoop to jump through? (i'm sure management will love that ;-)). It means that if they don't register their presence at regular intervals with your app by providing input of any kind, they are effectively absent. API problem solved and they're on their toes LOL
0
 
krakatoaCommented:
I agree with CEHJ. Since when has it anyway been the case that inactivity in one app means that the user is not present on the system somwhere else? If you want to detect inactivity in the java chat application, you can do it as previously described. Or is this question just a joke, like so many that get posted here?
0
 
krakatoaCommented:
>> Since when has it anyway been the case that inactivity in one app means that the user is not present on the system somwhere else? ...

by which I mean of course that it sounds like you need 2 computers for each employee - one to do real work, and one to keep you happy.
0
 
krakatoaCommented:
Your premises are incorrect I would venture to say. You wrote :

"My main problem is to detect inactivity when the user is actually working on some other applications.  You know messenger applications like ICQ and AIM...  They spend most of their time in the background until the user starts chatting with someone.  The chat application that I'm implementing will be automatically linked to our company's live tech support line.  If there are no tech people using their computers, then the live tech support system should automatically turn off.  So we basically don't want to have any accidents in which one of our customers send us a message, and we miss it..."

a) How can a user be "inactive" when he is working on some other applications? If he souldn't be working on the other apps, then they shouldnt be on his PC.
b) If no tech people are "using their computers", then there is nothing to detect anyway;
c) Why would you want to turn it off? On the face of it this makes little sense.
d) What accidents? You mean people ignoring incoming requests, right? If so, that should be handled differently.

It seems to me that what you want is a system that detect inactivity in your app *as well as* in all other apps. That's maybe where you need JNI, although you are going to have a lot of fun when people go to staggered lunch breaks - should make a nice switch case block somewhere.
0
 
krakatoaCommented:
Your best bet is to write threads into your app which launch the other apps via Runtime.exec()'s and hover on waitFor's. That way, you'll know exactly when each user started and stopped an app. Then you can get your java to pop a message on to the techie's screen every so often, to the effect of "If you dont type something soon, clear your desk at 5:00 tonight".
0
 
Tommy BraasCommented:
That last suggestion krakatoa is not a very good one. I am sure that there are plenty examples on the net describing how to register and listen for system event queue events. It might not be trivial, as CEHJ has alluded to, but not insurmountable I am sure.
0
 
krakatoaCommented:
Well I dont know why it wouldnt be a good one - not that I meant it very seriously in the first place though, as I think the question has unrealistic expectations.
0
 
objectsCommented:
The question is totally realistic, and many other applications have implemented exactly the same thing.
But you cannot implement it in Java without use of JNI, I'd suggest asking in Window/Mac programming topics for the native code involved. Once you've got that using JNI to integrate with Java is fairly straight forward.
0
 
CEHJCommented:
>>I'd suggest asking in Window/Mac programming topics for the native code involved.

I can give you that native code, but it's not necessary, nor probably desirable
0
 
krakatoaCommented:
>> and many other applications have implemented exactly the same thing ...

when I said unrealistic, I didnt mean technically. I think you are missing the picture here objects; computers are meant to serve people, not the other way 'round. You may well be able to detect inactivity across the whole system, but what does that tell you? If you applied the same principle to the classic bank teller's problem - which people have tried to do in the past - then you end up with a system that deceives itself into believing its own lies - ie that there are enough resources to cater for demand, or, vice versa, that there are not.

The way an away flag should be raised is by the computer user himself, not by some arbitrary piece of code taking that decision away from the user. There is no argument for automatiing an inactivity flag that could ever handle all the eventualities that occur in real life that would amount to a jot.
0
 
krakatoaCommented:
Of course, the chickens only come home to roost on a question like this when a manager has a client; then, the manager wants his cake and eat it too - he wants to see all the traffic, but doesnt have anything to add, unless and until some situation requires intervention, in which case he's probably going to pick the bone with the techie afterwards offline. Of course, he'll want a much longer timeout on his client in order to be able to do this. :)). LOL.
0
 
krakatoaCommented:
Anyway, the operating system already has an inactivity detector built in - its called the screen saver.
0
 
objectsCommented:
here's the windows code:

static HANDLE hMapObject = NULL;
static DWORD *lastTime = NULL;
static HHOOK keyHook = NULL;
static HHOOK mouseHook = NULL;

static
DWORD*
SetupSharedMemory()
{
     // Set up the shared memory.
     hMapObject = CreateFileMapping(
          (HANDLE) 0xFFFFFFFF, // use paging file
          NULL,                // no security attributes
          PAGE_READWRITE,      // read/write access
          0,                   // size: high 32-bits
          sizeof(DWORD),       // size: low 32-bits
          "timermem"); // name of map object

     if (hMapObject == NULL)
          return NULL;
     
     // The first process to attach initializes memory.
     bool fInit = (GetLastError() != ERROR_ALREADY_EXISTS);
     
     // Get a pointer to the file-mapped shared memory.
     lastTime = (DWORD*) MapViewOfFile(
          hMapObject,     // object to map view of
          FILE_MAP_WRITE, // read/write access
          0,              // high offset:  map from
          0,              // low offset:   beginning
          0);             // default: map entire file

     if (lastTime == NULL)
          return NULL;
     
     *lastTime = GetTickCount();

     return lastTime;
}


LRESULT
CALLBACK
KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
     if (code < 0)
          return CallNextHookEx(keyHook, code, wParam, lParam);

     if (lastTime == NULL)
          lastTime = SetupSharedMemory();

     if (lastTime)
          *lastTime = GetTickCount();

     return 0;
}


LRESULT
CALLBACK
MouseProc(int code, WPARAM wParam, LPARAM lParam)
{
     if (code < 0)
          return CallNextHookEx(mouseHook, code, wParam, lParam);

     if (lastTime == NULL)
          lastTime = SetupSharedMemory();

     if (lastTime)
          *lastTime = GetTickCount();

     return 0;
}


DWORD
GetCurrentTime()
{
     return GetTickCount();
}


DWORD
GetLastActiveTime()
{
     if (lastTime == NULL)
          lastTime = SetupSharedMemory();

     if (lastTime)
          return *lastTime;
     
     return 0;
}


BOOL
SetHooks()
{
     // Set up the shared memory.
     lastTime = SetupSharedMemory();
     if (lastTime == NULL)
          return FALSE;
     *lastTime = GetTickCount();

     // Set up the keyboard hook.
     keyHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, theApp.m_hInstance, NULL);
     if (keyHook == NULL)
     {
          UnmapViewOfFile(lastTime);
          CloseHandle(hMapObject);
          return false;
     }

     // Set up the mouse hook.
     mouseHook = SetWindowsHookEx(WH_MOUSE, MouseProc, theApp.m_hInstance, NULL);
     if (mouseHook == NULL)
     {
          UnhookWindowsHookEx(keyHook);
          UnmapViewOfFile(lastTime);
          CloseHandle(hMapObject);
          return FALSE;
     }

     return TRUE;
}


void
RemoveHooks()
{
     if (keyHook)
          UnhookWindowsHookEx(keyHook);
     if (mouseHook)
          UnhookWindowsHookEx(mouseHook);
     if (lastTime)
          UnmapViewOfFile(lastTime);
     if (hMapObject)
          CloseHandle(hMapObject);
}

0
 
asimalpAuthor Commented:
objects, thank you very much for the code you have provided!  I think this is the solution to our problem.  Now, I'll just go ahead and figure out JNI to hook-up this code to my Java program.

orangehead911, thank you very much for the links and all the input.

CEHJ, thank you very much for your comments and the code piece you have provided.

krakatoa, the main problem is this:  8 am in the morning, tech people come to work.  Turn on their chat applications.  Then they start doing whatever they need to do (write programs, design websites, write HTML code, answer support emails...).  During this time, from time to time, chat application pops up with questions from our customers.  Of course, the support people answer these questions...  At lunch time however, when they are all away from their computers (eating lunch), they might forget the turn off the chat application that usually runs in the background.  In that case, our customers might still send messages, but this time there is no one to reply...  The same case applies when the support people leave office at 6 pm...  We happen to leave all our computers on through out the night.  Anyway, there is no reason to get very philosophical and question the need for such a program.  We need this feature simply because the company officials want it.  I personally think it makes sense.  But I do respect your opinion.  Thank you very much for all your input.
0
 
Tommy BraasCommented:
My pleasure! =-)
0
 
objectsCommented:
0
 
CEHJCommented:
8-)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 13
  • 7
  • 4
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now