<commit_before>package hooktest

/*
 * Copyright (c) 2016 <NAME>
 * Licensed under the MIT License.
 */

//import scala.concurrent._
//import ExecutionContext.Implicits.global
import java.util.concurrent.SynchronousQueue
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean

import win32ex.WinUserX.{ MSLLHOOKSTRUCT => HookInfo }

object EventWaiter {
    // http://hsmemo.github.io/articles/no3059sSJ.html
    private val THREAD_PRIORITY = 7 // THREAD_PRIORITY_ABOVE_NORMAL
    
    private val ctx = Context
    private val logger = ctx.logger
    private val sync = new SynchronousQueue[MouseEvent](true)
    
    private val waiting = new AtomicBoolean(false)
    private var waitingEvent: MouseEvent = null
    private val offerThread = Thread.currentThread()
    
    private def setFlagsOffer(me: MouseEvent) {
        //logger.debug("setFlagsOffer")
        me match {
            case Move(_) => {
                logger.debug(s"setFlagsOffer - setResent (Move): ${waitingEvent.name}")
                ctx.LastFlags.setResent(waitingEvent)
                //Thread.sleep(1)
            }
            case LeftUp(_) | RightUp(_) => {
                logger.debug(s"setFlagsOffer - setResent (Up): ${waitingEvent.name}")
                ctx.LastFlags.setResent(waitingEvent)
            }
            case LeftDown(_) | RightDown(_) => {
                logger.debug(s"setFlagsOffer - setSuppressed: ${waitingEvent.name}")
                ctx.LastFlags.setSuppressed(waitingEvent)
                ctx.LastFlags.setSuppressed(me)
                ctx.setStartingScrollMode
            }
            case _ => throw new IllegalStateException(me.name)
        }
    }
    
    def offer(me: MouseEvent): Boolean = {
        if (waiting.get) {
            try {
                val res = sync.offer(me, Context.getPollTimeout, TimeUnit.MILLISECONDS)
                
                if (res)
                    setFlagsOffer(me)
                    
                res
            }
            catch {
                case _: InterruptedException => {
                    logger.info("offer - InterruptedException")
                    false
                }
            }
        }
        else
            false
    }
    
    private def poll(timeout: Long): Option[MouseEvent] = {
        try {
            Option(sync.poll(timeout, TimeUnit.MILLISECONDS))
        }
        finally {
            waiting.set(false)
            offerThread.interrupt()
        }
    }
    
    private def fromTimeout(down: MouseEvent) {
        ctx.LastFlags.setResent(down)
        
        logger.debug(s"wait Trigger (${down.name} -->> Timeout): resend ${down.name}")
        Windows.resendDown(down)
    }
    
    private def fromMove(down: MouseEvent) {
        //ctx.LastFlags.setResent(down)
        logger.debug(s"wait Trigger (${down.name} -->> Move): resend ${down.name}")
        Windows.resendDown(down)
    }
    
    private def fromUp(down: MouseEvent, up: MouseEvent) {
        //ctx.LastFlags.setResent(down)
        
        def resendC(mc: MouseClick) = {
            logger.debug(s"wait Trigger (${down.name} -->> ${up.name}): resend ${mc.name}")
            Windows.resendClick(mc)
        }
        
        def resendUD = {
            logger.debug(s"wait Trigger (${down.name} -->> ${up.name}): resend ${down.name}, ${up.name}")
            Windows.resendDown(down)
            Windows.resendUp(up)
        }
        
        (down, up) match {
            case (LeftDown(_), LeftUp(_)) => {
                if (Mouse.samePoint(down, up))
                    resendC(LeftClick(down.info))
                else
                    resendUD
            }
            case (LeftDown(_), RightUp(_)) => resendUD
            case (RightDown(_), RightUp(_)) => {
                if (Mouse.samePoint(down, up))
                    resendC(RightClick(down.info))
                else
                    resendUD
            }
            case (RightDown(_), LeftUp(_)) => resendUD
        }
    }
    
    private def fromDown(d1: MouseEvent, d2: MouseEvent) {
        //ctx.LastFlags.setSuppressed(d1)
        //ctx.LastFlags.setSuppressed(d2)
        
        logger.debug(s"wait Trigger (${d1.name} -->> ${d2.name}): start scroll mode")
        Context.startScrollMode(d2.info)
    }
    
    private def dispatchEvent(down: MouseEvent, res: MouseEvent) = res match {
        case Move(_) => fromMove(down)
        case LeftUp(_) | RightUp(_) => fromUp(down, res)
        case LeftDown(_) | RightDown(_) => fromDown(down, res)
    }
    
    private val waiterQueue = new SynchronousQueue[MouseEvent](true)
    
    private val waiterThread = new Thread(new Runnable {
        override def run {
            while (true) {
                val down = waiterQueue.take
                
                poll(Context.getPollTimeout) match {
                    case Some(res) => dispatchEvent(down, res)
                    case None => fromTimeout(down)
                }
            }
        }
    })
    
    waiterThread.setDaemon(true)
    waiterThread.setPriority(THREAD_PRIORITY)
    waiterThread.start
    
    // RightDown or LeftDown
    def start(down: MouseEvent) {
        if (!down.isDown)
            throw new IllegalArgumentException
        
        waitingEvent = down
        waiterQueue.put(down)
        waiting.set(true)
    }
}<commit_msg>Improve event offer (Change to loop)<commit_after>package hooktest

/*
 * Copyright (c) 2016 <NAME>
 * Licensed under the MIT License.
 */

//import scala.concurrent._
//import ExecutionContext.Implicits.global
import java.util.concurrent.SynchronousQueue
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean
import scala.annotation.tailrec

import win32ex.WinUserX.{ MSLLHOOKSTRUCT => HookInfo }

object EventWaiter {
    // http://hsmemo.github.io/articles/no3059sSJ.html
    private val THREAD_PRIORITY = 7 // THREAD_PRIORITY_ABOVE_NORMAL
    
    private val ctx = Context
    private val logger = ctx.logger
    private val sync = new SynchronousQueue[MouseEvent](true)
    
    private val waiting = new AtomicBoolean(false)
    private var waitingEvent: MouseEvent = null
    
    private def setFlagsOffer(me: MouseEvent) {
        //logger.debug("setFlagsOffer")
        me match {
            case Move(_) => {
                logger.debug(s"setFlagsOffer - setResent (Move): ${waitingEvent.name}")
                ctx.LastFlags.setResent(waitingEvent)
                //Thread.sleep(1)
            }
            case LeftUp(_) | RightUp(_) => {
                logger.debug(s"setFlagsOffer - setResent (Up): ${waitingEvent.name}")
                ctx.LastFlags.setResent(waitingEvent)
            }
            case LeftDown(_) | RightDown(_) => {
                logger.debug(s"setFlagsOffer - setSuppressed: ${waitingEvent.name}")
                ctx.LastFlags.setSuppressed(waitingEvent)
                ctx.LastFlags.setSuppressed(me)
                ctx.setStartingScrollMode
            }
            case _ => throw new IllegalStateException(me.name)
        }
    }
    
    def offer(me: MouseEvent): Boolean = {
        if (waiting.get) {
            @tailrec
            def loop(): Boolean = { 
                if (sync.offer(me)) {
                    setFlagsOffer(me)
                    true
                }
                else
                    if (waiting.get) loop() else false
            }
            
            loop()
        }
        else
            false
    }
    
    private def poll(timeout: Long): Option[MouseEvent] = {
        try {
            Option(sync.poll(timeout, TimeUnit.MILLISECONDS))
        }
        finally {
            waiting.set(false)
        }
    }
    
    private def fromTimeout(down: MouseEvent) {
        ctx.LastFlags.setResent(down)
        
        logger.debug(s"wait Trigger (${down.name} -->> Timeout): resend ${down.name}")
        Windows.resendDown(down)
    }
    
    private def fromMove(down: MouseEvent) {
        //ctx.LastFlags.setResent(down)
        logger.debug(s"wait Trigger (${down.name} -->> Move): resend ${down.name}")
        Windows.resendDown(down)
    }
    
    private def fromUp(down: MouseEvent, up: MouseEvent) {
        //ctx.LastFlags.setResent(down)
        
        def resendC(mc: MouseClick) = {
            logger.debug(s"wait Trigger (${down.name} -->> ${up.name}): resend ${mc.name}")
            Windows.resendClick(mc)
        }
        
        def resendUD = {
            logger.debug(s"wait Trigger (${down.name} -->> ${up.name}): resend ${down.name}, ${up.name}")
            Windows.resendDown(down)
            Windows.resendUp(up)
        }
        
        (down, up) match {
            case (LeftDown(_), LeftUp(_)) => {
                if (Mouse.samePoint(down, up))
                    resendC(LeftClick(down.info))
                else
                    resendUD
            }
            case (LeftDown(_), RightUp(_)) => resendUD
            case (RightDown(_), RightUp(_)) => {
                if (Mouse.samePoint(down, up))
                    resendC(RightClick(down.info))
                else
                    resendUD
            }
            case (RightDown(_), LeftUp(_)) => resendUD
        }
    }
    
    private def fromDown(d1: MouseEvent, d2: MouseEvent) {
        //ctx.LastFlags.setSuppressed(d1)
        //ctx.LastFlags.setSuppressed(d2)
        
        logger.debug(s"wait Trigger (${d1.name} -->> ${d2.name}): start scroll mode")
        Context.startScrollMode(d2.info)
    }
    
    private def dispatchEvent(down: MouseEvent, res: MouseEvent) = res match {
        case Move(_) => fromMove(down)
        case LeftUp(_) | RightUp(_) => fromUp(down, res)
        case LeftDown(_) | RightDown(_) => fromDown(down, res)
    }
    
    private val waiterQueue = new SynchronousQueue[MouseEvent](true)
    
    private val waiterThread = new Thread(new Runnable {
        override def run {
            while (true) {
                val down = waiterQueue.take
                
                poll(Context.getPollTimeout) match {
                    case Some(res) => dispatchEvent(down, res)
                    case None => fromTimeout(down)
                }
            }
        }
    })
    
    waiterThread.setDaemon(true)
    waiterThread.setPriority(THREAD_PRIORITY)
    waiterThread.start
    
    // RightDown or LeftDown
    def start(down: MouseEvent) {
        if (!down.isDown)
            throw new IllegalArgumentException
        
        waitingEvent = down
        waiterQueue.put(down)
        waiting.set(true)
    }
}
{'fraction_non_alphanumeric': 0.11016153268219384, 'fraction_numerical': 0.0035687453042824945, 'mean_word_length': 1.69526702100734, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 54, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6948326', 'n_tokens_mistral': 3145, 'n_tokens_neox': 3070, 'n_words': 591}