home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 August / maximum-cd-2010-08.iso / DiscContents / AutoHotkey104805_Install.exe / AutoHotkey.chm / docs / scripts / winlirc.ahk < prev    next >
Encoding:
Text File  |  2009-09-25  |  11.3 KB  |  281 lines

  1. ; WinLIRC Client
  2. ; http://www.autohotkey.com
  3. ; This script receives notifications from WinLIRC whenever you press
  4. ; a button on your remote control. It can be used to automate Winamp,
  5. ; Windows Media Player, etc. It's easy to configure. For example, if
  6. ; WinLIRC recognizes a button named "VolUp" on your remote control,
  7. ; create a label named VolUp and beneath it use the command
  8. ; "SoundSet +5" to increase the soundcard's volume by 5%.
  9.  
  10. ; Here are the steps to use this script:
  11. ; 1) Configure WinLIRC to recognize your remote control and its buttons.
  12. ;    WinLIRC is at http://winlirc.sourceforge.net
  13. ; 2) Edit the WinLIRC path, address, and port in the CONFIG section below.
  14. ; 3) Launch this script. It will start the WinLIRC server if needed.
  15. ; 4) Press some buttons on your remote control. A small window will
  16. ;    appear showing the name of each button as you press it.
  17. ; 5) Configure your buttons to send keystrokes and mouse clicks to
  18. ;    windows such as Winamp, Media Player, etc. See the examples below.
  19.  
  20. ; This script requires AutoHotkey 1.0.38.04 or later.
  21. ; HISTORY OF CHANGES
  22. ; March 2, 2007:
  23. ; - Improved reliability via "Critical" in ReceiveData().
  24. ; October 5, 2005:
  25. ; - Eliminated Winsock warning dialog "10054" upon system shutdown/logoff.
  26. ; - Added option "DelayBetweenButtonRepeats" to throttle the repeat speed.
  27.  
  28. ; -------------------------------------------------
  29. ; CONFIGURATION SECTION: Set your preferences here.
  30. ; -------------------------------------------------
  31. ; Some remote controls repeat the signal rapidly while you're holding down
  32. ; a button. This makes it difficult to get the remote to send only a single
  33. ; signal. The following setting solves this by ignoring repeated signals
  34. ; until the specified time has passed. 200 is often a good setting.  Set it
  35. ; to 0 to disable this feature.
  36. DelayBetweenButtonRepeats = 200
  37.  
  38. ; Specify the path to WinLIRC, such as C:\WinLIRC\winlirc.exe
  39. WinLIRC_Path = %A_ProgramFiles%\WinLIRC\winlirc.exe
  40.  
  41. ; Specify WinLIRC's address and port. The most common are 127.0.0.1 (localhost) and 8765.
  42. WinLIRC_Address = 127.0.0.1
  43. WinLIRC_Port = 8765
  44.  
  45. ; Do not change the following two lines. Skip them and continue below.
  46. Gosub WinLIRC_Init
  47. return
  48.  
  49. ; --------------------------------------------
  50. ; ASSIGN ACTIONS TO THE BUTTONS ON YOUR REMOTE
  51. ; --------------------------------------------
  52. ; Configure your remote control's buttons below. Use WinLIRC's names
  53. ; for the buttons, which can be seen in your WinLIRC config file
  54. ; (.cf file) -- or you can press any button on your remote and the
  55. ; script will briefly display the button's name in a small window.
  56. ; Below are some examples. Feel free to revise or delete them to suit
  57. ; your preferences.
  58.  
  59. VolUp:
  60. SoundSet +5  ; Increase master volume by 5%. On Vista, replace this line with: Send {Volume_Up}
  61. return
  62.  
  63. VolDown:
  64. SoundSet -5  ; Reduce master volume by 5%. On Vista, replace this line with: Send {Volume_Down}
  65. return
  66.  
  67. ChUp:
  68. WinGetClass, ActiveClass, A
  69. if ActiveClass in Winamp v1.x,Winamp PE  ; Winamp is active.
  70.     Send {right}  ; Send a right-arrow keystroke.
  71. else  ; Some other type of window is active.
  72.     Send {WheelUp}  ; Rotate the mouse wheel up by one notch.
  73. return
  74.  
  75. ChDown:
  76. WinGetClass, ActiveClass, A
  77. if ActiveClass in Winamp v1.x,Winamp PE  ; Winamp is active.
  78.     Send {left}  ; Send a left-arrow keystroke.
  79. else  ; Some other type of window is active.
  80.     Send {WheelDown}  ; Rotate the mouse wheel down by one notch.
  81. return
  82.  
  83. Menu:
  84. IfWinExist, Untitled - Notepad
  85. {
  86.     WinActivate
  87. }
  88. else
  89. {
  90.     Run, Notepad
  91.     WinWait, Untitled - Notepad
  92.     WinActivate
  93. }
  94. Send Here are some keystrokes sent to Notepad.{Enter}
  95. return
  96.  
  97. ; The examples above give a feel for how to accomplish common tasks.
  98. ; To learn the basics of AutoHotkey, check out the Quick-start Tutorial
  99. ; at http://www.autohotkey.com/docs/Tutorial.htm
  100.  
  101. ; ----------------------------
  102. ; END OF CONFIGURATION SECTION
  103. ; ----------------------------
  104. ; Do not make changes below this point unless you want to change the core
  105. ; functionality of the script.
  106.  
  107. WinLIRC_Init:
  108. OnExit, ExitSub  ; For connection cleanup purposes.
  109.  
  110. ; Launch WinLIRC if it isn't already running:
  111. Process, Exist, winlirc.exe
  112. if not ErrorLevel  ; No PID for WinLIRC was found.
  113. {
  114.     IfNotExist, %WinLIRC_Path%
  115.     {
  116.         MsgBox The file "%WinLIRC_Path%" does not exist. Please edit this script to specify its location.
  117.         ExitApp
  118.     }
  119.     Run %WinLIRC_Path%
  120.     Sleep 200  ; Give WinLIRC a little time to initialize (probably never needed, just for peace of mind).
  121. }
  122.  
  123. ; Connect to WinLIRC (or any type of server for that matter):
  124. socket := ConnectToAddress(WinLIRC_Address, WinLIRC_Port)
  125. if socket = -1  ; Connection failed (it already displayed the reason).
  126.     ExitApp
  127.  
  128. ; Find this script's main window:
  129. Process, Exist  ; This sets ErrorLevel to this script's PID (it's done this way to support compiled scripts).
  130. DetectHiddenWindows On
  131. ScriptMainWindowId := WinExist("ahk_class AutoHotkey ahk_pid " . ErrorLevel)
  132. DetectHiddenWindows Off
  133.  
  134. ; When the OS notifies the script that there is incoming data waiting to be received,
  135. ; the following causes a function to be launched to read the data:
  136. NotificationMsg = 0x5555  ; An arbitrary message number, but should be greater than 0x1000.
  137. OnMessage(NotificationMsg, "ReceiveData")
  138.  
  139. ; Set up the connection to notify this script via message whenever new data has arrived.
  140. ; This avoids the need to poll the connection and thus cuts down on resource usage.
  141. FD_READ = 1     ; Received when data is available to be read.
  142. FD_CLOSE = 32   ; Received when connection has been closed.
  143. if DllCall("Ws2_32\WSAAsyncSelect", "UInt", socket, "UInt", ScriptMainWindowId, "UInt", NotificationMsg, "Int", FD_READ|FD_CLOSE)
  144. {
  145.     MsgBox % "WSAAsyncSelect() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
  146.     ExitApp
  147. }
  148. return
  149.  
  150.  
  151.  
  152. ConnectToAddress(IPAddress, Port)
  153. ; This can connect to most types of TCP servers, not just WinLIRC.
  154. ; Returns -1 (INVALID_SOCKET) upon failure or the socket ID upon success.
  155. {
  156.     VarSetCapacity(wsaData, 400)
  157.     result := DllCall("Ws2_32\WSAStartup", "UShort", 0x0002, "UInt", &wsaData) ; Request Winsock 2.0 (0x0002)
  158.     ; Since WSAStartup() will likely be the first Winsock function called by this script,
  159.     ; check ErrorLevel to see if the OS has Winsock 2.0 available:
  160.     if ErrorLevel
  161.     {
  162.         MsgBox WSAStartup() could not be called due to error %ErrorLevel%. Winsock 2.0 or higher is required.
  163.         return -1
  164.     }
  165.     if result  ; Non-zero, which means it failed (most Winsock functions return 0 upon success).
  166.     {
  167.         MsgBox % "WSAStartup() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
  168.         return -1
  169.     }
  170.  
  171.     AF_INET = 2
  172.     SOCK_STREAM = 1
  173.     IPPROTO_TCP = 6
  174.     socket := DllCall("Ws2_32\socket", "Int", AF_INET, "Int", SOCK_STREAM, "Int", IPPROTO_TCP)
  175.     if socket = -1
  176.     {
  177.         MsgBox % "socket() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
  178.         return -1
  179.     }
  180.  
  181.     ; Prepare for connection:
  182.     SizeOfSocketAddress = 16
  183.     VarSetCapacity(SocketAddress, SizeOfSocketAddress)
  184.     InsertInteger(2, SocketAddress, 0, AF_INET)   ; sin_family
  185.     InsertInteger(DllCall("Ws2_32\htons", "UShort", Port), SocketAddress, 2, 2)   ; sin_port
  186.     InsertInteger(DllCall("Ws2_32\inet_addr", "Str", IPAddress), SocketAddress, 4, 4)   ; sin_addr.s_addr
  187.  
  188.     ; Attempt connection:
  189.     if DllCall("Ws2_32\connect", "UInt", socket, "UInt", &SocketAddress, "Int", SizeOfSocketAddress)
  190.     {
  191.         MsgBox % "connect() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError") . ". Is WinLIRC running?"
  192.         return -1
  193.     }
  194.     return socket  ; Indicate success by returning a valid socket ID rather than -1.
  195. }
  196.  
  197.  
  198.  
  199. ReceiveData(wParam, lParam)
  200. ; By means of OnMessage(), this function has been set up to be called automatically whenever new data
  201. ; arrives on the connection.  It reads the data from WinLIRC and takes appropriate action depending
  202. ; on the contents.
  203. {
  204.     Critical  ; Prevents another of the same message from being discarded due to thread-already-running.
  205.     socket := wParam
  206.     ReceivedDataSize = 4096  ; Large in case a lot of data gets buffered due to delay in processing previous data.
  207.  
  208.     VarSetCapacity(ReceivedData, ReceivedDataSize, 0)  ; 0 for last param terminates string for use with recv().
  209.     ReceivedDataLength := DllCall("Ws2_32\recv", "UInt", socket, "Str", ReceivedData, "Int", ReceivedDataSize, "Int", 0)
  210.     if ReceivedDataLength = 0  ; The connection was gracefully closed, probably due to exiting WinLIRC.
  211.         ExitApp  ; The OnExit routine will call WSACleanup() for us.
  212.     if ReceivedDataLength = -1
  213.     {
  214.         WinsockError := DllCall("Ws2_32\WSAGetLastError")
  215.         if WinsockError = 10035  ; WSAEWOULDBLOCK, which means "no more data to be read".
  216.             return 1
  217.         if WinsockError <> 10054 ; WSAECONNRESET, which happens when WinLIRC closes via system shutdown/logoff.
  218.             ; Since it's an unexpected error, report it.  Also exit to avoid infinite loop.
  219.             MsgBox % "recv() indicated Winsock error " . WinsockError
  220.         ExitApp  ; The OnExit routine will call WSACleanup() for us.
  221.     }
  222.     ; Otherwise, process the data received. Testing shows that it's possible to get more than one line
  223.     ; at a time (even for explicitly-sent IR signals), which the following method handles properly.
  224.     ; Data received from WinLIRC looks like the following example (see the WinLIRC docs for details):
  225.     ; 0000000000eab154 00 NameOfButton NameOfRemote
  226.     Loop, parse, ReceivedData, `n, `r
  227.     {
  228.         if A_LoopField in ,BEGIN,SIGHUP,END  ; Ignore blank lines and WinLIRC's start-up messages.
  229.             continue
  230.         ButtonName =  ; Init to blank in case there are less than 3 fields found below.
  231.         Loop, parse, A_LoopField, %A_Space%  ; Extract the button name, which is the third field.
  232.             if A_Index = 3
  233.                 ButtonName := A_LoopField
  234.         global DelayBetweenButtonRepeats  ; Declare globals to make them available to this function.
  235.         static PrevButtonName, PrevButtonTime, RepeatCount  ; These variables remember their values between calls.
  236.         if (ButtonName != PrevButtonName || A_TickCount - PrevButtonTime > DelayBetweenButtonRepeats)
  237.         {
  238.             if IsLabel(ButtonName)  ; There is a subroutine associated with this button.
  239.                 Gosub %ButtonName%  ; Launch the subroutine.
  240.             else ; Since there is no associated subroutine, briefly display which button was pressed.
  241.             {
  242.                 if (ButtonName == PrevButtonName)
  243.                     RepeatCount += 1
  244.                 else
  245.                     RepeatCount = 1
  246.                 SplashTextOn, 150, 20, Button from WinLIRC, %ButtonName% (%RepeatCount%)
  247.                 SetTimer, SplashOff, 3000  ; This allows more signals to be processed while displaying the window.
  248.             }
  249.             PrevButtonName := ButtonName
  250.             PrevButtonTime := A_TickCount
  251.         }
  252.     }
  253.     return 1  ; Tell the program that no further processing of this message is needed.
  254. }
  255.  
  256.  
  257.  
  258. SplashOff:
  259. SplashTextOff
  260. SetTimer, SplashOff, Off
  261. return
  262.  
  263.  
  264.  
  265. InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
  266. ; The caller must ensure that pDest has sufficient capacity.  To preserve any existing contents in pDest,
  267. ; only pSize number of bytes starting at pOffset are altered in it.
  268. {
  269.     Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
  270.         DllCall("RtlFillMemory", "UInt", &pDest + pOffset + A_Index-1, "UInt", 1, "UChar", pInteger >> 8*(A_Index-1) & 0xFF)
  271. }
  272.  
  273.  
  274.  
  275. ExitSub:  ; This subroutine is called automatically when the script exits for any reason.
  276. ; MSDN: "Any sockets open when WSACleanup is called are reset and automatically
  277. ; deallocated as if closesocket was called."
  278. DllCall("Ws2_32\WSACleanup")
  279. ExitApp
  280.