0

I am trying to create a sample application that monitors key strokes from scala on a windows machine using the jNativeHook library.

I have the following listener that listens for events,

object KeyListener extends org.jnativehook.keyboard.NativeKeyListener {

  val keyPressedActor = implicitly[ActorSystem].actorOf(Props[KeyPressedActor](), "KeyPressedActor")

  def nativeKeyPressed(event: NativeKeyEvent): Unit = {
    keyPressedActor ! event    
  }
 //blank override two more methods.
}

The main driver app that plugs the listener,

object ConsoleApp extends App {
  try {
    GlobalScreen.registerNativeHook();
    GlobalScreen.addNativeKeyListener(KeyListener)
  } catch {
    case nativehookException: NativeHookException => System.out.println("Encountered error while Hooking to global screen" + nativehookException.fillInStackTrace())
    case ex: Exception                            => System.out.println("Miserable ! Shouldn't have happened ." + ex.fillInStackTrace())
  }
}

And this is the implementation of the actor that i want to store the key strokes in some collection,

class KeyPressedActor extends Actor {
  var testQueue = new scala.collection.mutable.Queue[String]()

  def receive = {
    case event: NativeKeyEvent =>

      if (event.paramString().contains("modifiers=Ctrl")) {
         testQueue.enqueue("this_is_test")        
      }

    case _ => System.out.println("Bummer !  You are NOT supposed to see THIS !")
  }
}

Now i am seeing each time the actor enters the block where we add a string to the queue it does not remember the last element that got inserted into it.

I cannot understand why this is happening. This problem is not seen if i just have a Main app that sends messages to the actor. I cannot put a finger on why this is happening.


Update :

Actually there is something else going on with the code in a section i did not copy here initially. So if i have this inside the if block of the actor ,

NativeKeyEvent.getKeyText(event.getKeyCode) match {
          case "C" =>   
                        isCPressed = true
          case "V" => isVPressed = true
          case "N" => isNPressed = true

this behavior is observed. I changed this code to this ,

 val keyCode = NativeKeyEvent.getKeyText(event.getKeyCode)

        if (keyCode.equalsIgnoreCase("c")) {
         testQueue.enqueue("this_is_test")
        }

I wonder if this means that the match statement is running on some different context/thread ???

Som Bhattacharyya
  • 3,972
  • 35
  • 54
  • What is your test for checking whether or not it 'remembers the last element that got inserted' ? – Erix Aug 02 '17 at 12:19
  • Well i am currently using breakpoint in eclipse. But i have tried using a print over the queue as well. This is the smallest working code that i could do. – Som Bhattacharyya Aug 02 '17 at 12:21
  • Your `queue` is both mutable and a var. That's confusing. – rethab Aug 02 '17 at 12:47
  • That is because var or val should affect the reference while the collection itself being mutable affects the contents. – Som Bhattacharyya Aug 02 '17 at 12:54
  • 1
    In this case the queue can be a val since it isnt being reassigned, unless you are reassigning it outside this code. Anyway I dont see any issue with this. I would verify that only one actor is being created and only one queue is being created – Erix Aug 02 '17 at 12:55
  • But if i want to have shared state it has to be a var right ? – Som Bhattacharyya Aug 02 '17 at 12:56
  • 1
    what do you mean by shared state? It would only need to be 'var' if you reassign to the same variable name. – Erix Aug 02 '17 at 13:00
  • @Erix Yeah you are correct. Got that. So after a little investigation i have found some other queer behavior. I am updating the question with that information – Som Bhattacharyya Aug 02 '17 at 13:34
  • Why are you getting the key text and comparing the string? Just use the keyCode constants. – Alex Barker Aug 02 '17 at 17:17
  • @AlexBarker yes agreed. But that does not affect the scenario. – Som Bhattacharyya Aug 06 '17 at 07:30

0 Answers0