You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python如何实现不依赖外接扬声器调用主板蜂鸣器发声

问题

想咨询Windows平台下是否存在Python实现方案,可独立于电脑外接扬声器,直接驱动系统/主板蜂鸣器发出蜂鸣音。
目前正在编写Windows平台的电脑空闲时长统计脚本,脚本会将空闲时段的起止时间写入文本文件,用于门店场景下配合监控系统核查店内是否有人员值守:用户临时离店后,可通过日志核对对应时段的空闲情况。需要脚本触发提示时,通过主板蜂鸣器发声提醒用户移动鼠标。
现有修改后的代码如下:

import ctypes, ctypes.wintypes
from time import strftime
from datetime import datetime

class LASTINPUTINFO(ctypes.Structure):
    _fields_ = [
      ('cbSize', ctypes.wintypes.UINT),
      ('dwTime', ctypes.wintypes.DWORD),
      ]

PLASTINPUTINFO = ctypes.POINTER(LASTINPUTINFO)


user32 = ctypes.windll.user32
GetLastInputInfo = user32.GetLastInputInfo
GetLastInputInfo.restype = ctypes.wintypes.BOOL
GetLastInputInfo.argtypes = [PLASTINPUTINFO]

kernel32 = ctypes.windll.kernel32
GetTickCount = kernel32.GetTickCount
Sleep = kernel32.Sleep

def wait_until_idle(idle_time=60):
    idle_time_ms = int(idle_time*1000)
    liinfo = LASTINPUTINFO()
    liinfo.cbSize = ctypes.sizeof(liinfo)
    while True:
        GetLastInputInfo(ctypes.byref(liinfo))
        elapsed = GetTickCount() - liinfo.dwTime
        if elapsed>=idle_time_ms:
            break
        Sleep(idle_time_ms - elapsed or 1)


def wait_until_active(tol=5):
    liinfo = LASTINPUTINFO()
    liinfo.cbSize = ctypes.sizeof(liinfo)
    lasttime = None
    delay = 1 # ms
    maxdelay = int(tol*1000)
    while True:
        GetLastInputInfo(ctypes.byref(liinfo))
        if lasttime is None: lasttime = liinfo.dwTime
        if lasttime != liinfo.dwTime:
            break
        delay = min(2*delay, maxdelay)
        Sleep(delay)

def test():
    string = strftime('%I:%M:%S %p ')
    string2 = strftime('%A  %d-%b-%Y')
    new_line = '\n'
    wait_until_idle(600)
    user32.MessageBeep(0)
    with open("D:\idle.txt", "a") as f:
        f.write(new_line + string + string2 + ' Start')

   
test()
def test2():
    wait_until_active(1)
    user32.MessageBeep(0)
    now = datetime.now()
    string = now.strftime('%I:%M:%S %p ')
    string2 = now.strftime('%A  %d-%b-%Y')
    new_line = '\n'
    with open("D:\idle.txt", "a") as f:
        f.write(new_line + string + string2 + ' End')

test2()

while True:
    duration1 = test()
    duration2 = test2()
    print(duration1)
    print(duration2)
解答
  • 现有代码里使用的user32.MessageBeep()默认走系统音频通道,声音从外接扬声器/声卡输出,不会直接驱动主板原生蜂鸣器。要实现独立于外接音频设备驱动主板蜂鸣器,直接调用Windows kernel32提供的原生Beep接口即可,这个接口直接向主板蜂鸣器硬件发送控制指令,不依赖系统音频服务。
  • 调用方法很简单,在现有代码加载kernel32的部分,补充绑定Beep函数即可:
# 补充在现有kernel32相关定义的后面
Beep = kernel32.Beep
Beep.restype = ctypes.wintypes.BOOL
Beep.argtypes = [ctypes.wintypes.DWORD, ctypes.wintypes.DWORD]

Beep函数接收两个参数:第一个是蜂鸣频率,单位为Hz,取值范围37~32767;第二个是蜂鸣持续时长,单位为毫秒。

  • 替换代码里原来的user32.MessageBeep(0)即可触发主板蜂鸣,比如空闲超时的时候用3次短蜂提醒,辨识度更高:
# 替换原有的user32.MessageBeep(0)
for _ in range(3):
    Beep(1200, 200)
    Sleep(100)
  • 注意事项:
    • 近年新出的消费级主板大多已经取消板载原生蜂鸣器(需要单独接主板SPEAKER插针的小蜂鸣器才会有对应硬件),这类设备上Windows会自动把Beep调用重定向到默认声卡播放,没有原生蜂鸣器硬件无法实现完全脱离扬声器发声。
    • 64位Windows系统默认禁用蜂鸣器内核驱动,如果调用无反应,需要用管理员权限打开命令提示符,执行sc config beep start= system后重启电脑,开启原生蜂鸣器支持。
    • 现有代码存在逻辑冗余:进入while循环前已经手动调用了一次test()和test2(),会导致第一次空闲记录重复写入,且两个函数没有设置返回值,循环里打印的duration1、duration2始终为None,删掉循环外单独的test()、test2()调用即可。

内容的提问来源于stack exchange,提问作者Mohamed Hussein

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 20:12:21