danjmwalker
danjmwalker

Reputation: 51

python 3 detect caps lock status

I've been searching for a way to identify the status of the CAPS LOCK in Python 3 and the only thing I've found applicable was a post here in Stack Overflow answered by Abhijit stating:

You can use ctypes to load user32.dll and then call GetKeyState with nVirtKey = VK_CAPITAL (0x14)

def get_capslock_state():
    import ctypes
    hllDll = ctypes.WinDLL ("User32.dll")
    VK_CAPITAL = 0x14
    return hllDll.GetKeyState(VK_CAPITAL)

I've applied this to my script, but the value returned is not the anticipated 1/0, but a long 9 number sequence which never repeats. I'm not certain how to use this value to return the 1/0, T/F, or any true value to test against.

Any ideas, either based on Abhijit's comment or another method that works in Python 3? Your help is greatly appreciated, as this is driving me nuts.

Upvotes: 1

Views: 4800

Answers (4)

JRiggles
JRiggles

Reputation: 6780

I'll throw my hat in the ring - here's an answer I found that works under Windows

Using pywin32

import win32api
import win32con


def is_caps_lock_on() -> bool:
    return bool(win32api.GetKeyState(win32con.VK_CAPITAL) & 1)

Using ctypes

import ctypes


def is_caps_lock_on() -> bool:
    VK_CAPITAL = 0x14
    return bool(ctypes.windll.user32.GetKeyState(VK_CAPITAL) & 1)

These two solutions are essentially identical, but the ctypes version leverages the standard library.

In my testing, the call to GetKeyState(VK_CAPITAL) would return decimal -127 (0xFFFF_FFFF_FFFF_FF81) when caps-lock was ON, and decimal -128 (0xFFFF_FFFF_FFFF_FF80) when caps-lock was OFF

Masking this value with & 1 effectively strips off all the bits we don't care about and leaves us with either decimal 1 or 0; passing this to bool gives us a simple True or False.

Note that it's not strictly necessary to use bool here since you can just as easily check truthiness against 1 or 0, but returning a Boolean is probably more "Pythonic".

Upvotes: 0

Ishan Jindal
Ishan Jindal

Reputation: 208

Here is the minimal working answer, which I built upon the answer of danjmwalker

import ctypes

def is_capslock_on():
    return True if ctypes.WinDLL("User32.dll").GetKeyState(0x14) else False

print(is_capslock_on())

Upvotes: 0

danjmwalker
danjmwalker

Reputation: 51

Thanks, Gimson, that did help. I was able to resolve this by calling the value as below:

def CAPSLOCK_STATE():
    import ctypes
    hllDll = ctypes.WinDLL ("User32.dll")
    VK_CAPITAL = 0x14
    return hllDll.GetKeyState(VK_CAPITAL)

CAPSLOCK = CAPSLOCK_STATE()
if ((CAPSLOCK) & 0xffff) != 0:
    print("\nWARNING:  CAPS LOCK IS ENABLED!\n")

This does the trick.

Upvotes: 1

Gimson
Gimson

Reputation: 66

From the looks of it, your value is being treated as a full-sized integer.

hllDll.GetKeyState gets its return value from the Win32 GetKeyState function seen here.

The return value from Windows is a Short. Your return value from the function was 361693184, which if you translate into binary is 10101100011110000000000000000. Notice the trailing 16 0-bits. I'm guessing that return value came from a test when you should have gotten a 0, and because it's trying to read a full 32-bit int, the top 16 bits are just garbage.

I would start by looking at your code to see why it might be assuming the value is a 32-bit integer. The joys of duck typing :)

I hope this helps! If this doesn't seem to be the problem, post some code where you call the function, so we can get a better look.

Upvotes: 2

Related Questions