python study/import pygame

python) pygame,키보드 처리(대소문자 처리) (2)

mhe1239 2024. 12. 28. 23:19

이전 글에서 Caps Lock키로 인해 대소문자 구분이 어렵다고 하였다. 그 이유는 실행시에 Caps Lock키가 켜져있는지 켜져있지 않은지를 알 수 없기에 이후에 누르는 Caps Lock키를 %2해서 판별한다고 해도 반대로 판별할 가능성이 있기 때문이다.

이번 글에서는 이 Caps Lock키가 켜져있는지 꺼져있는지 판별하는 것을 포함하여 pygame에서 대소문자 구분 방법에 대해 정확히 다루어보려한다. 

이를 시용하는 예는 코드 실행 중에 퍼즐을 위한 문장 등을 입력 할 수도 있기 때문이라고 생각한다.

 

import pygame만 사용하여 Caps Lock키를 판별하면 생기는 문제점

import pygame,sys
LIGHT_GRAY=(200,200,200)
LIGHT_MOSS_GREEN=(143,188,143)
screenw,screenh,FPS=100,100,80
caps_lock_on=False
def main():
    global caps_lock_on
    pygame.init()
    screen=pygame.display.set_mode((screenw,screenh))
    pygame.display.set_caption("caps_lock")
    font=pygame.font.SysFont('arial',30)
    clock=pygame.time.Clock()
    while True:
        for event in pygame.event.get():
            if event.type==pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type==pygame.KEYDOWN:
                if event.key==pygame.K_CAPSLOCK:
                    caps_lock_on=not caps_lock_on
                    print("Caps Lock On" if caps_lock_on else "Caps Lock Off")
                if event.key==pygame.K_a:
                    print("Shift key pressed, uppercase 'A'") if event.mod&pygame.KMOD_SHIFT else print("Lowercase 'a'")
        pygame.display.update()
        clock.tick(FPS)

if __name__=="__main__":
    main()

Caps Lock키를 킨 상태로 코드를 실행한다면 코드는 Caps Lock 키를 반대로 판단하게 된다. 

 

 

그래서 다른 방법으로 import ctypes를 하는 방법이 있다.(이는 window 운영 체제만 된다. import keyboard에 is_toggled 함수가 있었으면 모든 운영체제에서 되도록할 수 있을텐데 아쉽다.)

import pygame,sys,ctypes
BLACK=(0,0,0);WHITE=(255,255,255)
BACKGROUND_COLOR=(255,100,100);LIGHT_GRAY=(200,200,200)
LIGHT_MOSS_GREEN=(143,188,143)
screenw,screenh,FPS=400,200,80
#Caps Lock 상태 확인 함수
def is_capslock_on():
    return bool(ctypes.windll.user32.GetKeyState(0x14)&1)
def main():
    pygame.init()
    screen=pygame.display.set_mode((screenw,screenh))
    pygame.display.set_caption("Check_Caps_Lock_status")
    font=pygame.font.SysFont('arial',30)
    clock=pygame.time.Clock()
    screen.fill(WHITE)
    while True:
        for event in pygame.event.get():
            if event.type==pygame.QUIT:
                pygame.quit()
                sys.exit()
        caps_lock_on=is_capslock_on()
        screen.fill(LIGHT_MOSS_GREEN if caps_lock_on else LIGHT_GRAY)
        caps_text="Caps Lock: ON" if caps_lock_on else "Caps Lock: OFF"
        font_w,_=font.size(caps_text)
        text=font.render(caps_text,True,BLACK)
        screen.blit(text,((screenw-font_w)//2,screenh//2))
        pygame.display.update()
        clock.tick(FPS)

if __name__ == "__main__":
    main()

이를 실행하면 Caps Lock키를 눌러보면 켜진 상태인지 켜져있지않은 상태인지를 알 수 있다.

함수 is_caps_lock_on()에서 0x14가 Caps Lock 키의 가상 키 코드이다.

 

이를 기초로 Caps Lock키가 켜진 상태에서 Shift키를 누르는지, 안누르는지 그리고  Caps Lock키가 껴진 상태에서 Shift키를 누르는지, 안누르는지를 판단해 알파벳을 누를때에 구분할 수 있도록 코드를 짜보자.

import pygame,sys,ctypes
BLACK=(0,0,0);BACKGROUND_COLOR=(255,100,100)
LIGHT_GRAY=(200,200,200)
LIGHT_MOSS_GREEN=(143,188,143)
WHITE=(255,255,255)
screenw,screenh,FPS=300,200,60
status_text="Normal: Key Release"
user_text=""
# Caps Lock 상태 확인 함수
def is_caps_lock_on():
    return bool(ctypes.windll.user32.GetKeyState(0x14)&1)
def main():
    global status_text,user_text
    pygame.init()
    screen=pygame.display.set_mode((screenw,screenh))
    pygame.display.set_caption("Caps Lock_and_Shift_Screen")
    font=pygame.font.SysFont('arial',20)
    clock=pygame.time.Clock()
    state_text=''
    caps_lock_on_and_shift_pressed=''
    while True:
        caps_lock_on=is_caps_lock_on()
        shift_pressed=pygame.key.get_mods()&pygame.KMOD_SHIFT
        for event in pygame.event.get():
            if event.type==pygame.QUIT:
                pygame.quit()
                sys.exit()
            if caps_lock_on and shift_pressed:
                caps_lock_on_and_shift_pressed='Shift + Caps Lock'
            elif caps_lock_on and not shift_pressed:
                caps_lock_on_and_shift_pressed='Caps Lock'
            elif not caps_lock_on and shift_pressed:
                caps_lock_on_and_shift_pressed='Shift'
            else:
                caps_lock_on_and_shift_pressed='Normal'
            if event.type==pygame.KEYDOWN:
                
                if pygame.K_a<=event.key<=pygame.K_z:
                    key_name=pygame.key.name(event.key)

                    if caps_lock_on and shift_pressed:
                        user_text+=key_name.lower()
                        status_text=f"Shift + Caps Lock: Lowercase '{key_name.lower()}'"
                    elif caps_lock_on and not shift_pressed:
                        user_text+=key_name.upper()
                        status_text=f"Caps Lock: Uppercase '{key_name.upper()}'"
                    elif not caps_lock_on and shift_pressed:
                        user_text+=key_name.upper()
                        status_text=f"Shift: Uppercase '{key_name.upper()}'"
                    else:
                        user_text+=key_name.lower()
                        status_text=f"Normal: Lowercase '{key_name.lower()}'"
                elif event.key==pygame.K_SPACE:
                    user_text+=' '
                    status_text=f"{caps_lock_on_and_shift_pressed}: 'Space'"
                else:
                    key_name=pygame.key.name(event.key)
                    key_name=key_name.title()
                    status_text=f"{caps_lock_on_and_shift_pressed} '{key_name}'"

        state_text=f"Caps Lock {'ON' if caps_lock_on else 'OFF'}, Shift {'PRESSED' if shift_pressed else 'NOT PRESSED'}"

        screen.fill(LIGHT_MOSS_GREEN if caps_lock_on else LIGHT_GRAY)

        status_text_width,status_text_height=font.size(status_text)
        state_text_width,state_text_height=font.size(state_text)
        user_text_width,_=font.size(user_text)

        status_text_x=(screenw-status_text_width)//2
        status_text_y=(screenh-status_text_height)//2-40
        state_text_x=(screenw-state_text_width)//2
        state_text_y=status_text_y+status_text_height+10
        user_text_x=(screenw-user_text_width)//2
        user_text_y=state_text_y+state_text_height+10

        status_surface=font.render(status_text,True,BLACK)
        screen.blit(status_surface,(status_text_x,status_text_y))

        state_surface=font.render(state_text,True,BLACK)
        screen.blit(state_surface,(state_text_x,state_text_y))
        
        user_surface=font.render(user_text,True,BLACK,BACKGROUND_COLOR)
        screen.blit(user_surface,(user_text_x,user_text_y))

        pygame.display.update()
        clock.tick(FPS)

if __name__=="__main__":
    main()

pygame에서는 shift나 Ctrl과 같은 특수키를 사용할 때에 pygame.key.get_mods()가 0이 아닌 특정 정수 값을 가지게 된다. 그래서 23번째 줄에서 pygame.KMOD_SHIFT가 눌렸는지 그리고 pygame.key.get_mods()가 0이 아닌지를 확인하여 더 안정성 있게 사용 가능하다.

key_name=pygame.key.name(event.key)에서 pygame.key.name(event.key)는 pygame에서 특정 키의 이름을 문자열을 반환하는 함수으로 예를 들어 K_A를 입력하면 a를 반환하는 것이다.

만약 이것이 없다면 이 글의 3번째 코드처럼 모두 일일히 구현해둬야한다.

caps_lock_on_and_shift_pressed변수에 현재 Caps Lock과 Shift의 상태를 인식하게 하여서 이 두 가지 키의 영향을 받지 않는 키(Space)의 경우 표시만 하도록 하였다.

이외의 구현하지 않은 키들의 경우 else로 처리하여 key_name의 경우 key_name.title()을 통해 형식에 맞추어서 화면에 표시하도록 하였다.