Python:鼠标向下计数,鼠标向上时停止

时间:2016-11-20 14:23:37

标签: python multithreading multiprocessing pyhook

我试图创建一个python脚本,当按下鼠标按钮时,该脚本从0开始计数。我的想法是当按下鼠标左键时使用pyHook进入函数,并在释放鼠标左键时退出函数。我对python很陌生,所以对于糟糕的解释感到抱歉。 一些伪代码:

import pyHook
import pythoncom

def termin():
    return None
def counter(tell):
    a=0
    while True:
        print a
        a+=1
        hm = pyHook.HookManager()
        hm.SubscribeMouseLeftUp(termin)

hm = pyHook.HookManager()
hm.SubscribeMouseLeftDown(counter)
hm.HookMouse()
pythoncom.PumpMessages()
hm.UnhookMouse()

这段代码是我的总体想法,但是我认为它不会起作用,因为SubscribeMouseLeftUp是在离散时间发生的。我正在寻找的可能是在某种线程或多处理模块中运行计数器函数和终止函数,并在一个函数中使用条件来终止其他运行函数。但我不确定如何使这项工作。

好的,所以我在意志力的评论之后尝试了这个脚本:

import pyHook,time,pythoncom

def counter(go):
    for a in range(5):
        time.sleep(1)
        print a
    return True

hm=pyHook.HookManager()
hm.SubscribeMouseLeftDown(counter)
hm.HookMouse()
pythoncom.PumpMessages()
hm.UnhookMouse()

willpower2727接受的答案是我迄今为止看到的最佳解决方案。在他使用线程发布他的解决方案之前,我做了以下代码:

from multiprocessing import Process,Queue
import pyHook
import time
import pythoncom
import ctypes

def counter(tellerstate,q):
    while True:
        a=0
        tellerstate=q.get()
        if tellerstate==1:
            while True:
                a+=1
                print a
                tellerstate=q.get()
                if tellerstate==0:
                    break
        time.sleep(0.1)

def mousesignal(q):
    def OnDown(go):
        tellstate=1
        q.put(tellstate)
        return None

    def OnUp(go):
        tellstate=0
        q.put(tellstate)
        return None

    def terminate(go):
        if chr(go.Ascii)=='q' or chr(go.Ascii)=='Q':
            ctypes.windll.user32.PostQuitMessage(0)
            hm.UnhookKeyboard()
            hm.UnhookMouse()
            q.close()
            q.join_thread()
            process_counter.join()
            process_mousesignal.join() 
        return None

    hm=pyHook.HookManager()
    hm.KeyDown = terminate
    hm.MouseLeftDown = OnDown
    hm.MouseLeftUp = OnUp
    hm.HookMouse()
    hm.HookKeyboard()
    pythoncom.PumpMessages()

if __name__ == '__main__':
    tellerstate=0
    q=Queue()
    process_counter = Process(target=counter,args=(tellerstate,q))
    process_mousesignal = Process(target=mousesignal,args=(q,))
    process_mousesignal.start()
    process_counter.start()

我对此代码的预期行为是计数器和mousesignal函数应作为单独的进程运行。在mousesignal过程中,我根据鼠标输入将0或1放入队列。计数器函数连续运行并读取Queue并使用if语句进入并退出此函数中的循环。这段代码根本不起作用,但我不明白为什么。

2 个答案:

答案 0 :(得分:0)

根据您提供的示例,您似乎想要计算鼠标按钮停止的秒数?您可以在不使用多个线程的情况下执以下示例将打印按下鼠标按钮的时间:

import pyHook
import time
import pythoncom

global starttime
starttime = time.time()
global endtime
endtime = time.time()

def OnDown(go):
    global starttime
    starttime = time.time()
    return True

def OnUp(go):
    global starttime
    global endtime
    endtime = time.time()
    etime = endtime-starttime
    print(etime)
    return True

hm = pyHook.HookManager()
hm.MouseLeftDown = OnDown
hm.MouseLeftUp = OnUp
hm.HookMouse()
pythoncom.PumpMessages()

答案 1 :(得分:0)

好的我有一个使用线程在按住鼠标按钮时执行某些操作的示例。如果用户非常快速地双击鼠标,此示例会中断/卡住。它使用一个锁和一个只在锁被释放时执行某些代码的线程(由鼠标按下触发)。

library(shiny)
library(DT)

ui <- fluidPage(
  title = 'Empty Table Example',
  fluidRow(
    column(4,
     uiOutput("dataAvailable_UI"),
     uiOutput("controls_UI")
    ),
    column(8, DT::dataTableOutput('reviewdata'))
  )
)

server <- function(input, output, session) {
  # similate the available tables in DB
  availableDatasets <- c("mtcars","iris", "cars", "trees")

  dataset <- reactive({
    input$deleteBT # to update when data is deleted

    # only return the corresponding table if user clicked on Review
    if (is.null(input$ReviewBT) || input$ReviewBT == 0)
      return(NULL)

    dataName <- isolate(input$dropdownbox)
    if (is.null(dataName) || !dataName %in% availableDatasets)
      return(NULL)

    # return the selected data
    get(dataName)

  })

  output$reviewdata = DT::renderDataTable(dataset())

  output$dataAvailable_UI <- renderUI({
    # no data is selected
    selectInput("dropdownbox", "Select a Table", 
                choices = c("", availableDatasets)) 
  })

  output$controls_UI <- renderUI({
    # only shows the buttons if a dataset is selected
    if (!is.null(input$dropdownbox) && nchar(input$dropdownbox) > 0)
      div(
        actionButton("ReviewBT", "Review Table"),
        actionButton("deleteBT", "Delete Table")
      )
  })

  observeEvent(input$deleteBT,{
    # delete data and update the selectInput
    dataName <- input$dropdownbox
    if (dataName %in% availableDatasets) {
      availableDatasets <<- availableDatasets[-match(dataName, availableDatasets)]
      updateSelectInput(session, "dropdownbox", choices = c("",availableDatasets))
    }
  })
}
shinyApp(ui = ui, server = server)

使用线程的挑战是它们只能启动一次,因此每次按下鼠标时都无法调用thread.start(),它只能在第一次启动时才能运行。通过允许线程保持活动但不做任何事情(除了经常检查它是否应该),使得在鼠标停机时只能执行一些代码的可能性。有一些更复杂的方法可以改善计算机上的处理负载(可能使用线程条件而不是常规锁)但这是我的一般想法。