Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
create global hotkeys for a tray app
#1
I want to create global hotkeys for a tray application, for example, as shown in the code below.  
When I press the hotkey F12, the subroutine sub.hk_F12 will be executed.  
When I press the hotkey Ctrl+F12, the subroutine sub.hk_Ctrl_F12 will be executed.  

I haven't found any useful information on the forums.  
Thanks in advance for any suggestions and help.

Function TcpServer2
Code:
Copy      Help
out
if(getopt(nthreads)>1) ret ;;allow single instance
AddTrayIcon "cut.ico" "test_TcpSocket_server[]Ctrl+click to end."

#compile "__TcpSocket"
TcpSocket x.ServerStart(5032 &sub.OnClientConnected)

#sub OnClientConnected
function TcpSocket&client $clientIp param !*reserved

client.Receive(_s 1000)
out F"SERVER: client request: {_s}"

client.Send("response 1")

#sub hk_F12
mes "hk_F12"

#sub hk_Ctrl_F12
mes "hk_Ctrl_F12"
#2
/*******************************************************************************
 *
 * Global Hotkey TCP Server Application
 *
 * Description:
 * This script demonstrates the correct method for creating a tray application
 * with global hotkeys in Quick Macros. It combines a TCP server with a
 * message-handling loop to process system-wide hotkeys (F12 and Ctrl+F12)
 * and tray icon interactions.
 *
 * Core Concepts:
 * 1. Hidden Window: A hidden window (dialog) is created to act as the
 * message receiver for the application.
 * 2. Windows API: Uses RegisterHotKey() to tell Windows to notify our
 * application when the specific key combinations are pressed.
 * 3. Dialog Procedure: A function (sub.DialogProc) is created to process
 * messages sent to the hidden window, such as WM_HOTKEY and tray icon clicks.
 * 4. Message Loop: The `wait` command keeps the script alive, listening for
 * and dispatching messages to the Dialog Procedure.
 * 5. Cleanup: UnregisterHotKey() is called when the application exits to
 * release the hotkeys for other applications to use.
 *
 *******************************************************************************/

function TcpServerWithHotkeys

    // Allow only a single instance of this application to run.
    if(getopt(nthreads)>1) ret
    
    // --- Setup for Hidden Window and Message Handling ---
    // Define a unique class name for our application window.
    str className="GlobalHotkeyServerApp"
    // Specify the function that will handle messages for this window.
    str dialogProc="sub.DialogProc"
    
    // Register the window class with Windows if it hasn't been registered yet.
    WNDCLASSW w
    if(!GetClassLong(0 +&dialogProc &className))
        w.cbClsExtra=4 // Reserve 4 bytes for a pointer.
        w.lpfnWndProc=&dialogProc
        w.lpszClassName=className
        if(!RegisterClassW(&w)) ret ;; Exit if class registration fails.
    
    // Create the hidden window. It won't be visible to the user.
    int hdlg=CreateWindowEx(0 className "TrayAppHiddenWindow" 0 0 0 0 0 0 0 _hinst 0)
    if(!hdlg) ret ;; Exit if window creation fails.

    // --- Add Tray Icon ---
    // The 4th parameter associates the tray icon with our hidden window (hdlg).
    // The 5th parameter is the icon's ID.
    AddTrayIcon "cut.ico" "TCP Server Running[]Ctrl+Left-click to end." "" hdlg 101

    // --- Register Global Hotkeys ---
    // We associate the hotkeys with our hidden window (hdlg).
    // When a hotkey is pressed, Windows will send a WM_HOTKEY message to this window.
    // The second parameter is a unique ID for each hotkey.
    if(!RegisterHotKey(hdlg 1 0 VK_F12)) out "Error: Failed to register hotkey F12."
    if(!RegisterHotKey(hdlg 2 MOD_CONTROL VK_F12)) out "Error: Failed to register hotkey Ctrl+F12."

    // --- Start TCP Server ---
    // The #compile directive should be at the top level of the function.
    #compile "__TcpSocket"
    TcpSocket x
    x.ServerStart(5032 &sub.OnClientConnected)
    
    // Store the TcpSocket object's address in the window's extra memory.
    // This allows us to access it later from the dialog procedure.
    SetWindowLong hdlg 0 x

    // --- Main Message Loop ---
    // The `wait` command pauses the script and processes the window message queue.
    // The script will stay here, responsive to events, until the window is destroyed.
    wait 0 H hdlg

    // --- Cleanup on Exit ---
    // This code runs after the message loop ends (i.e., when the window is destroyed).
    out "Exiting application, cleaning up..."
    UnregisterHotKey hdlg 1
    UnregisterHotKey hdlg 2
    // The tray icon is removed automatically when its parent window is destroyed.
ret


//================================================================================
//                            CALLBACK FUNCTIONS
//================================================================================

#sub DialogProc
function# hWnd message wParam lParam

// This function is the heart of the event-driven part of the app.
// It receives all messages for our hidden window.

sel message
    case WM_DESTROY
        // This message is sent when DestroyWindow(hWnd) is called.
        // It's the standard way to gracefully end a message loop.
        PostQuitMessage 0
        ret

    case WM_HOTKEY
        // A registered hotkey was pressed!
        // wParam contains the ID of the hotkey that was pressed.
        sel wParam
            case 1 ;; This is the ID for F12
                sub.hk_F12
            case 2 ;; This is the ID for Ctrl+F12
                sub.hk_Ctrl_F12
        ret

    case WM_APP+1 // Tray icon message (AddTrayIcon uses WM_APP+1 by default)
        // lParam contains the specific mouse event that occurred on the tray icon.
        // Check if Ctrl key was down during a left-click to exit.
        if(lParam=WM_LBUTTONDOWN and GetMod & 4) ;; 4 is the flag for the Ctrl key
            out "Ctrl+Click detected on tray icon. Shutting down."
            DestroyWindow hWnd // This will end the message loop and exit the app.
        ret

// For all other messages, use the default window procedure.
ret DefWindowProc(hWnd message wParam lParam)


#sub OnClientConnected
function TcpSocket&client $clientIp param !*reserved
// This is your original TCP connection handler.
// It can be called at any time, independent of the UI messages.
client.Receive(_s 1000)
out F"SERVER: Client request: {_s}"
client.Send("response from server")


#sub hk_F12
// This subroutine is now correctly called by the WM_HOTKEY handler.
mes "F12 Hotkey Pressed!" "Global Hotkey"


#sub hk_Ctrl_F12
// This subroutine is now correctly called by the WM_HOTKEY handler.
mes "Ctrl+F12 Hotkey Pressed!" "Global Hotkey"
#3
Thank you for your help.
The code seems to be AI-generated and contains some errors, but I can still learn from some of its ideas. I still haven't managed to solve it.
#4
Yes I was using that to help solve it. I'll try a few other ways and I'll try to post again soon.


Forum Jump:


Users browsing this thread: 1 Guest(s)