/AutoHotkey.docset/Contents/Resources/Documents/scripts/WinLIRC.htm
HTML | 297 lines | 256 code | 41 blank | 0 comment | 0 complexity | cf67d1faae4eff403840ccac954ea3b0 MD5 | raw file
- <!DOCTYPE HTML>
- <html>
- <head>
- <title>WinLIRC Client</title>
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <link href="../static/theme.css" rel="stylesheet" type="text/css" />
- <script src="../static/content.js" type="text/javascript"></script>
- <meta name="description" content="This open-source WinLIRC client can perform keystrokes, mouse clicks, and other actions in response to buttons you press on your remote control.">
- </head>
- <body>
- <h1>WinLIRC Client</h1>
- <p>This script receives notifications from <a href="http://winlirc.sourceforge.net">WinLIRC</a> whenever you press
- a button on your remote control. It can be used to automate Winamp,
- Windows Media Player, etc. It's easy to configure. For example, if
- WinLIRC recognizes a button named "VolUp" on your remote control,
- create a label named VolUp and beneath it use the command
- <code>SoundSet +5</code> to increase the soundcard's volume by 5%.
- </p>
- <p><a href="WinLIRC.ahk">Download This Script</a> | <a href="index.htm">Other Sample Scripts</a> | <a href="../AutoHotkey.htm">Home</a></p>
- <pre class="NoIndent"><em>; Here are the steps to use this script:
- ; 1) Configure WinLIRC to recognize your remote control and its buttons.
- ; WinLIRC is at <a href="http://winlirc.sourceforge.net">http://winlirc.sourceforge.net</a>
- ; 2) Edit the WinLIRC path, address, and port in the CONFIG section below.
- ; 3) Launch this script. It will start the WinLIRC server if needed.
- ; 4) Press some buttons on your remote control. A small window will
- ; appear showing the name of each button as you press it.
- ; 5) Configure your buttons to send keystrokes and mouse clicks to
- ; windows such as Winamp, Media Player, etc. See the examples below.</em>
- <em>; This script requires AutoHotkey 1.0.38.04 or later.
- ; HISTORY OF CHANGES
- ; March 2, 2007:
- ; - Improved reliability via "Critical" in ReceiveData().
- ; October 5, 2005:
- ; - Eliminated Winsock warning dialog "10054" upon system shutdown/logoff.
- ; - Added option "DelayBetweenButtonRepeats" to throttle the repeat speed.</em>
- <em>; -------------------------------------------------
- ; CONFIGURATION SECTION: Set your preferences here.
- ; -------------------------------------------------
- ; Some remote controls repeat the signal rapidly while you're holding down
- ; a button. This makes it difficult to get the remote to send only a single
- ; signal. The following setting solves this by ignoring repeated signals
- ; until the specified time has passed. 200 is often a good setting. Set it
- ; to 0 to disable this feature.</em>
- DelayBetweenButtonRepeats = 200
- <em>; Specify the path to WinLIRC, such as C:\WinLIRC\winlirc.exe</em>
- WinLIRC_Path = %A_ProgramFiles%\WinLIRC\winlirc.exe
- <em>; Specify WinLIRC's address and port. The most common are 127.0.0.1 (localhost) and 8765.</em>
- WinLIRC_Address = 127.0.0.1
- WinLIRC_Port = 8765
- <em>; Do not change the following two lines. Skip them and continue below.</em>
- Gosub WinLIRC_Init
- return
- <em>; --------------------------------------------
- ; ASSIGN ACTIONS TO THE BUTTONS ON YOUR REMOTE
- ; --------------------------------------------
- ; Configure your remote control's buttons below. Use WinLIRC's names
- ; for the buttons, which can be seen in your WinLIRC config file
- ; (.cf file) -- or you can press any button on your remote and the
- ; script will briefly display the button's name in a small window.
- ;
- ; Below are some examples. Feel free to revise or delete them to suit
- ; your preferences.</em>
- VolUp:
- SoundSet +5 <em>; Increase master volume by 5%. On Vista, replace this line with: Send {Volume_Up}</em>
- return
- VolDown:
- SoundSet -5 <em>; Reduce master volume by 5%. On Vista, replace this line with: Send {Volume_Down}</em>
- return
- ChUp:
- WinGetClass, ActiveClass, A
- if ActiveClass in Winamp v1.x,Winamp PE <em>; Winamp is active.</em>
- Send {right} <em>; Send a right-arrow keystroke.</em>
- else <em>; Some other type of window is active.</em>
- Send {WheelUp} <em>; Rotate the mouse wheel up by one notch.</em>
- return
- ChDown:
- WinGetClass, ActiveClass, A
- if ActiveClass in Winamp v1.x,Winamp PE <em>; Winamp is active.</em>
- Send {left} <em>; Send a left-arrow keystroke.</em>
- else <em>; Some other type of window is active.</em>
- Send {WheelDown} <em>; Rotate the mouse wheel down by one notch.</em>
- return
- Menu:
- IfWinExist, Untitled - Notepad
- {
- WinActivate
- }
- else
- {
- Run, Notepad
- WinWait, Untitled - Notepad
- WinActivate
- }
- Send Here are some keystrokes sent to Notepad.{Enter}
- return
- <em>; The examples above give a feel for how to accomplish common tasks.
- ; To learn the basics of AutoHotkey, check out the Quick-start Tutorial
- ; at <a href="http://www.autohotkey.com/docs/Tutorial.htm">http://www.autohotkey.com/docs/Tutorial.htm</a></em>
- <em>; ----------------------------
- ; END OF CONFIGURATION SECTION
- ; ----------------------------
- ; Do not make changes below this point unless you want to change the core
- ; functionality of the script.</em>
- WinLIRC_Init:
- OnExit, ExitSub <em>; For connection cleanup purposes.</em>
- <em>; Launch WinLIRC if it isn't already running:</em>
- Process, Exist, winlirc.exe
- if not ErrorLevel <em>; No PID for WinLIRC was found.</em>
- {
- IfNotExist, %WinLIRC_Path%
- {
- MsgBox The file "%WinLIRC_Path%" does not exist. Please edit this script to specify its location.
- ExitApp
- }
- Run %WinLIRC_Path%
- Sleep 200 <em>; Give WinLIRC a little time to initialize (probably never needed, just for peace of mind).</em>
- }
- <em>; Connect to WinLIRC (or any type of server for that matter):</em>
- socket := ConnectToAddress(WinLIRC_Address, WinLIRC_Port)
- if socket = -1 <em>; Connection failed (it already displayed the reason).</em>
- ExitApp
- <em>; Find this script's main window:</em>
- Process, Exist <em>; This sets ErrorLevel to this script's PID (it's done this way to support compiled scripts).</em>
- DetectHiddenWindows On
- ScriptMainWindowId := WinExist("ahk_class AutoHotkey ahk_pid " . ErrorLevel)
- DetectHiddenWindows Off
- <em>; When the OS notifies the script that there is incoming data waiting to be received,
- ; the following causes a function to be launched to read the data:</em>
- NotificationMsg = 0x5555 <em>; An arbitrary message number, but should be greater than 0x1000.</em>
- OnMessage(NotificationMsg, "ReceiveData")
- <em>; Set up the connection to notify this script via message whenever new data has arrived.
- ; This avoids the need to poll the connection and thus cuts down on resource usage.</em>
- FD_READ = 1 <em>; Received when data is available to be read.</em>
- FD_CLOSE = 32 <em>; Received when connection has been closed.</em>
- if DllCall("Ws2_32\WSAAsyncSelect", "UInt", socket, "UInt", ScriptMainWindowId, "UInt", NotificationMsg, "Int", FD_READ|FD_CLOSE)
- {
- MsgBox % "WSAAsyncSelect() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
- ExitApp
- }
- return
- ConnectToAddress(IPAddress, Port)
- <em>; This can connect to most types of TCP servers, not just WinLIRC.
- ; Returns -1 (INVALID_SOCKET) upon failure or the socket ID upon success.</em>
- {
- VarSetCapacity(wsaData, 400)
- result := DllCall("Ws2_32\WSAStartup", "UShort", 0x0002, "UInt", &wsaData) <em>; Request Winsock 2.0 (0x0002)</em>
- <em>; Since WSAStartup() will likely be the first Winsock function called by this script,</em>
- <em>; check ErrorLevel to see if the OS has Winsock 2.0 available:</em>
- if ErrorLevel
- {
- MsgBox WSAStartup() could not be called due to error %ErrorLevel%. Winsock 2.0 or higher is required.
- return -1
- }
- if result <em>; Non-zero, which means it failed (most Winsock functions return 0 upon success).</em>
- {
- MsgBox % "WSAStartup() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
- return -1
- }
- AF_INET = 2
- SOCK_STREAM = 1
- IPPROTO_TCP = 6
- socket := DllCall("Ws2_32\socket", "Int", AF_INET, "Int", SOCK_STREAM, "Int", IPPROTO_TCP)
- if socket = -1
- {
- MsgBox % "socket() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
- return -1
- }
- <em>; Prepare for connection:</em>
- SizeOfSocketAddress = 16
- VarSetCapacity(SocketAddress, SizeOfSocketAddress)
- InsertInteger(2, SocketAddress, 0, AF_INET) <em>; sin_family</em>
- InsertInteger(DllCall("Ws2_32\htons", "UShort", Port), SocketAddress, 2, 2) <em>; sin_port</em>
- InsertInteger(DllCall("Ws2_32\inet_addr", "AStr", IPAddress), SocketAddress, 4, 4) <em>; sin_addr.s_addr</em>
- <em>; Attempt connection:</em>
- if DllCall("Ws2_32\connect", "UInt", socket, "UInt", &SocketAddress, "Int", SizeOfSocketAddress)
- {
- MsgBox % "connect() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError") . ". Is WinLIRC running?"
- return -1
- }
- return socket <em>; Indicate success by returning a valid socket ID rather than -1.</em>
- }
- ReceiveData(wParam, lParam)
- <em>; By means of OnMessage(), this function has been set up to be called automatically whenever new data
- ; arrives on the connection. It reads the data from WinLIRC and takes appropriate action depending
- ; on the contents.</em>
- {
- Critical <em>; Prevents another of the same message from being discarded due to thread-already-running.</em>
- socket := wParam
- ReceivedDataSize = 4096 <em>; Large in case a lot of data gets buffered due to delay in processing previous data.</em>
- VarSetCapacity(ReceivedData, ReceivedDataSize, 0) <em>; 0 for last param terminates string for use with recv().</em>
- ReceivedDataLength := DllCall("Ws2_32\recv", "UInt", socket, "Str", ReceivedData, "Int", ReceivedDataSize, "Int", 0)
- if ReceivedDataLength = 0 <em>; The connection was gracefully closed, probably due to exiting WinLIRC.</em>
- ExitApp <em>; The OnExit routine will call WSACleanup() for us.</em>
- if ReceivedDataLength = -1
- {
- WinsockError := DllCall("Ws2_32\WSAGetLastError")
- if WinsockError = 10035 <em>; WSAEWOULDBLOCK, which means "no more data to be read".</em>
- return 1
- if WinsockError <> 10054 <em>; WSAECONNRESET, which happens when WinLIRC closes via system shutdown/logoff.</em>
- <em>; Since it's an unexpected error, report it. Also exit to avoid infinite loop.</em>
- MsgBox % "recv() indicated Winsock error " . WinsockError
- ExitApp <em>; The OnExit routine will call WSACleanup() for us.</em>
- }
- <em>; Otherwise, process the data received. Testing shows that it's possible to get more than one line</em>
- <em>; at a time (even for explicitly-sent IR signals), which the following method handles properly.</em>
- <em>; Data received from WinLIRC looks like the following example (see the WinLIRC docs for details):</em>
- <em>; 0000000000eab154 00 NameOfButton NameOfRemote</em>
- Loop, parse, ReceivedData, `n, `r
- {
- if A_LoopField in ,BEGIN,SIGHUP,END <em>; Ignore blank lines and WinLIRC's start-up messages.</em>
- continue
- ButtonName = <em>; Init to blank in case there are less than 3 fields found below.</em>
- Loop, parse, A_LoopField, %A_Space% <em>; Extract the button name, which is the third field.</em>
- if A_Index = 3
- ButtonName := A_LoopField
- global DelayBetweenButtonRepeats <em>; Declare globals to make them available to this function.</em>
- static PrevButtonName, PrevButtonTime, RepeatCount <em>; These variables remember their values between calls.</em>
- if (ButtonName != PrevButtonName || A_TickCount - PrevButtonTime > DelayBetweenButtonRepeats)
- {
- if IsLabel(ButtonName) <em>; There is a subroutine associated with this button.</em>
- Gosub %ButtonName% <em>; Launch the subroutine.</em>
- else <em>; Since there is no associated subroutine, briefly display which button was pressed.</em>
- {
- if (ButtonName == PrevButtonName)
- RepeatCount += 1
- else
- RepeatCount = 1
- SplashTextOn, 150, 20, Button from WinLIRC, %ButtonName% (%RepeatCount%)
- SetTimer, SplashOff, 3000 <em>; This allows more signals to be processed while displaying the window.</em>
- }
- PrevButtonName := ButtonName
- PrevButtonTime := A_TickCount
- }
- }
- return 1 <em>; Tell the program that no further processing of this message is needed.</em>
- }
- SplashOff:
- SplashTextOff
- SetTimer, SplashOff, Off
- return
- InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
- <em>; The caller must ensure that pDest has sufficient capacity. To preserve any existing contents in pDest,
- ; only pSize number of bytes starting at pOffset are altered in it.</em>
- {
- Loop %pSize% <em>; Copy each byte in the integer into the structure as raw binary data.</em>
- DllCall("RtlFillMemory", "UInt", &pDest + pOffset + A_Index-1, "UInt", 1, "UChar", pInteger >> 8*(A_Index-1) & 0xFF)
- }
- ExitSub: <em>; This subroutine is called automatically when the script exits for any reason.
- ; MSDN: "Any sockets open when WSACleanup is called are reset and automatically
- ; deallocated as if closesocket was called."</em>
- DllCall("Ws2_32\WSACleanup")
- ExitApp
- </pre>
- </body>
- </html>