在宏运行结束时打开 NUMLOCK

Posted

技术标签:

【中文标题】在宏运行结束时打开 NUMLOCK【英文标题】:Turning NUMLOCK on at the end of a macro run 【发布时间】:2017-02-24 14:10:08 【问题描述】:

代码的作用:我有一个代码可以在屏幕上移动鼠标,获取打印屏幕并将其粘贴到 excel 中。

问题:出于某种原因,我的代码总是(绝对没有例外)在每次运行后关闭 NUMLOCK 键。

到目前为止我尝试了什么:我四处搜索并找到了 SendKeys (NUMLOCK),理论上它是有效的(尽管它似乎对用户来说很成问题)。

我想做什么:我想在每次宏运行后打开 NUMLOCK,

Obs1:我不知道是什么导致宏首先将其关闭。修复导致此问题的任何原因是理想的,但由于我不知道问题出在哪里,我首先想让我的代码正常工作。一旦找到打开 NUMLOCK 键的方法,我就会着手解决这个问题。

问题:我可以使用 SendKeys 做到这一点吗?我是否正确使用它?有没有更好的办法?

Obs2:由于它是一个更大的代码,一旦解决了这个问题,我将在整个代码中发布另一个问题,并查看导致问题的原因。

代码我正在尝试打开numlock:

Application.Sendkeys (NUMLOCK)

也试过了:

Application.Sendkeys ("NUMLOCK")

Application.Sendkeys NUMLOCK

【问题讨论】:

您可能想在这里阅读:***.com/questions/25977933/…。这也可能是一个已知问题:support.microsoft.com/en-us/help/179987/… @sous2817 感谢您的评论。已经看到这个问题并尝试过,仍然遇到同样的问题。 另外,对于它的价值...不是语法:SendKeys "NUMLOCK", True 奇怪的是,我从未在我的戴尔机器上看到过这种情况,但它似乎总是在惠普笔记本电脑上发生。 顺便说一句,请不要使用macros 标签,它专门不适用于 VBA ;) 【参考方案1】:

您可以通过几个 Windows API 调用直接设置密钥状态。移植自MSDN page for keybd_event function:

#If VBA7 Then
    Private Declare PtrSafe Sub keybd_event Lib "user32.dll" (ByVal bVk As Byte, ByVal bScan As Byte, _
                                                              ByVal dwFlags As LongPtr, ByVal dwExtraInfo As LongPtr)
    Private Declare PtrSafe Function GetKeyboardState Lib "user32.dll" (ByVal lpKeyState As LongPtr) As Boolean
#Else
    Private Declare Sub keybd_event Lib "user32.dll" (ByVal bVk As Byte, ByVal bScan As Byte, _
                                                      ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
    Private Declare Function GetKeyboardState Lib "user32.dll" (ByVal lpKeyState As Long) As Boolean
#End If  

Private Const KEYEVENTF_EXTENDEDKEY As Long = &H1
Private Const KEYEVENTF_KEYUP As Long = &H2
Private Const VK_NUMLOCK As Byte = &H90
Private Const NumLockScanCode As Byte = &H45

Private Sub ToggleNumlock(enabled As Boolean)
    Dim keystate(255) As Byte
    'Test current keyboard state.
    GetKeyboardState (VarPtr(keystate(0)))
    If (Not keystate(VK_NUMLOCK) And enabled) Or (keystate(VK_NUMLOCK) And Not enabled) Then
        'Send a keydown
        keybd_event VK_NUMLOCK, NumLockScanCode, KEYEVENTF_EXTENDEDKEY, 0&
        'Send a keyup
        keybd_event VK_NUMLOCK, NumLockScanCode, KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0&
    End If
End Sub

这样称呼它:

Sub Example()
    'Turn Numlock off.
    ToggleNumlock False
    'Turn Numlock on.
    ToggleNumlock True
End Sub

【讨论】:

我也正要推荐keybd_event。顺便说一句,在GetKeyboardState 之后的测试中,您在最后一个enabled 之前缺少一个Not,当前一个与If enabled Then 相同。 ;) @Comintern 感谢您的回答。这种类型的api调用可以用来设置任何类型的keystate吗? @Comintern 你贴的这段代码,变量不用声明吗? @DGMS89 他们是。仅有的两个变量是enabled,它被声明为一个参数,和keystate,它显式地Dim'd。其余的被声明为常量。 @DGMS89 - 将Private Sub ToggleNumlock 上方的所有内容放在模块的最顶部,就在Option Explicit 下方。【参考方案2】:

首先,将以下代码复制并粘贴到 Excel 工作表的模块中(例如:-Module-1)...

Private Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
       Private Const kCapital = 20
       Private Const kNumlock = 144

       Public Function CapsLock() As Boolean
       CapsLock = KeyState(kCapital)
       End Function

       Public Function NumLock() As Boolean
       NumLock = KeyState(kNumlock)
       End Function

       Private Function KeyState(lKey As Long) As Boolean
       KeyState = CBool(GetKeyState(lKey))
       End Function

然后,将以下内容复制并粘贴到您的工作表代码中(例如:- Sheet1(代码))...

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
      Range("XFD1").FormulaR1C1 = "=NumLock()"
      If Range("XFD1").Value = "FALSE" Then
      SendKeys "NUMLOCK"
      Else
      End If
      End Sub

现在冷静!!!对于您所做的每个 SelectionChange,Excel 都会自行刷新并确保 Numlock 始终处于打开状态。 如果需要,请根据需要替换“Capslock”而不是 Numlock。

谢谢。萨西精英:)

【讨论】:

【参考方案3】:

我发现这个解决方案是迄今为止最好的,并且不会干扰 NUMLOCK。 将以下代码放入模块中,并从项目中的任何位置调用它。脚本对象会覆盖 VBA 中的 SendKeys。

Public Sub Sendkeys(text as variant, Optional wait As Boolean = False)
   Dim WshShell As Object
   Set WshShell = CreateObject("wscript.shell")
   WshShell.Sendkeys cstr(text), wait
   Set WshShell = Nothing
End Sub 

我在下面的帖子中找到了它:

SendKeys() permission denied error in Visual Basic

【讨论】:

【参考方案4】:

我尝试了所有建议,直到发现不是 (NUMLOCK) 而是 NUMLOCK。这对我有用。

子数字锁() 发送键“NUMLOCK” 结束子

【讨论】:

请阅读 cmets 部分,OP 已经尝试过此操作但无法正常工作【参考方案5】:

你几乎拥有它! 正确的编码是: Application.Sendkeys ("NUMLOCK")

【讨论】:

如果您阅读了有关该问题的 cmets,您会看到 OP 已经尝试过了,但没有成功。

以上是关于在宏运行结束时打开 NUMLOCK的主要内容,如果未能解决你的问题,请参考以下文章

在宏中使用用户在表单中输入的信息

在宏中过度使用会损害性能吗?

MS Visual Studio 2010 C++ 预处理器 - 如果函数在宏中定义并在其他地方调用,未定义时是不是有任何开销

Centos打开关闭结束tomcat,及查看tomcat运行日志

如何在宏禁用系统上锁定 Access 数据库?

在宏内部使用变量内部数据集名称时,SAS语法错误22和200