
Research
NPM targeted by malware campaign mimicking familiar library names
Socket uncovered npm malware campaign mimicking popular Node.js libraries and packages from other ecosystems; packages steal data and execute remote code.
💻 A Python library to create and deploy cross-platform native context menus. 💻
Documentation available at: https://context-menu.readthedocs.io/en/latest/
This library lets you edit the entries on the right click menu for Windows and Linux using pure Python. It also allows you to make cascading context menus!
context_menu was created as due to the lack of an intuitive and easy to use cross-platform context menu library. The library allows you to create your own context menu entries and control their behavior seamlessly in native Python. The library has the following features:
The context menu is the window that is displayed when you right click:
The context menu is different depending on what was right clicked. For example, right clicking a folder will give you different options than right clicking a file.
Currently, the only operating systems supported are:
All python versions 3.7 and above are supported.
If you haven't installed Python, download and run an installer from the official website: https://www.python.org/downloads/
Once you have Python, the rest is super simple. Simply just run the following command in a terminal to install the package:
python -m pip install context_menu
or if you're on Linux:
python3 -m pip install context_menu
Note: If you're on Windows and it says the command isn't recognized, make sure to add Python to your path and run the command prompt as administrator
Let's say you want to make a basic context menu entry when you right click a file.
python -m pip install context_menu
It's super easy! You can create entries in as little as 3 lines:
from context_menu import menus
fc = menus.FastCommand('Example Fast Command 1', type='FILES', command='echo Hello')
fc.compile()
All you have to do is import the library and define the type of context entry you want. The options are:
You can also create much more complicated nested menus:
def foo2(filenames, params):
print('foo2')
print(filenames)
input()
def foo3(filenames, params):
print('foo3')
print(filenames)
input()
if __name__ == '__main__':
from context_menu import menus
cm = menus.ContextMenu('Foo menu', type='FILES')
cm2 = menus.ContextMenu('Foo Menu 2')
cm3 = menus.ContextMenu('Foo Menu 3')
cm3.add_items([
menus.ContextCommand('Foo One', command='echo hello > example.txt'),
])
cm2.add_items([
menus.ContextCommand('Foo Two', python=foo2),
cm3,
])
cm.add_items([
cm2,
menus.ContextCommand('Foo Three', python=foo3)
])
cm.compile()
All context menus are permanent unless you remove them.
ContextMenu
ClassThe ContextMenu object holds other context objects. It expects a name, the activation type if it is the root menu(the first menu), and an optional icon path. Only compile the root menu.
ContextMenu(name: str, type: str = None, icon_path: str = None)
Menus can be added to menus, creating cascading context menus. You can use the {MENU}.add_items{ITEMS} function to add context elements together, for example:
cm = menus.ContextMenu('Foo menu', type='DIRECTORY_BACKGROUND')
cm.add_items([
menus.ContextMenu(...),
menus.ContextCommand(...),
menus.ContextCommand(...)
])
cm.compile()
You have to call {MENU}.compile() in order to create the menu.
ContextCommand
ClassThe ContextCommand class creates the selectable part of the menu (you can click it). It requires a name, and either a Python function or a command (but NOT both) and has various other options
ContextCommand(name: str, command: str = None, python: 'function' = None, params: str = None, command_vars: list = None, icon_path: str = None)
Python functions can be passed to this method, regardless of their location. However, the function must accept only
two parameters filenames
, which is a list of paths*, and params
, the parameters passed to the function. and if
the function is in the same file as the menu, you have to surround it with if __name__ == '__main__':
# An example of a valid function
def valid_function(filenames, params):
print('Im valid!')
print(filenames)
print(params)
# Examples of invalid functions
def invalid_function_1(filenames, param1, param2):
print('Im invalid!')
print(filenames)
def invalid_function_2(params):
print('Im invalid!')
print(params)
Any command passed (as a string) will be directly ran from the shell.
FastCommand
ClassThe FastCommand class is an extension of the ContextMenu class and allows you to quickly create a single entry menu. It expects a name, type, command/function and an optional icon path.
FastCommand(
name: str, type: str, command: str = None, python: 'function' = None, params: str = '', command_vars: list = None, icon_path: str = None)
def foo1(filenames, params):
print(filenames)
input()
if __name__ == '__main__':
from context_menu import menus
fc = menus.FastCommand('Example Fast Command 1', type='FILES', python=foo1)
fc.compile()
removeMenu
methodYou can remove a context menu entry easily as well. Simply call the 'menus.removeMenu()' method.
removeMenu(name: str, type: str)
For example, if I wanted to remove the menu 'Foo Menu' that activated on type 'FILES':
from context_menu import menus
menus.removeMenu('Foo Menu', 'FILES')
and boom! It's gone 😎
params
Command ParameterIn both the ContextCommand
class and FastCommand
class you can pass in a parameter, defined by the parameter=None
variable. This value MUST be a string! This means instead of passing a list or numbers, pass it as a string
separated by spaces or whatever to delimitate it.
fc = menus.FastCommand('Example Fast Command 1', type='FILES', python=foo1, params='a b c d e')
fc.compile()
For more information, see this.
Works on the FastCommand
and ContextCommand
class.
command_vars
Command ParameterIf you decide to pass a shell command, you can access a list of special variables. For example, if I wanted to run a custom command with the file selected, I could use the following:
fc = menus.FastCommand('Weird Copy', type='FILES', command='touch ?x', command_vars=['FILENAME'])
fc.compile()
which would create a new file with the name of whatever I selected with an 'x' on the end. The ?
variable is
interpreted from left to right and replaced with the selected
values (see this).
All of the preset values are as follows:
Name | Function |
---|---|
FILENAME | The path to the file selected |
DIR/DIRECTORY | The directory the script was ran in. |
PYTHONLOC | The location of the python interpreter. |
Works on the FastCommand
and ContextCommand
class.
Let's say you only want your context menu entry to open on a certain type of file, such as a .txt
file. You can do
this by adding a type
variable to the ContextCommand
or FastCommand
class.
fc = menus.FastCommand('Weird Copy', type='.txt', command='touch ?x',
command_vars=['FILENAME']) # opens only on .txt files
fc.compile()
Now you'll only see the "Weird Copy" menu entry when you right click a .txt file.
There are different locations where a context menu can fire. For example, if you right click on a folder you'll get
different options than if you right click on a file. The type
variable controls this behavior in the library, and you
can reference this table to determine the type
:
Name | Location | Action |
---|---|---|
FILES | HKEY_CURRENT_USER\Software\Classes\*\shell\ | Opens on a file |
DIRECTORY | HKEY_CURRENT_USER\Software\Classes\Directory\shell | Opens on a directory |
DIRECTORY_BACKGROUND | HKEY_CURRENT_USER\Software\Classes\Directory\Background\shell | Opens on the background of the Directory |
DRIVE | HKEY_CURRENT_USER\Software\Classes\Drive\shell | Opens on the drives(think USBs) |
DESKTOP | Software\Classes\DesktopBackground\shell | Opens on the background of the desktop |
I strongly recommend checking out the examples folder for more complicated examples and usage.
You can check out the official documentation here.
This project tackles some pretty big issues, and there's definetly some goals that I'd like to accomplish. The current roadmap is as follows:
If by all means you want to help reach these milestones, see contribution below.
I really want to add support for MacOS, but I don't have the experience required to implement it.
Contributing is super simple! Create an additional branch and make a pull request with your changes. If the changes past the automated tests, it will be manually reviewed and merged accordingly.
Any and all help is appreciated, and if you have any questions, feel free to contact me directly.
if __name__ == '__main__':
.Feel free to check out a file sorter program I made that directly implements this library.
All my work is and always will be free and open source. If you'd like to support me, please consider leaving a ⭐ star ⭐, as it motivates me and the community to keep working on this project.
Thanks for reading!
FAQs
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Socket uncovered npm malware campaign mimicking popular Node.js libraries and packages from other ecosystems; packages steal data and execute remote code.
Research
Socket's research uncovers three dangerous Go modules that contain obfuscated disk-wiping malware, threatening complete data loss.
Research
Socket uncovers malicious packages on PyPI using Gmail's SMTP protocol for command and control (C2) to exfiltrate data and execute commands.