EloiStree / 2024_05_23_HelloStreamDeckGirleek

In the context of Girleek and a QA testing workshop. We are going to learn how to remote control game with code in a steam deck hub way.
0 stars 0 forks source link

Guide: Scratch à fausses touches sur son Window #38

Open EloiStree opened 6 months ago

EloiStree commented 6 months ago

Bienvenue dans ce guide

Bienvenue à vous dans ce guide sur comment contrôler des jeux en local sur Windows et des ordinateurs à distance à l'aide d'un entier entre -2147483648 et 2147483647.

Le but de l'atelier est de pratiquer Python et Scratch, car tous deux vous permettent d'apprendre à programmer et de créer des macros (succession d'actions dans le temps).

Si vous maîtrisez cet exercice, vous gagnerez le pouvoir de contrôler à distance toutes les actions possibles sur des ordinateurs distants via Python :).

Liste non exhaustive :

Python est extrêmement versatile et alimenté par la communauté.

Bon apprentissage à vous.

L'utilité d'utiliser un entier avec 4 milliards de possibilités ?

Je peux vous trouver d'autres raisons issues de mon passé qui m'amènent à utiliser des entiers comme commande d'action à distance.

Exemple : contrôler un drone en utilisant ces deux joysticks

image

190009876

Avec un peu plus de précisions si nécessaire :

2099887766

Exercice 1

Dans cet atelier, nous allons apprendre via un Drum Pad en Scratch sur votre ordinateur.

image

Exercice 2

Via une table d'indexation et de l'UDP, vous allez contrôler un champion dans World of Warcraft.

Le but de l'exercice est en groupe d'aller tuer Lardeur : image

Scratch demo:

EloiStree commented 6 months ago

Créé un Drum Pad / Stream deck

Dans ce premier exercice nous créons un interface graphique sur Scratch pour plus tard controller des actions sur notre ordinateur.

Scratch de ce tutorial: https://scratch.mit.edu/projects/1022612664/editor

Créé un compte Scratch https://scratch.mit.edu.

image

Créé un nouveal project Scratch

image

Donner un nom au projet et sauvegarder

image

Créé un variable "wsvar nom_que_vous_voulez"

Ce qui est imporant ici c'est d'utiliser le "wsvar " au début du nom pour facilement la trouver and l'HTML de la page web. image

Utiliser un évènement de touche pour set un "wsvar"

image

Trouver un image de Drum Pad en vue du dessus

Utiliser Remove Background: https://www.remove.bg Et Krita (ou autre): https://krita.org/fr/ Pour nettoyer l'image. Group après remove background image

Seul après recadrage dans Krita. DrumPad

Importer l'image

image

Renommer le pad et dimensionner

image

Créér un évènement de click et set wsvar à un nombre

image

Si vous avez besoin de cliquer plusieurs fois d'affiler sur le bouton. (Car le code qui suit détecte le changement de valeur seulement.) image

Dupliquer autant que necessaire pour vous

image

Cette tache est un peu longue à faire car il faut tout dupliquer puis donner un numéro à la main à toutes les touches. (76 C'étais bien pour mon image.)

image

Personnaliser un bouton

Si vous avez le temps, vous pouvez personnaliser les boutons avec un constume. image image

image image image

Astuce: Vous pouvez double cliquer sur une image en jeu dans l'éditeur pour les customiser

EloiStree commented 6 months ago

2 Extraire le nombre dans "wsvar " avec Tamper Monkey

Ici l'exercice n'est pas de comprendre le code que nous allons utiliser mais de le copier coller.

Aller sur https://www.tampermonkey.net

image

Installer le module dans notre navigateur web

image

image

Lancer le module installer

image ( Double clique sur tamper monkey pour ouvrir le menu )

Ouvrir le Dashboard

image

Ajouter un script à tamper monkey

image

Copier le code pour hack le code HTML de Scratch

Source sur GitHub pour avoir la dernier version: https://github.com/EloiStree/2024_05_10_TamperMonkeyToRsaTunnelingIID/blob/main/ScratchToLocalWebsocket/ScratchVarToLocalWebsocket.js

Code au moment de l'écriture de ce tutorial


// ==UserScript==
// @name         Push Scratch wsvar to Local WS IID
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Source: https://github.com/EloiStree/2024_05_10_TamperMonkeyToRsaTunnelingIID/blob/main/ScratchToLocalWebsocket/ScratchVarToLocalWebsocket.js
// @description  Test zone: https://scratch.mit.edu/projects/1018462085
// @author       Eloi stree
// @match        https://scratch.mit.edu/projects/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=integergames.be
// @require      http://code.jquery.com/jquery-1.8.3.min.js

// @grant        none

// ==/UserScript==
//TO LOOK LATER
//https://github.com/travist/jsencrypt
(function() {
    'use strict';

/*
What this code do ?
This code overlook at the HTML code when you are on https://scratch.mit.edu/projects/*
It searches about the HTML of a variable display in the scratch game that are a HTML Div code.
The div Id are
- name: .monitor_label_ci1ok
- value: .monitor_value_3Yexa

It add the key value in a dictionary if the value changed only to avoid spam when send outside of the script.

With the help of a unsecure websocket client it send the value as a integer converted to 4 bytes in little format.
To use this script you need to recover it with a websocket server of your own and turn back the 4 bytes to integer.

*/

//Just show in console that the script is injected
console.log("Hello Tamper to Integer :).\n Websocket client will try to connect to websocket server. \n  ")

// Creating url to push on local computer at the port 7073 the integer that changed.
var socketUrl= 'ws://localhost:7073';
// Defined the var of the future websocket client
var socket = null;
// Will be use to have a way to know that the server is still in theory connected
var isConnectionValide=false;
// Dictionnary that is storing the previous state when a change happened
// Used to detect any change in the Scratch variable
var previousData = {};

// Do we want to display console log in the browser or not.
var useConsoleDebug=false;

/* This function is use to make some test. It allow to push randomply a integer if the connection is still active */
   function PushMessageToServerRandomInteger(){
       if(!isConnectionValide){
           return;
       }
       const randomInt = Math.floor(Math.random() * 1000000000) + 1;
       PushMessageToServerInteger(randomInt)

   }
    /*This function send an integer into a exportable value with the date of when it was detected as a ulong format */
   function PushMessageToServerIntegerDate(integer){
    if(!isConnectionValide){return;}
      var value =integer;
       // Get the current UTC time in milliseconds
     const currentTimeMillis = Date.now();

     // Convert to an unsigned long (assuming 64-bit)
     const ulongVar = BigInt(currentTimeMillis);

     // Create a byte array of length 12
     const byteArray = new Uint8Array(12);
     // Set the first 4 bytes of the array from the value in little-endian format
     byteArray[0] = value & 0xFF;
     byteArray[1] = (value >> 8) & 0xFF;
     byteArray[2] = (value >> 16) & 0xFF;
     byteArray[3] = (value >> 24) & 0xFF;

     // Set the next 8 bytes of the array from ulongVar in little-endian format
     const view = new DataView(byteArray.buffer);
     view.setBigUint64(4, ulongVar, true);
     socket.send(byteArray);
    if(useConsoleDebug)
     console.log("Random date with date:", value)
}

/*This function send an integer into a exportable value and don't attach to it a date value */
function PushMessageToServerInteger(integer){
    if(!isConnectionValide){return;}

      var value =integer;
     const byteArray = new Uint8Array(4);
     byteArray[0] = value & 0xFF;
     byteArray[1] = (value >> 8) & 0xFF;
     byteArray[2] = (value >> 16) & 0xFF;
     byteArray[3] = (value >> 24) & 0xFF;
     socket.send(byteArray);
    if(useConsoleDebug)
     console.log("Int Pushed to web local server:", value)
}

var server_is_offline=false;

/*Try to reconnect with a new websocket client if it detect that the current is for any reason not there */
function ReconnectIfOffline(){

    if (socket !=null && socket && socket.readyState === WebSocket.OPEN) {
    }
    else{
        isConnectionValide=false
        try{
            if(useConsoleDebug)
            console.log('Try estabalish connection with: '+socketUrl);
            socket = new WebSocket(socketUrl);
            // Event listener for when the connection is established
            socket.addEventListener('open', () => {
                console.log('WebSocket connection established');
                isConnectionValide=true
            });

            // Event listener for incoming messages
            socket.addEventListener('message', (event) => {
                console.log('Received message from server:', event.data);

            });

            // Event listener for when the connection is closed
            socket.addEventListener('close', () => {
                console.log('WebSocket connection closed');
                isConnectionValide=false

            });

            // Event listener for errors
            socket.addEventListener('error', (error) => {
                console.error('WebSocket error:', error);
            });
            server_is_offline=false;
            console.log("Server Online");
        }catch(Exception){
            server_is_offline=true;
        }
    }
}

    /*This will send key value as integer if it detect the variable start with "wsvar " and connection is open */
    function sentKeyValueToOpenWebsocket(label, value) {

        if (socket && socket.readyState === WebSocket.OPEN) {
            const lowerStr = label.toLowerCase().trim();

            if (lowerStr.startsWith("wsvar ")) {
                const number = parseInt(value);
                //console.log("The string starts with 'wsvar'");
                if (!isNaN(number)) {

                    console.log("Change detectected wsvar int: "+value)
                    PushMessageToServerInteger(number);
                    //console.log("The string is a valid integer:", number);
                } else {
                    //console.log("The string is not a valid integer");
                }
            }

        }
    }

    /*This will look in the HTML code for the Scratch variable as HTML.
    If it find the div of the key value that start with "wsvar ". It will set them in the dictionary and notify if it changed*/
    function extractAndSendData() {
        var dataString = '';
        // Find all elements with class 'react-contextmenu-wrapper'
        var elements = document.getElementsByClassName('react-contextmenu-wrapper');
        // Iterate through each element
        for (var i = 0; i < elements.length; i++) {
            var element = elements[i];
            // Find elements with classes 'monitor_label_ci1ok' and 'monitor_value_3Yexa' within current element
            var labelElement = element.querySelector('.monitor_label_ci1ok');
            var valueElement = element.querySelector('.monitor_value_3Yexa');

            // Extract text content from label and value elements
            var label = labelElement ? labelElement.textContent.trim() : '';
            var value = valueElement ? valueElement.textContent.trim() : '';

            if (label && value) {
                if(label.startsWith("wsvar ") ){
                   dataString += label + ': ' + value + '\n';
                    if (!previousData[label]) {
                        previousData[label] = value;
                        sentKeyValueToOpenWebsocket(label, value);
                    } else {
                        if (previousData[label] !== value) {
                            previousData[label] = value;

                            console.log("Change detectected: "+value)
                            sentKeyValueToOpenWebsocket(label, value);
                        }
                    }
                }
            }
        }
    }

    if(useConsoleDebug)
        console.log("Interval :) Start ")

    setInterval(ReconnectIfOffline, 1000);
    setInterval(extractAndSendData,15);
    if(useConsoleDebug)
        console.log('Code end reach');

})();

Sauvegarder le code et la page pour aller sur votre projet Scratch

Chercher "Inspect Code" sur votre navigature

Clique droit sur une partie "HTML" du projet.

Il existe sur tout les navigateurs.

Opera GX: image

Brave image

Chrome image

Vous devriez avoir quelque chose comme ceci

image

Rafraichissez votre page avec CTRL+F5

Vous devriez avoir un message comme celui-ci image Le client veut se connecter à un websocket local mais n'y arrive pas car il n'existe pas.

Allons créé un server websocket local

Pour la suite de l'aventure nous avons besoin d'installer Python et de créé un server local.

EloiStree commented 6 months ago

Créé un websocket local avec Python

(Version Window)

Installer Python

Télécharger l'installeur : https://www.python.org/downloads/ image

Valider c'est deux casses ensuite fait next next next. image

Ouvrir le terminal sur window

Par une recherche image

par un Window + R suivit d'un appel cmd image

Vérifier que Python c'est bien installé sur Window

image

Type print("Hello World")

image Voici votre première ligne de commande python sous console. Nous n'allons pas faire du python en console ^^. On va le faire dans un éditeur de code

EloiStree commented 6 months ago

Dire bonjour à python

Ouvrir l'éditeur de code par défaut pour python

image

Ouvrir un fichier Python

image

Ecrire "Hello World"

image

Sauver le fichier

La où vous avez l'habitue. (Attention pas de nom utilisateur avec é, à ou de espace. Règle d'or en information "AlphaNumérique_09" seulement. La raison est que un cartère spécial peu ne pas être reconnu dans certain langage et créé des bugs. Et un espace peu poser problème dans des lignes de commandes n'utilisant pas " " )

image

Pour le fun copier ce script

Astuce F5 pour execute sans le menu

# Ceci est un commentaire en Python
# // Celui-ci en JavaScript et en C#
"""
Ceci est un commentaire sur plusieurs lignes en Python

/* Celui-ci en JavaScript et en C#
*/

"""
print("Hello World")

je_suis_une_variable = 0
print(je_suis_une_variable)

# En Python les variables sont dynamiques
# Elles peuvent donc changer de type de contenu
je_suis_une_variable = "Bonjour"
print(je_suis_une_variable)

variable_avec_du_texte = "J'aime les frites"
variable_avec_un_nombre = 3
# Vous pouvez ajouter du texte avec d'autres types de contenu.
# Mais il faut d'abord le transformer en texte
print("> " + variable_avec_du_texte + ": " + str(variable_avec_un_nombre))

# Python offre un outil pour ne pas devoir faire ça
print(f"> {variable_avec_du_texte}: {variable_avec_un_nombre}")

# print() et str() c'est ce que l'on appelle une méthode
# un bout de code d'un autre développeur qui fait une chose pour nous.

# Vous pouvez en créer vous aussi en les "définissant"
def dire_bonjour():
    print("Bonjour")

# La définition doit toujours être avant son "appel"
# Vous pouvez l'appeler comme ceci
dire_bonjour()

# On aimerait dire bonjour à une personne
def dire_bonjour_a(nom_de_la_personne):
    print(f"Bonjour, {nom_de_la_personne}")

dire_bonjour_a("Eloi")

# On aimerait qu'elle réponde "j'aime les frites" 30 fois
def j_aime_les_frites(nombre_de_print):
    for index in range(nombre_de_print):
        print(f"J'aime les frites ({index})")

j_aime_les_frites(5)

# S'il aime d'autres choses ?
tableau_de_gouts = ["à la sauce Liégeoise", "aux samouraïs", "dans une mitraillette", "avec un œuf"]

# On aimerait qu'elle réponde "j'aime les frites" avec le tableau
def j_aime_les_frites_avec_un_tableau(tableau_de_gouts):
    for valeur_du_tableau in tableau_de_gouts:
        print(f"J'aime les frites {valeur_du_tableau}")

j_aime_les_frites_avec_un_tableau(tableau_de_gouts)

# Mais a-t-il faim ?
boolean_a_t_il_faim = False

def as_tu_faim(boolean_a_t_il_faim):
    if boolean_a_t_il_faim:
        print("Oui, j'ai faim.")
    else:
        print("Non, mais je mangerais bien une frite pour le fun")

as_tu_faim(boolean_a_t_il_faim)

# Comme Python est un langage interprété, on peut
# importer du code au milieu du script
# Mais c'est déconseillé, on le met généralement en première ligne.

# Importation du temps pour attendre qu'Eloi ait faim
import time

# La fonction time.sleep() permet de geler le temps et d'attendre avant d'exécuter la suite du code
time.sleep(1)
print("Et maintenant tu as faim ?")
as_tu_faim(boolean_a_t_il_faim)
time.sleep(1)
print("Toujours pas faim ?")
as_tu_faim(boolean_a_t_il_faim)
time.sleep(1)
print("Ok, dis-moi quand tu as faim")
as_tu_faim(boolean_a_t_il_faim)
time.sleep(1)

# On peut attendre qu'Eloi commence à vouloir manger
import random

while boolean_a_t_il_faim == False:
    as_tu_faim(boolean_a_t_il_faim)
    # On attend aléatoirement qu'Eloi ait faim.
    boolean_a_t_il_faim = random.randint(0, 10) == 0

# Enfin... C'était pas trop tôt
as_tu_faim(boolean_a_t_il_faim)
EloiStree commented 6 months ago

Utiliser un WebSocket local

Pour pouvoir recevoir les informations de votre navigateur, sur votre ordinateur vous aurez besion d'un server local. Une petite application qui tourne pour écouter et retransmettre (ou faire).

Installer ces boites à outils via le terminal

Window + R > CMD

pip3 install websockets
pip3 install asyncio

Copier ce code pour avoir un server local

https://github.com/EloiStree/2024_05_17_BasicPythonUdpWebsocketIID/tree/main/LocalWebsocketServerToBroadcast

websocket_server_port=7073
udp_server_port = 7072

# List of IP:PORT to broadcast the data to the apps    
broadcast_list_udp_target={"127.0.0.1:404"}
broadcast_list_udp_target={"127.0.0.1:405"}

# Set to True if you want to print the received data of clients
debug_received_data = False

def handle_integer_received(integer):
    i=int(integer)
    # If you want it out of the script
    YourCodeHere.handle_integer_received(integer)
    # if you want to broadcast the data to apps with UDP
    broadcast_to_targets(int(i))
    ## If you want in the script
    print(f"R|{integer}")

################### Websocket don't touch  #####################

import asyncio
import websockets
import struct
import os
import socket

# pip3 install websockets
# pip3 install asyncio
# pip3 install struct
# pip3 install socket

filename = "YourCodeHere.py"
if not os.path.exists(filename):
    with open(filename, "w") as f:
        # You can add initial content to the file if you want
        f.write("""# YourCodeHere.py
def handle_integer_received(integer):
    i=int(integer)""")
    print(f"File '{filename}' created successfully!")

import YourCodeHere

def broadcast_to_targets(message):
    for target in broadcast_list_udp_target:
        temp = target.split(":")
        target_address = ("127.0.0.1", "")

        if len(temp) == 2:
            target_address = (temp[0], int(temp[1]))  
        elif len(temp) == 1:
            target_address = ("", int(temp[0]))  

        udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        udp_socket.sendto(struct.pack('<i', message), target_address)
        udp_socket.close()

def get_current_ip():
    hostname = socket.gethostname()
    ip_address = socket.gethostbyname(hostname)
    return ip_address

async def handle_message(websocket, path):
    try:
        async for message in websocket:
            message_length = len(message)

            if message_length == 4:
                value1 = struct.unpack('<i', message)[0]
                if debug_received_data:
                    print(f"Received value: {value1} (format: <i)")
                handle_integer_received(int(value1))
            elif message_length == 12:
                value1, value2 = struct.unpack('<iQ', message)
                if debug_received_data:
                    print(f"Received values: {value1}, {value2} (format: <iQ)")
                handle_integer_received(int(value1))

            elif message_length == 16:
                value1, value2, value3 = struct.unpack('<iiQ', message)
                if debug_received_data:
                    print(f"Received values: {value1}, {value2}, {value3} (format: <iiQ)")
                handle_integer_received(int(value1))
    except websockets.ConnectionClosedError as e:
            print(f"Connection closed with error: {e}")
            # Wait a bit before trying to reconnect
            await asyncio.sleep(5)

start_server = websockets.serve(handle_message, "", websocket_server_port)

asyncio.get_event_loop().run_until_complete(start_server)

print("Current IP:", get_current_ip())
print("WebSocket server is listening on port 7073")

################### UDP don't touch  #####################

def integer_listener_client_udp(host, port):
    # Create a UDP socket
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # Bind the socket to the host and port
    udp_socket.bind((host, port))
    print("UDP integer listener client is now listening on {}:{}".format(host, port))

    try:
        while True:
            # Receive data from the socket
            data, address = udp_socket.recvfrom(64)
            if len(data)==4:
                received_integer = struct.unpack('<i', data)[0]
                handle_integer_received(received_integer)
            elif len(data)==12:
                received_integer = struct.unpack('<iQ', data)[0]
                handle_integer_received(received_integer)
            elif len(data)==16:
                received_integer = struct.unpack('<iiQ', data)[0]
                handle_integer_received(received_integer)
            else: continue
            #print("Received integer:", received_integer, "from", address)

    except KeyboardInterrupt:
        print("UDP integer listener client stopped.")
    finally:
        # Close the socket
        udp_socket.close()

asyncio.get_event_loop().run_in_executor(None, integer_listener_client_udp, "", udp_server_port)

asyncio.get_event_loop().run_forever()

Retourner sur Scratch :)

image

Pousser sur azer et les touches de l'écran:
https://scratch.mit.edu/projects/1022612664/editor/

Profiter de votre magnifique premiers server WebSocket en python !

EloiStree commented 6 months ago

Replace BGB by Wow or other.

EloiStree commented 6 months ago

Scratch à Clavier

Retourner sur le code fait plutôt ensemble.

Vous avez plusieurs choix:

Ouvrez YourCodeHere.py

Dans le code donné plus tôt vous avez un YourCodeHere.handle_integer_received(integer) Celui-ci invoke une action dans le fichier YourCodehere.py à côté

EloiStree commented 6 months ago

Comment faire avec un ordinateur distance

Sur l'ordinateur que vous voulez controller

Installer Python

Voir Exercice précèdent

Copier ce script

Last version: https://github.com/EloiStree/2024_05_17_BasicPythonUdpWebsocketIID/blob/main/SendUdpInteger/ReceivedUdpInteger.py


def handle_integer_received(integer):
    value=int(integer)
    print(value)

import socket
import struct

def integer_listener_client_udp(host, port):
    # Create a UDP socket
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # Bind the socket to the host and port
    udp_socket.bind((host, port))
    print("UDP integer listener client is now listening on {}:{}".format(host, port))

    try:
        while True:
            # Receive data from the socket
            data, address = udp_socket.recvfrom(64)
            if len(data)==4:
                received_integer = struct.unpack('<i', data)[0]
                handle_integer_received(received_integer)
            elif len(data)==12:
                received_integer = struct.unpack('<iQ', data)[0]
                handle_integer_received(received_integer)
            elif len(data)==16:
                received_integer = struct.unpack('<iiQ', data)[0]
                handle_integer_received(received_integer)
            else: continue
            #print("Received integer:", received_integer, "from", address)

    except KeyboardInterrupt:
        print("UDP integer listener client stopped.")
    finally:
        # Close the socket
        udp_socket.close()

# Example usage:
if __name__ == "__main__":
    HOST = "0.0.0.0"   # Listen on all available interfaces
    PORT = 404       # Example port (change to your desired port)
    integer_listener_client_udp(HOST, PORT)

Trouver l'adresse IP de l'ordinateur à controller.

image image

Ouvrir le/les ports

Si vous êtes pressé et non axés sécurité, vous pouvez désactiver les pare feu. image

Si vous voulez n'ouvrir que le port cible. image https://youtu.be/NUaCl5Yqz3g?t=27

EloiStree commented 6 months ago

R

EloiStree commented 6 months ago

R

EloiStree commented 6 months ago

R

EloiStree commented 6 months ago

R

EloiStree commented 6 months ago

R

EloiStree commented 6 months ago

R

EloiStree commented 6 months ago

R

EloiStree commented 6 months ago

R

EloiStree commented 6 months ago

R

EloiStree commented 6 months ago

R

EloiStree commented 6 months ago

R

EloiStree commented 6 months ago

R

EloiStree commented 6 months ago

R

EloiStree commented 6 months ago

R

EloiStree commented 6 months ago

R

EloiStree commented 6 months ago

R

EloiStree commented 6 months ago

https://www.emulatorgames.net/download/?rom=super-mario-bros https://www.emulatorgames.net/emulators/nintendo/

https://github.com/Genymobile/scrcpy/releases/tag/v2.4

https://www.emulatorgames.net/emulators/nintendo/nostalgia-nes-1-15-8/

EloiStree commented 6 months ago

Note


import pyautogui
import time

time.sleep(5)
# Commentaire sur une ligne
"""
Commentaire sur plusieur
ligne
"""
print("Pousse sur R pour recommencer")
pyautogui.keyDown('r')
pyautogui.keyUp('r')

time.sleep(0.1)
print("Sword")
pyautogui.keyDown('x')
pyautogui.keyUp('x')
time.sleep(0.1)
print("kunai")
pyautogui.keyDown('z')
pyautogui.keyUp('z')

time.sleep(0.1)
print("Aller à gauche")
pyautogui.keyDown('left')
pyautogui.keyUp('left')

time.sleep(0.1)
print("Sauter")
pyautogui.keyDown('up')
pyautogui.keyUp('up')

time.sleep(0.1)
print("Aller à droite")
pyautogui.keyDown('right')
pyautogui.keyUp('right')

print("Doubel saut")
pyautogui.keyDown('up')
pyautogui.keyUp('up')
time.sleep(0.1)
pyautogui.keyDown('up')
pyautogui.keyUp('up')
EloiStree commented 6 months ago

https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes VK_CODES = { 'LBUTTON': 0x01, # Left mouse button 'RBUTTON': 0x02, # Right mouse button 'CANCEL': 0x03, # Control-break processing 'MBUTTON': 0x04, # Middle mouse button (three-button mouse) 'XBUTTON1': 0x05, # X1 mouse button 'XBUTTON2': 0x06, # X2 mouse button 'BACK': 0x08, # BACKSPACE key 'TAB': 0x09, # TAB key 'CLEAR': 0x0C, # CLEAR key 'RETURN': 0x0D, # ENTER key 'SHIFT': 0x10, # SHIFT key 'CONTROL': 0x11, # CTRL key 'MENU': 0x12, # ALT key 'PAUSE': 0x13, # PAUSE key 'CAPITAL': 0x14, # CAPS LOCK key 'KANA': 0x15, # IME Kana mode 'HANGUEL': 0x15, # IME Hanguel mode (maintained for compatibility; use HANGUL) 'HANGUL': 0x15, # IME Hangul mode 'JUNJA': 0x17, # IME Junja mode 'FINAL': 0x18, # IME final mode 'HANJA': 0x19, # IME Hanja mode 'KANJI': 0x19, # IME Kanji mode 'ESCAPE': 0x1B, # ESC key 'CONVERT': 0x1C, # IME convert 'NONCONVERT': 0x1D, # IME nonconvert 'ACCEPT': 0x1E, # IME accept 'MODECHANGE': 0x1F, # IME mode change request 'SPACE': 0x20, # SPACEBAR 'PRIOR': 0x21, # PAGE UP key 'NEXT': 0x22, # PAGE DOWN key 'END': 0x23, # END key 'HOME': 0x24, # HOME key 'LEFT': 0x25, # LEFT ARROW key 'UP': 0x26, # UP ARROW key 'RIGHT': 0x27, # RIGHT ARROW key 'DOWN': 0x28, # DOWN ARROW key 'SELECT': 0x29, # SELECT key 'PRINT': 0x2A, # PRINT key 'EXECUTE': 0x2B, # EXECUTE key 'SNAPSHOT': 0x2C, # PRINT SCREEN key 'INSERT': 0x2D, # INS key 'DELETE': 0x2E, # DEL key 'HELP': 0x2F, # HELP key '0': 0x30, # 0 key '1': 0x31, # 1 key '2': 0x32, # 2 key '3': 0x33, # 3 key '4': 0x34, # 4 key '5': 0x35, # 5 key '6': 0x36, # 6 key '7': 0x37, # 7 key '8': 0x38, # 8 key '9': 0x39, # 9 key 'A': 0x41, # A key 'B': 0x42, # B key 'C': 0x43, # C key 'D': 0x44, # D key 'E': 0x45, # E key 'F': 0x46, # F key 'G': 0x47, # G key 'H': 0x48, # H key 'I': 0x49, # I key 'J': 0x4A, # J key 'K': 0x4B, # K key 'L': 0x4C, # L key 'M': 0x4D, # M key 'N': 0x4E, # N key 'O': 0x4F, # O key 'P': 0x50, # P key 'Q': 0x51, # Q key 'R': 0x52, # R key 'S': 0x53, # S key 'T': 0x54, # T key 'U': 0x55, # U key 'V': 0x56, # V key 'W': 0x57, # W key 'X': 0x58, # X key 'Y': 0x59, # Y key 'Z': 0x5A, # Z key 'LWIN': 0x5B, # Left Windows key (Natural keyboard) 'RWIN': 0x5C, # Right Windows key (Natural keyboard) 'APPS': 0x5D, # Applications key (Natural keyboard) 'SLEEP': 0x5F, # Computer Sleep key 'NUMPAD0': 0x60, # Numeric keypad 0 key 'NUMPAD1': 0x61, # Numeric keypad 1 key 'NUMPAD2': 0x62, # Numeric keypad 2 key 'NUMPAD3': 0x63, # Numeric keypad 3 key 'NUMPAD4': 0x64, # Numeric keypad 4 key 'NUMPAD5': 0x65, # Numeric keypad 5 key 'NUMPAD6': 0x66, # Numeric keypad 6 key 'NUMPAD7': 0x67, # Numeric keypad 7 key 'NUMPAD8': 0x68, # Numeric keypad 8 key 'NUMPAD9': 0x69, # Numeric keypad 9 key 'MULTIPLY': 0x6A, # Multiply key 'ADD': 0x6B, # Add key 'SEPARATOR': 0x6C, # Separator key 'SUBTRACT': 0x6D, # Subtract key 'DECIMAL': 0x6E, # Decimal key 'DIVIDE': 0x6F, # Divide key 'F1': 0x70, # F1 key 'F2': 0x71, # F2 key 'F3': 0x72, # F3 key 'F4': 0x73, # F4 key 'F5': 0x74, # F5 key 'F6': 0x75, # F6 key 'F7': 0x76, # F7 key 'F8': 0x77, # F8 key 'F9': 0x78, # F9 key 'F10': 0x79, # F10 key 'F11': 0x7A, # F11 key 'F12': 0x7B, # F12 key 'F13': 0x7C, # F13 key 'F14': 0x7D, # F14 key 'F15': 0x7E, # F15 key 'F16': 0x7F, # F16 key 'F17': 0x80, # F17 key 'F18': 0x81, # F18 key 'F19': 0x82, # F19 key 'F20': 0x83, # F20 key 'F21': 0x84, # F21 key 'F22': 0x85, # F22 key 'F23': 0x86, # F23 key 'F24': 0x87, # F24 key 'NUMLOCK': 0x90, # NUM LOCK key 'SCROLL': 0x91, # SCROLL LOCK key '

EloiStree commented 6 months ago

Note OBS

import asyncio
import websockets
import json
from obswebsocket import obsws, requests

# OBS WebSocket connection details
OBS_HOST = 'localhost'
OBS_PORT = 4444
OBS_PASSWORD = 'your_password'

# WebSocket server details
WEBSOCKET_HOST = 'localhost'
WEBSOCKET_PORT = 8765

# Initialize OBS WebSocket client
obs_client = obsws(OBS_HOST, OBS_PORT, OBS_PASSWORD)

async def start_obs_recording():
    try:
        obs_client.call(requests.StartRecording())
        print("Recording started.")
    except Exception as e:
        print(f"Failed to start recording: {e}")

async def stop_obs_recording():
    try:
        obs_client.call(requests.StopRecording())
        print("Recording stopped.")
    except Exception as e:
        print(f"Failed to stop recording: {e}")

async def handler(websocket, path):
    async for message in websocket:
        data = json.loads(message)
        action = data.get('action')

        if action == 'start_recording':
            await start_obs_recording()
        elif action == 'stop_recording':
            await stop_obs_recording()
        else:
            print(f"Unknown action: {action}")

async def main():
    # Connect to OBS
    obs_client.connect()

    # Start the WebSocket server
    async with websockets.serve(handler, WEBSOCKET_HOST, WEBSOCKET_PORT):
        print(f"WebSocket server started on ws://{WEBSOCKET_HOST}:{WEBSOCKET_PORT}")
        await asyncio.Future()  # Run forever

try:
    asyncio.run(main())
except KeyboardInterrupt:
    pass
finally:
    obs_client.disconnect()
    print("OBS WebSocket client disconnected.")
EloiStree commented 6 months ago

Key Logger in C# to use in the project.

https://github.com/EloiStree/2024_02_21_OpenSourceKeyLoggerForUnity3D/releases/tag/V0

Source: https://github.com/EloiStree/2024_02_21_OpenSourceKeyLoggerForUnity3D/blob/main/2024_02_21_OpenSourceKeyLoggerToInteger/Program.cs


using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;

namespace KeyboardInputConsoleApp
{
    class Program
    {

        static int Port = 7072;
        static IPAddress BroadcastAddress = IPAddress.Parse("127.0.0.1"); 
        [DllImport("user32.dll")]
        public static extern short GetAsyncKeyState(int vKey);

        static bool[] previousKeyState = new bool[256];

        public class JsonConfig
        {
            public int m_offset { get; set; } = 160000;
            public int m_offset_press { get; set; } = 1000;
            public int m_offset_release { get; set; } = 2000;
            public int m_port { get; set; } = 7072;
            public string m_ip_target { get; set; } = "127.0.0.1";
        }

        static void Main(string[] args)
        {
            string filePath = "Config.json";
            JsonConfig config= new JsonConfig();

            if (!File.Exists(filePath))
            {
                // Read the JSON content from the file
                string outputJsonString = JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true });
                File.WriteAllText(filePath, outputJsonString);
            }
            if (File.Exists(filePath))
            {
                // Read the JSON content from the file
                string jsonString = File.ReadAllText(filePath);
                config = JsonSerializer.Deserialize<JsonConfig>(jsonString);
                Console.WriteLine(jsonString);

            }

            Port = config.m_port;
            BroadcastAddress = IPAddress.Parse(config.m_ip_target);

            int offset = config.m_offset;
            Console.WriteLine("Offset: " + offset);

            // Create UDP client
            UdpClient udpClient = new UdpClient();

            while (true)
            {
                for (int i = 0; i < 256; i++)
                {
                    bool isKeyPressed = (GetAsyncKeyState(i) & 0x8000) != 0;

                    if (isKeyPressed != previousKeyState[i])
                    {
                        int temp = isKeyPressed ? offset + config.m_offset_press + i : offset + config.m_offset_release + i;
                        string message = $"Key Pressed: {temp}" ;
                        Console.WriteLine(message);
                        SendUdpMessage(udpClient, temp);

                        previousKeyState[i] = isKeyPressed;
                    }
                }

                Thread.Sleep(TimeSpan.FromMicroseconds(10));
            }
        }

        static void SendUdpMessage(UdpClient client, int intValue)
        {

            byte[] bytes1 = BitConverter.GetBytes(intValue);

            client.Send(bytes1, bytes1.Length, new IPEndPoint(BroadcastAddress, Port));

        }
    }
}
EloiStree commented 6 months ago

Simulate Keys

import pyautogui

# Press the 'A' key
pyautogui.keyDown('a')

# Release the 'A' key
pyautogui.keyUp('a')

from pynput.keyboard import Key, Controller

# Create a keyboard controller object
keyboard = Controller()

# Simulate pressing and releasing the 'A' key
keyboard.press('a')
keyboard.release('a')

``` py 
import ctypes
from ctypes import wintypes
import time
import win32gui

user32 = ctypes.WinDLL('user32', use_last_error=True)

# Define constants
WM_KEYDOWN = 0x0100
WM_KEYUP = 0x0101
VK_A = 0x41

# Find the handle to the target window (e.g., Notepad)
hwnd = win32gui.FindWindow(None, "Untitled - Notepad")  # Change this to your target window title

if hwnd == 0:
    print("Target window not found!")
else:
    # Press the 'A' key
    user32.PostMessageW(hwnd, WM_KEYDOWN, VK_A, 0)

    # Small delay to simulate a key press duration
    time.sleep(0.1)

    # Release the 'A' key
    user32.PostMessageW(hwnd, WM_KEYUP, VK_A, 0)

    print("Key 'A' pressed and released.")

import ctypes
import time

# Constants
KEYEVENTF_KEYDOWN = 0x0000
KEYEVENTF_KEYUP = 0x0002
VK_A = 0x41  # Virtual-key code for the 'A' key

# Load the user32.dll
user32 = ctypes.windll.user32

def press_key(hexKeyCode):
    user32.keybd_event(hexKeyCode, 0, KEYEVENTF_KEYDOWN, 0)

def release_key(hexKeyCode):
    user32.keybd_event(hexKeyCode, 0, KEYEVENTF_KEYUP, 0)

if __name__ == "__main__":
    time.sleep(2)  # Sleep for 2 seconds to give you time to switch to the target window

    press_key(VK_A)
    time.sleep(0.1)  # Hold the key for a short duration
    release_key(VK_A)

UDP

Envoyé un text en UDP


import socket

def send_udp_message(target_ip, target_port, message):
    # Create a UDP socket
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    try:
        # Send the message
        udp_socket.sendto(message.encode(), (target_ip, target_port))
        print(f"Message sent to {target_ip}:{target_port}")
    except Exception as e:
        print(f"Error sending message: {e}")
    finally:
        # Close the socket
        udp_socket.close()

# Define target IP, port, and message
target_ip = "192.168.1.100"  # Replace with the target IP address
target_port = 404  # Target port
message = "Hello, this is a test message!"  # Message to send

# Send the UDP message
send_udp_message(target_ip, target_port, message)

Recevoir le texte UDP

import socket

def udp_server(host='0.0.0.0', port=404):
    # Create a UDP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # Bind the socket to the address and port
    server_address = (host, port)
    print(f'Starting UDP server on {server_address[0]} port {server_address[1]}')
    sock.bind(server_address)

    while True:
        print('Waiting to receive message...')
        data, address = sock.recvfrom(4096)

        print(f'Received {len(data)} bytes from {address}')
        print(data.decode('utf-8'))

        # If needed, send a response back to the client
        # sent = sock.sendto(data, address)
        # print(f'Sent {sent} bytes back to {address}')

if __name__ == "__main__":
    udp_server()
EloiStree commented 6 months ago

Simuler un touche Xbox ?

EloiStree commented 6 months ago

Simulate Xbox


import pyxinput
import time
import socket
import struct
import random

#pyxinput.test_virtual()

 # AxisLx          , Left Stick X-Axis
 # AxisLy          , Left Stick Y-Axis
 # AxisRx          , Right Stick X-Axis
 # AxisRy          , Right Stick Y-Axis
 # BtnBack         , Menu/Back Button
 # BtnStart        , Start Button
 # BtnA            , A Button
 # BtnB            , B Button
 # BtnX            , X Button
 # BtnY            , Y Button
 # BtnThumbL       , Left Thumbstick Click
 # BtnThumbR       , Right Thumbstick Click
 # BtnShoulderL    , Left Shoulder Button
 # BtnShoulderR    , Right Shoulder Button
 # Dpad            , Set Dpad Value (0 = Off, Use DPAD_### Constants) 1 up 2 down 3 left 4 right
 # TriggerL        , Left Trigger
 # TriggerR        , Right Trigger

listener_udp_address = ('', 7000)

int_offset=450000
int_player_offset=100

max_input=3

pv={}
pr={}

def set_value_for_all(value_key,value):
    for key in pv:
        pv[key].set_value(value_key, value)

for i in range(1,max_input+1):
    pv[str(i)] = pyxinput.vController()
    pr[str(i)] = pyxinput.rController(i)

def release_all():
        set_value_for_all('BtnA', 0),
        set_value_for_all('BtnB', 0),
        set_value_for_all('BtnX', 0),
        set_value_for_all('BtnY', 0),
        set_value_for_all('Dpad', 0),
        set_value_for_all('BtnThumbL', 0),
        set_value_for_all('BtnThumbR', 0),
        set_value_for_all('BtnShoulderL', 0),
        set_value_for_all('BtnShoulderR', 0),
        set_value_for_all('BtnStart', 0),
        set_value_for_all('BtnBack', 0),
        set_value_for_all('TriggerL', 0),
        set_value_for_all('TriggerR', 0),
        set_value_for_all('AxisLx', 0),
        set_value_for_all('AxisLy', 0),
        set_value_for_all('AxisRx', 0),
        set_value_for_all('AxisRy', 0),

def get_random_11():
    return random.uniform(-1.0, 1.0)

def all_player_move_randomly():
    for key in pv:
        pv[key].set_value('AxisLx', get_random_11())
        pv[key].set_value('AxisLy', get_random_11())
        pv[key].set_value('AxisRx', get_random_11())
        pv[key].set_value('AxisRy', get_random_11())

button_dico_all = {
    #ABXY
    0: lambda: release_all(),
    1: lambda: all_player_move_randomly(),
    1001: lambda: set_value_for_all('BtnA', 1),
    2001: lambda: set_value_for_all('BtnA', 0),
    1002: lambda: set_value_for_all('BtnB', 1),
    2002: lambda: set_value_for_all('BtnB', 0),
    1003: lambda: set_value_for_all('BtnX', 1),
    2003: lambda: set_value_for_all('BtnX', 0),
    1004: lambda: set_value_for_all('BtnY', 1),
    2004: lambda: set_value_for_all('BtnY', 0),
    #DPAD
    1005: lambda: set_value_for_all('Dpad', 2),# 2 down 
    2005: lambda: set_value_for_all('Dpad', 0),
    1006: lambda: set_value_for_all('Dpad', 1),# 1 up 
    2006: lambda: set_value_for_all('Dpad', 0),
    1007: lambda: set_value_for_all('Dpad', 4),#  4 left 
    2007: lambda: set_value_for_all('Dpad', 0),
    1008: lambda: set_value_for_all('Dpad', 8),# 8 right
    2008: lambda: set_value_for_all('Dpad', 0),

    #THUMB 
    1009: lambda: set_value_for_all('BtnThumbL', 1),
    2009: lambda: set_value_for_all('BtnThumbL', 0),
    1010: lambda: set_value_for_all('BtnThumbR', 1),
    2010: lambda: set_value_for_all('BtnThumbR', 0),

    #SHOULDER    
    1011: lambda: set_value_for_all('BtnShoulderL', 1),
    2011: lambda: set_value_for_all('BtnShoulderL', 0),
    1012: lambda: set_value_for_all('BtnShoulderR', 1),
    2012: lambda: set_value_for_all('BtnShoulderR', 0),

    #START BACK
    1013: lambda: set_value_for_all('BtnStart', 1),
    2013: lambda: set_value_for_all('BtnStart', 0),
    1014: lambda: set_value_for_all('BtnBack', 1),
    2014: lambda: set_value_for_all('BtnBack', 0),

    #TRIGGER
    2020: lambda: set_value_for_all('TriggerL', 0),
    2021: lambda: set_value_for_all('TriggerL', 0.1),
    2022: lambda: set_value_for_all('TriggerL', 0.2),
    2023: lambda: set_value_for_all('TriggerL', 0.3),
    2024: lambda: set_value_for_all('TriggerL', 0.4),
    2025: lambda: set_value_for_all('TriggerL', 0.5),
    2026: lambda: set_value_for_all('TriggerL', 0.6),
    2027: lambda: set_value_for_all('TriggerL', 0.7),
    2028: lambda: set_value_for_all('TriggerL', 0.8),
    2029: lambda: set_value_for_all('TriggerL', 0.9),
    2030: lambda: set_value_for_all('TriggerL', 1),

    #TRIGGER
    2040: lambda: set_value_for_all('TriggerR', 0),
    2041: lambda: set_value_for_all('TriggerR', 0.1),
    2042: lambda: set_value_for_all('TriggerR', 0.2),
    2043: lambda: set_value_for_all('TriggerR', 0.3),
    2044: lambda: set_value_for_all('TriggerR', 0.4),
    2045: lambda: set_value_for_all('TriggerR', 0.5),
    2046: lambda: set_value_for_all('TriggerR', 0.6),
    2047: lambda: set_value_for_all('TriggerR', 0.7),
    2048: lambda: set_value_for_all('TriggerR', 0.8),
    2049: lambda: set_value_for_all('TriggerR', 0.9),
    2050: lambda: set_value_for_all('TriggerR', 1),

    3100: lambda: set_value_for_all('AxisLx', -1),
    3101: lambda: set_value_for_all('AxisLx', -0.90),
    3102: lambda: set_value_for_all('AxisLx', -0.75),
    3103: lambda: set_value_for_all('AxisLx', -0.5),
    3104: lambda: set_value_for_all('AxisLx', -0.25),
    3105: lambda: set_value_for_all('AxisLx', 0),
    3106: lambda: set_value_for_all('AxisLx', 0.25),
    3107: lambda: set_value_for_all('AxisLx', 0.5),
    3108: lambda: set_value_for_all('AxisLx', 0.75),
    3109: lambda: set_value_for_all('AxisLx', 0.90),
    3110: lambda: set_value_for_all('AxisLx', 1),
    3111: lambda: set_value_for_all('AxisLy', get_random_11()),

    3200: lambda: set_value_for_all('AxisLy', -1),
    3201: lambda: set_value_for_all('AxisLy', -0.90),
    3202: lambda: set_value_for_all('AxisLy', -0.75),
    3203: lambda: set_value_for_all('AxisLy', -0.5),
    3204: lambda: set_value_for_all('AxisLy', -0.25),
    3205: lambda: set_value_for_all('AxisLy', 0),
    3206: lambda: set_value_for_all('AxisLy', 0.25),
    3207: lambda: set_value_for_all('AxisLy', 0.5),
    3208: lambda: set_value_for_all('AxisLy', 0.75),
    3209: lambda: set_value_for_all('AxisLy', 0.90),
    3210: lambda: set_value_for_all('AxisLy', 1),
    3211: lambda: set_value_for_all('AxisLy', get_random_11()),

    3300: lambda: set_value_for_all('AxisRx', -1),
    3301: lambda: set_value_for_all('AxisRx', -0.90),
    3302: lambda: set_value_for_all('AxisRx', -0.75),
    3303: lambda: set_value_for_all('AxisRx', -0.5),
    3304: lambda: set_value_for_all('AxisRx', -0.25),
    3305: lambda: set_value_for_all('AxisRx', 0),
    3306: lambda: set_value_for_all('AxisRx', 0.25),
    3307: lambda: set_value_for_all('AxisRx', 0.5),
    3308: lambda: set_value_for_all('AxisRx', 0.75),
    3309: lambda: set_value_for_all('AxisRx', 0.90),
    3310: lambda: set_value_for_all('AxisRx', 1),
    3311: lambda: set_value_for_all('AxisLy', get_random_11()),

    3400: lambda: set_value_for_all('AxisRy', -1),
    3401: lambda: set_value_for_all('AxisRy', -0.90),
    3402: lambda: set_value_for_all('AxisRy', -0.75),
    3403: lambda: set_value_for_all('AxisRy', -0.5),
    3404: lambda: set_value_for_all('AxisRy', -0.25),
    3405: lambda: set_value_for_all('AxisRy', 0),
    3406: lambda: set_value_for_all('AxisRy', 0.25),
    3407: lambda: set_value_for_all('AxisRy', 0.5),
    3408: lambda: set_value_for_all('AxisRy', 0.75),
    3409: lambda: set_value_for_all('AxisRy', 0.90),
    3410: lambda: set_value_for_all('AxisRy', 1),
    3411: lambda: set_value_for_all('AxisLy', get_random_11()),

    }

# Create a UDP socket

# Bind the socket to a specific IP address and port
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(listener_udp_address)

def integer_to_xbox_input(int_value):
    if button_dico_all.get(int_value) is not None:
        print(f"Received {int_value}")
        button_dico_all[int_value]()
    else :
        print(f"Received {int_value} not found")

print(f"Listening for incoming data... port {listener_udp_address[1]}")
# Listen for incoming data
while True:
    byte_received, address = sock.recvfrom(1024)  # Adjust the buffer size as needed
    print(f'Received {len(byte_received)} bytes from {address}: {byte_received}')
    if byte_received is not None:
        if len(byte_received) == 16:
            index = struct.unpack('<i', byte_received[0:4])[0]
            value = struct.unpack('<i', byte_received[4:8])[0]
            ulong_milliseconds = struct.unpack('<q', byte_received[8:16])[0]
            print(f"Received Bytes {index} | {value} | { ulong_milliseconds}")
            integer_to_xbox_input(value)
EloiStree commented 6 months ago
import socket

# Get the IP address of the current machine
ip_address = socket.gethostbyname(socket.gethostname())

# Print the IP address
print(f'My IP address is: {ip_address}')

# Create a UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# Bind the socket to a specific address and port
server_address = ('', 404)
sock.bind(server_address)

print('Listening for UDP messages on port 404...')

while True:
    # Receive a message and the client address
    data, address = sock.recvfrom(4096)

    # Print the received message
    print(f'Received message: {data.decode()} from {address[0]}:{address[1]}')

import socket
import time

def send_udp_packet(ip, port):
    # Create a UDP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # Send a UDP packet to the specified IP address and port
    sock.sendto(b"Hello, UDP!", (ip, port))

    # Close the socket
    sock.close()

# Specify the IP address and port to send the UDP packet to
ip = "127.0.0.1"  # Replace with the desired IP address
ip = "192.168.150.3"  # Replace with the desired IP address

port = 404  # Replace with the desired port number

# Call the function to send the UDP packet

while True:
    time.sleep(1)
    send_udp_packet(ip, port)