Play pause media keys.


(TheMightyFozz) #1

I am not a coder and don’t know where to start, just putting this idea out there;
I love blender the way it is. I also love being immersed in the projects, but I also love my music!

is there a way to ingratiate the windows media keys into a blender menu (preferably at the top of the 3d view very small).

i.e. vol up, vol down, mute, play/pause.

is it Just a Key press?

I found this;
https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx

if this is possible I can make the illustrations for the buttons.



(TheMightyFozz) #2

Update, found this;

And after a bit of fiddling… … Whooot it works!!!

import ctypes
from ctypes import wintypes
import time

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

INPUT_MOUSE    = 0
INPUT_KEYBOARD = 1
INPUT_HARDWARE = 2

KEYEVENTF_EXTENDEDKEY = 0x0001
KEYEVENTF_KEYUP       = 0x0002
KEYEVENTF_UNICODE     = 0x0004
KEYEVENTF_SCANCODE    = 0x0008

MAPVK_VK_TO_VSC = 0

# msdn.microsoft.com/en-us/library/dd375731
VK_MEDIA_PLAY_PAUSE  = 0xB3

# C struct definitions

wintypes.ULONG_PTR = wintypes.WPARAM

class MOUSEINPUT(ctypes.Structure):
    _fields_ = (("dx",          wintypes.LONG),
                ("dy",          wintypes.LONG),
                ("mouseData",   wintypes.DWORD),
                ("dwFlags",     wintypes.DWORD),
                ("time",        wintypes.DWORD),
                ("dwExtraInfo", wintypes.ULONG_PTR))

class KEYBDINPUT(ctypes.Structure):
    _fields_ = (("wVk",         wintypes.WORD),
                ("wScan",       wintypes.WORD),
                ("dwFlags",     wintypes.DWORD),
                ("time",        wintypes.DWORD),
                ("dwExtraInfo", wintypes.ULONG_PTR))

def __init__(self, *args, **kwds):
    super(KEYBDINPUT, self).__init__(*args, **kwds)
        # some programs use the scan code even if KEYEVENTF_SCANCODE
        # isn't set in dwFflags, so attempt to map the correct code.
    if not self.dwFlags & KEYEVENTF_UNICODE:
        self.wScan = user32.MapVirtualKeyExW(self.wVk,MAPVK_VK_TO_VSC, 0)

class HARDWAREINPUT(ctypes.Structure):
    _fields_ = (("uMsg",    wintypes.DWORD),
                ("wParamL", wintypes.WORD),
                ("wParamH", wintypes.WORD))

class INPUT(ctypes.Structure):
    class _INPUT(ctypes.Union):
        _fields_ = (("ki", KEYBDINPUT),
                    ("mi", MOUSEINPUT),
                    ("hi", HARDWAREINPUT))
    _anonymous_ = ("_input",)
    _fields_ = (("type",   wintypes.DWORD),
                ("_input", _INPUT))

LPINPUT = ctypes.POINTER(INPUT)

def _check_count(result, func, args):
    if result == 0:
        raise ctypes.WinError(ctypes.get_last_error())
    return args

user32.SendInput.errcheck = _check_count
user32.SendInput.argtypes = (wintypes.UINT, # nInputs
                             LPINPUT,       # pInputs
                             ctypes.c_int)  # cbSize

# Functions

def PressKey(hexKeyCode):
    x = INPUT(type=INPUT_KEYBOARD,
              ki=KEYBDINPUT(wVk=hexKeyCode))
    user32.SendInput(1, ctypes.byref(x), ctypes.sizeof(x))

def ReleaseKey(hexKeyCode):
    x = INPUT(type=INPUT_KEYBOARD,
              ki=KEYBDINPUT(wVk=hexKeyCode,
                            dwFlags=KEYEVENTF_KEYUP))
    user32.SendInput(1, ctypes.byref(x), ctypes.sizeof(x))

def PlayPause():
            PressKey(VK_MEDIA_PLAY_PAUSE) 
            time.sleep(.2)
            ReleaseKey(VK_MEDIA_PLAY_PAUSE)

if __name__ == "__main__":
    PlayPause()

Can someone help me create the button in the 3d view… …:stuck_out_tongue:
Oh and ill love to make my first venture into coding multi-platform… …is this?


(TheMightyFozz) #3

Ok so i’m now trying to decypher this, so i can call PlayPause() from an onscreen click. I know the screen cast keys use the 3d window. so by right i should be able to position the images i want… …the code is hidden in here somewhere. …mhwhaaaa.


(TheMightyFozz) #4

Ok… …turned it into a “Panel” menu…
…it wont stop pressing that key… …how do i fix it.

note the line; layout.operator(“PlayPause()”, text=“Play Pause Music”)
when i uncomment the PlayPause() the code spams the media button.


# Thanks to this video
# https://www.youtube.com/watch?v=OEkrQGFqM10
import bpy
from bpy.types import Panel
import ctypes
from ctypes import wintypes
import time

#================================================================
#---------------Media button script------------------------------
#================================================================
user32 = ctypes.WinDLL('user32', use_last_error=True)

INPUT_MOUSE    = 0
INPUT_KEYBOARD = 1
INPUT_HARDWARE = 2

KEYEVENTF_EXTENDEDKEY = 0x0001
KEYEVENTF_KEYUP       = 0x0002
KEYEVENTF_UNICODE     = 0x0004
KEYEVENTF_SCANCODE    = 0x0008

MAPVK_VK_TO_VSC = 0

# msdn.microsoft.com/en-us/library/dd375731
VK_MEDIA_PLAY_PAUSE  = 0xB3

# C struct definitions

wintypes.ULONG_PTR = wintypes.WPARAM

class MOUSEINPUT(ctypes.Structure):
    _fields_ = (("dx",          wintypes.LONG),
                ("dy",          wintypes.LONG),
                ("mouseData",   wintypes.DWORD),
                ("dwFlags",     wintypes.DWORD),
                ("time",        wintypes.DWORD),
                ("dwExtraInfo", wintypes.ULONG_PTR))

class KEYBDINPUT(ctypes.Structure):
    _fields_ = (("wVk",         wintypes.WORD),
                ("wScan",       wintypes.WORD),
                ("dwFlags",     wintypes.DWORD),
                ("time",        wintypes.DWORD),
                ("dwExtraInfo", wintypes.ULONG_PTR))

def __init__(self, *args, **kwds):
    super(KEYBDINPUT, self).__init__(*args, **kwds)
        # some programs use the scan code even if KEYEVENTF_SCANCODE
        # isn't set in dwFflags, so attempt to map the correct code.
    if not self.dwFlags & KEYEVENTF_UNICODE:
        self.wScan = user32.MapVirtualKeyExW(self.wVk,MAPVK_VK_TO_VSC, 0)

class HARDWAREINPUT(ctypes.Structure):
    _fields_ = (("uMsg",    wintypes.DWORD),
                ("wParamL", wintypes.WORD),
                ("wParamH", wintypes.WORD))

class INPUT(ctypes.Structure):
    class _INPUT(ctypes.Union):
        _fields_ = (("ki", KEYBDINPUT),
                    ("mi", MOUSEINPUT),
                    ("hi", HARDWAREINPUT))
    _anonymous_ = ("_input",)
    _fields_ = (("type",   wintypes.DWORD),
                ("_input", _INPUT))

LPINPUT = ctypes.POINTER(INPUT)

def _check_count(result, func, args):
    if result == 0:
        raise ctypes.WinError(ctypes.get_last_error())
    return args

user32.SendInput.errcheck = _check_count
user32.SendInput.argtypes = (wintypes.UINT, # nInputs
                             LPINPUT,       # pInputs
                             ctypes.c_int)  # cbSize

# Functions

def PressKey(hexKeyCode):
    x = INPUT(type=INPUT_KEYBOARD,
              ki=KEYBDINPUT(wVk=hexKeyCode))
    user32.SendInput(1, ctypes.byref(x), ctypes.sizeof(x))

def ReleaseKey(hexKeyCode):
    x = INPUT(type=INPUT_KEYBOARD,
              ki=KEYBDINPUT(wVk=hexKeyCode,
                            dwFlags=KEYEVENTF_KEYUP))
    user32.SendInput(1, ctypes.byref(x), ctypes.sizeof(x))

def PlayPause():
            PressKey(VK_MEDIA_PLAY_PAUSE) 
            time.sleep(.2)
            ReleaseKey(VK_MEDIA_PLAY_PAUSE)
#========================================================================
#the panel
#========================================================================

# Naming and creating new new panel..
class MediaCont(Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_label = 'Media Controls'
    bl_context = 'objectmode'
    bl_category = 'Music'

    
    #UI
    def draw(self, context):
        layout = self.layout
        layout.operator("PlayPause()", text="Play Pause Music")

# Register
def register():
    bpy.utils.register_class(MediaCont)
    
# Unregister
def unregister():
    bpy.utils.unregister_class(MediaCont)

# Needed for text editor
if __name__ == "__main__":
    register()


(TheMightyFozz) #5

Here is the first version I feel comfortable people testing…


copy the code below into blenders text editor and click run


bl_info = {
    'name': 'Media Keys',
    'author': 'Robert Forsyth',
    'version': (0, 0, 1),
    'blender': (2, 78, 0),
    'location': 'View3D > Tool Panel > Music',
    'description': 'Disables Blenders use of Media Keys and adds a menu (good for tablet use)',
    'warning': 'Does not disable blenders use of the media keys yet!',
    'wiki_url': 'http://blenderartists.org',
    'tracker_url': '',
    'support': 'COMMUNITY',
    'category': '3D View'}

import bpy
import ctypes
from ctypes import wintypes
import time

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

INPUT_MOUSE    = 0
INPUT_KEYBOARD = 1
INPUT_HARDWARE = 2

KEYEVENTF_EXTENDEDKEY = 0x0001
KEYEVENTF_KEYUP       = 0x0002
KEYEVENTF_UNICODE     = 0x0004
KEYEVENTF_SCANCODE    = 0x0008

MAPVK_VK_TO_VSC = 0

# msdn.microsoft.com/en-us/library/dd375731
VK_MEDIA_PLAY_PAUSE  = 0xB3
VK_MEDIA_PREV_TRACK  = 0xB1
VK_MEDIA_NEXT_TRACK  = 0xB0
VK_VOLUME_DOWN  = 0xAE
VK_VOLUME_UP  = 0xAF
VK_VOLUME_MUTE  = 0xAD

# C struct definitions

wintypes.ULONG_PTR = wintypes.WPARAM

class MOUSEINPUT(ctypes.Structure):
    _fields_ = (("dx",          wintypes.LONG),
                ("dy",          wintypes.LONG),
                ("mouseData",   wintypes.DWORD),
                ("dwFlags",     wintypes.DWORD),
                ("time",        wintypes.DWORD),
                ("dwExtraInfo", wintypes.ULONG_PTR))

class KEYBDINPUT(ctypes.Structure):
    _fields_ = (("wVk",         wintypes.WORD),
                ("wScan",       wintypes.WORD),
                ("dwFlags",     wintypes.DWORD),
                ("time",        wintypes.DWORD),
                ("dwExtraInfo", wintypes.ULONG_PTR))

    def __init__(self, *args, **kwds):
        super(KEYBDINPUT, self).__init__(*args, **kwds)
        # some programs use the scan code even if KEYEVENTF_SCANCODE
        # isn't set in dwFflags, so attempt to map the correct code.
        if not self.dwFlags & KEYEVENTF_UNICODE:
            self.wScan = user32.MapVirtualKeyExW(self.wVk,
                                                 MAPVK_VK_TO_VSC, 0)

class HARDWAREINPUT(ctypes.Structure):
    _fields_ = (("uMsg",    wintypes.DWORD),
                ("wParamL", wintypes.WORD),
                ("wParamH", wintypes.WORD))

class INPUT(ctypes.Structure):
    class _INPUT(ctypes.Union):
        _fields_ = (("ki", KEYBDINPUT),
                    ("mi", MOUSEINPUT),
                    ("hi", HARDWAREINPUT))
    _anonymous_ = ("_input",)
    _fields_ = (("type",   wintypes.DWORD),
                ("_input", _INPUT))

LPINPUT = ctypes.POINTER(INPUT)

def _check_count(result, func, args):
    if result == 0:
        raise ctypes.WinError(ctypes.get_last_error())
    return args

user32.SendInput.errcheck = _check_count
user32.SendInput.argtypes = (wintypes.UINT, # nInputs
                             LPINPUT,       # pInputs
                             ctypes.c_int)  # cbSize

# Functions

def PressKey(hexKeyCode):
    x = INPUT(type=INPUT_KEYBOARD,
              ki=KEYBDINPUT(wVk=hexKeyCode))
    user32.SendInput(1, ctypes.byref(x), ctypes.sizeof(x))

def ReleaseKey(hexKeyCode):
    x = INPUT(type=INPUT_KEYBOARD,
              ki=KEYBDINPUT(wVk=hexKeyCode,
                            dwFlags=KEYEVENTF_KEYUP))
    user32.SendInput(1, ctypes.byref(x), ctypes.sizeof(x))

# Add new keys here.

def PlayPause():
            PressKey(VK_MEDIA_PLAY_PAUSE) 
            time.sleep(.2)
            ReleaseKey(VK_MEDIA_PLAY_PAUSE)

def PrevTrack():
            PressKey(VK_MEDIA_PREV_TRACK) 
            time.sleep(.2)
            ReleaseKey(VK_MEDIA_PREV_TRACK)

def NextTrack():
            PressKey(VK_MEDIA_NEXT_TRACK) 
            time.sleep(.2)
            ReleaseKey(VK_MEDIA_NEXT_TRACK)

def VolUp():
            PressKey(VK_VOLUME_UP) 
            time.sleep(.2)
            ReleaseKey(VK_VOLUME_UP)

def VdoDo():
            PressKey(VK_VOLUME_DOWN) 
            time.sleep(.2)
            ReleaseKey(VK_VOLUME_DOWN)

def Vmute():
            PressKey(VK_VOLUME_MUTE) 
            time.sleep(.2)
            ReleaseKey(VK_VOLUME_MUTE)

 
#if __name__ == "__main__":
#    PlayPause()
# ------------------------------------------------------------------------
# Music Menu
# ------------------------------------------------------------------------

class ToolPropsPanel(bpy.types.Panel):
    bl_label = "Hello from Tool props"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_label = "Media Controls"
    bl_context = "objectmode"
    bl_category = "Music"
     
    def draw(self, context):
        layout = self.layout
        
        layout.label("Music Controls")

        row = layout.row(align=False)
        layout.operator("hello.hello", icon='FILE_SOUND', text='Play/Pause').function = "Play"

        row = layout.row(align=False)
        row.alignment = 'LEFT'
        layout.operator("hello.hello", icon='REW', text='Previous').function = "Prev"

        row = layout.row(align=False)
        row.alignment = 'LEFT'
        layout.operator("hello.hello", icon='FF', text='Next').function = "Next"

        layout.label("Volume Controls")

        row = layout.row(align=False)
        row.alignment = 'LEFT'
        layout.operator("hello.hello", icon='PLAY_AUDIO', text='Vol Up').function = "Vup"

        row = layout.row(align=False)
        row.alignment = 'LEFT'
        layout.operator("hello.hello", icon='PLAY_AUDIO', text='Vol Down').function = "Vdown"

        row = layout.row(align=False)
        row.alignment = 'LEFT'
        layout.operator("hello.hello", icon='X_VEC', text='Toggle Mute').function = "Vmute"


class Button_Of_Good_Music(bpy.types.Operator):
    bl_idname = "hello.hello"
    bl_label = "Say Boom"
    row = bpy.props.IntProperty()
    function = bpy.props.StringProperty()
 
    def execute(self, context):
        if self.function == 'Play':
            PlayPause()
            print('PlayPause')
        if self.function == 'Prev':
            PrevTrack()
            print('Last Track')
        if self.function == 'Next':
            NextTrack()
            print('Next Track')
        if self.function == 'Vup':
            VolUp()
            print('Volume Up')
        if self.function == 'Vdown':
            VdoDo()
            print('Volume Down')
        if self.function == 'Vmute':
            Vmute()
            print('Volume Down')
        else:
            print('Error')
        return{'FINISHED'}   

# ------------------------------------------------------------------------
# register and unregister functions
# ------------------------------------------------------------------------

def register():
    bpy.utils.register_module(__name__)

def unregister():
    bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
    register()

[edit] doesn’t work on mac YET