Blog slowly looming over

This commit is contained in:
Andrew Illarionov 2024-02-19 22:49:55 +03:00
parent b58407d358
commit 44c60f7069
11 changed files with 552 additions and 131 deletions

17
app.vue
View File

@ -3,12 +3,23 @@ const config = useAppConfig()
const theme = useVThemeSSR()
const vdisp = ref(useVDisplay())
const { reader } = storeToRefs(usePageStore())
const route = useRoute()
useHead({
titleTemplate: (chunk?) => {
return chunk === config.title.short
? config.title.full
: `${chunk} ${config.title.short}`
if (route.fullPath === '/') return config.title.full
console.log(route.fullPath.split('/'))
if (route.fullPath.split('/').length === 2)
switch (route.fullPath.split('/')[1]) {
case 'blog':
return 'The Enderchest'
default:
return `${chunk} ${config.title.short}`
}
return chunk!
},
})
</script>

View File

@ -244,6 +244,10 @@ body {
border-radius: 8px;
background-color: rgb(255 255 255 / 15%);
}
&::-webkit-scrollbar-button {
color: white;
}
}
@media (prefers-color-scheme: light) {
@ -307,6 +311,9 @@ body {
}
.post {
scroll-snap-type: both mandatory;
scroll-snap-stop: normal;
&-box {
position: relative;
@ -363,16 +370,52 @@ body {
}
}
&-details {
}
&-preamble {
&-thumb {
max-width: 800px;
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: flex-start;
position: relative;
width: 100%;
min-height: 400px;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
background-attachment: fixed;
border-radius: 1em;
scroll-snap-align: end;
text-shadow: black 1px 1px 7px;
iconify-icon {
filter: drop-shadow(1px 2px 3px rgb(0 0 0 / 100%));
}
&-share {
position: absolute;
top: 0;
left: 0;
}
&-control {
position: absolute;
top: 0;
right: 0;
}
}
&-content {
scroll-snap-align: start;
:is(p, li) {
a {
@extend %link;
@ -383,6 +426,21 @@ body {
color: royalblue;
}
}
code {
padding: 0.25em;
border-radius: 0.5em;
cursor: pointer;
background-color: rgb(83 35 162 / 10%);
transition: 0.3s ease;
&:hover {
background-color: rgb(138 71 245 / 20%);
}
}
}
:is(h1, h2, h3, h4, h5, h6) {
@ -399,8 +457,90 @@ body {
}
img {
max-width: 100%;
max-height: 400px;
}
blockquote {
padding: 0.75em 1em;
border-left: 0.25em solid rgb(153 153 255 / 60%);
border-top-right-radius: 0.5em;
border-bottom-right-radius: 0.5em;
background-color: rgb(153 153 255 / 10%);
transition: 0.3s ease;
&:hover {
border-left-color: rgb(153 153 255 / 100%);
background-color: rgb(153 153 255 / 15%);
}
:last-child {
margin-bottom: 0;
}
}
pre {
font-size: 14px;
padding: 1em;
border-radius: 0.5em;
background-color: rgb(83 35 162 / 5%);
position: relative;
overflow-x: auto;
code {
counter-reset: step;
counter-increment: step 0;
scroll-padding: 0.5em;
.line::before {
content: counter(step);
counter-increment: step;
display: inline-block;
text-align: right;
color: rgb(238 246 250 / 40%);
width: 1rem;
margin-right: 1.5rem;
}
}
.button {
position: absolute;
top: 0;
right: 0;
margin: 0.5em;
padding: 0.5em;
cursor: pointer;
background-color: rgb(153 153 255 / 10%);
border: 1px solid rgb(153 153 255 / 60%);
border-radius: 0.5em;
opacity: 0;
transition: 0.3s ease;
}
&:hover {
.button {
opacity: 1;
}
}
}
}
}
@ -470,7 +610,7 @@ body {
&-description {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
text-overflow: ellipsis;

View File

@ -1,11 +1,16 @@
---
title: The Windows Context Menu Is It a Lost Cause?
description: We dive in deep into the Windows context menu and how to customize it to your liking.
description: A deep dive into the Windows context menu API and customization options it offers. Shell components for beginners and context menu cleanup.
authors: ['Enderman']
created: 2023-08-13T15:51:19Z
updated: 2024-02-18T21:32:12Z
draft: false
tags: ['windows', 'context-menu', 'customization', 'registry', 'shell', 'shell-extensions', 'context-menu-handlers']
thumbnail: '/images/blog/thumbnails/the-windows-context-menu.png'
tags: ['windows', 'context menu', 'customization', 'registry', 'windows tweaks', 'shell', 'shell extensions', 'shell components', 'context menu handlers', 'windows 10', 'windows 11']
thumbnail: /images/blog/thumbnails/the-windows-context-menu.png
ogImage:
component: BlogImage
props:
image: /images/blog/thumbnails/the-windows-context-menu.png
---
# The Windows context menu is... poorly made.
@ -63,7 +68,7 @@ upon execution.
There are two main components the context menu is composed of:
* **Shell entries** — provided locally and managed by the registry;
* **Context menu handlers** — provided and managed by external software;
* **Context menu handlers** — provided and managed by external software.
Neither of them is documented well, but
there is some developer documentation for handlers available [on Microsoft's website](https://go.enderman.ch/Fm4t3).
@ -97,7 +102,7 @@ In conclusion, there are three types of applications in terms of friendliness to
* **Apps using context menu handlers with customizable settings** — the friendliest;
* **Apps using shell entries** — customizable through registry hacks;
* **Apps using context menu handlers without settings** — the entries are uneditable;
* **Apps using context menu handlers without settings** — the entries are uneditable.
The first case is the simplest and isn't worth talking about —
consult the documentation for the software in question to find all the necessary tweaks.
@ -154,7 +159,7 @@ for better understanding:
* **Shell extension** is a general term for a plugin for the Windows Explorer — the **context menu handler** is a
particular case of a shell extension;
* **Shell component** is a broad term for a component that helps the shell interact with the system — that includes
shell extensions, file extensions, protocols, etc.;
shell extensions, file extensions, protocols, etc.
If this doesn't show how big of a predicament Microsoft is in with the context menu, I don't know what does.
I tried my best to keep the technical language as clear as possible. 😒
@ -167,7 +172,7 @@ Entries provided by software — the context menu handlers — are stored under
![Directory.png](/images/blog/assets/the-windows-context-menu/directory.png)
Since registry key names are case-insensitive by design in Windows, capitalization plays no role.
**The value names, however, are** — keep that in mind, as in some cases it might bite you.
**The value names, however, are** — keep that in mind, as in some cases it might bite.
The context menu doesn't seem to care.
_Truly an amazing specification!_
@ -189,9 +194,9 @@ No matter how hard I tried, I could not find the exact specification of the inco
My suggestion is to treat the default `command` value as **raw command line** (e.g. Run box),
with an exception to the following two macros:
* `%1` — the absolute file path without quotes
If you right-click `C:\Users\bleh\p.txt`, execute the shell entry,
the `%1` in the context of the command line will be equivalent to `C:\Users\bleh\p.txt`;
* `%V` — the absolute directory path without quotes;
When the shell entry is executed after a right-click on `C:\Users\bleh\p.txt`,
the `%1` in the context of the command line is equivalent to `C:\Users\bleh\p.txt`;
* `%V` — the absolute directory path without quotes.
::card
---
@ -210,7 +215,7 @@ The directory macro `%V` also sometimes falls flat depending on the shell entry
On rare occasions, the default value is left unset, with `DelegateExecute` alongside it containing a GUID.
When that's the case, the command handler is implemented through the `IExecuteCommand` COM interface,
and you cannot customize it.
and hence cannot be customized by normal means.
**Why is that a thing?** Ask me a simpler question. It could be a compatibility layer for C, but your guess is as good as mine.
@ -281,17 +286,20 @@ you should use the `REG_SZ` value called `Icon` inside the respective `shell` ke
It uses that unmistakably distinct and clumsy **WinAPI resource syntax** to specify a direct link to the icon within
a file containing resources.
```csv
PATH_TO_FILE_WITH_ICON_RESOURCES,INDEX
```
If you want to select the first icon (in that case, the `INDEX` part is 0),
the `INDEX` part can be omitted completely:
```csv
PATH_TO_FILE_WITH_ICON_RESOURCES
```
The following expressions are completely valid and are going to work:
```csv
"C:\Windows\system32\cmd.exe"
C:\Windows\regedit.exe
@ -302,6 +310,7 @@ shell32.dll,3
SHELL32.DLL,10
"C:\Windows\system32\SHELL32.DLL",9
```
You can omit the quotes and absolute paths depending on the `%PATH%` variable that unholy concoction of an API uses.
**Spoiler:** they don't match against the system `%PATH%`.
Only God knows what paths it's able to parse by default.
@ -381,11 +390,11 @@ Please tag me on [Twitter](https://go.enderman.ch/twitter) or [send a mail](mail
have the knowledge.
**A few examples:**
* `CanonicalName`
* `CommandStateHandler`
* `CommandStateSync`
* `Description`
* `VerbName`
* `CanonicalName`;
* `CommandStateHandler`;
* `CommandStateSync`;
* `Description`;
* `VerbName`.
#### Deleting entries
Even simpler — it's the opposite of adding one.
@ -400,86 +409,195 @@ Even simpler — it's the opposite of adding one.
which might result in the item remaining in place despite the deletion.
#### Sorting entries
Now that's the funniest one. I even memed about it on Twitter.
The only way to sort the context menu is via the alphabetical order of its respective shell entries in the registry.
Yes. I am not kidding. Let the screenshots speak for themselves.
That's easily the most hilarious procedure of them all. I even [tweeted](https://go.enderman.ch/3hcO9) about it.
The only way to sort the context menu items is...
**by managing the alphabetical order of their respective shell entries in the registry**.
Seriously, I am not kidding.
Let the screenshots speak for themselves.
![Alphabetical Sort 1.png](/images/blog/assets/the-windows-context-menu/alphabetical-sort-1.png)
![Alphabetical Sort 2.png](/images/blog/assets/the-windows-context-menu/alphabetical-sort-2.png)
Yeah... I'd rather not comment on that.
_Yeah... I'd rather leave all the obscene comments aside._
##### Position override
Another silly and janky feature that has a limited number of use cases.
You can manually override the position of your context menu item to be...
Another silly feature with a limited number of use cases
that's likely been created due to all prior mess Microsoft has created.
It's possible to manually override the position of a context menu item to be...
either at the very top, or the very bottom.
Not much better than alphabetical sorting if you ask me...
_Still doesn't top off the alphabetical sorting between the registry peers..._
In your entry under shell, create a REG_SZ value called Position.
If you want to force the context menu handler to the top, put Top as data, otherwise put Bottom.
In the `shell` subkey under the respective shell entry, create a `REG_SZ` value called `Position`.
To enforce the context menu item to appear at the very top,
insert `Top` into the value data, otherwise insert `Bottom`.
Sometimes this may be necessary, as, for example, Microsoft dumps their regular alphabetical sorting strategy at
the bottom of the context menu, where display and personalization settings reside.
They simply specify the Bottom position for each of the entries.
If I recall correctly, they're still sorted alphabetically between themselves, as position override takes precedence.
Sometimes directly enforcing the position happens to be necessary.
For instance, Microsoft dumps the usual sorting strategy at the very bottom of the context menu,
where the display and personalization settings reside.
They simply set the `Bottom` position for each of the entries.
**What happens when there are multiple shell entries enforced to be in a set position?**
The alphabetical sorting makes a comeback,
it occurs between the shell entries with overridden positions just the same way.
![Position Override.png](/images/blog/assets/the-windows-context-menu/position-override.png)
##### Bottom line
Some of the default shell entries like Powershell have specific keys
(for the sake of that example, `ProgrammaticAccessOnly`) to control their appearance context menu.
As a rule of thumb, every time you're dealing with existing shell entries,
I REALLY suggest that you search for a way to modify them online before resorting to any of the general cases I've described above.
If you can't find anything even on the Internet, well, anything works.
### Uneditable entries
As for the Context Menu handlers, there's actually not much you can do.
They're located under the shellex\ContextMenuHandlers subkey.
### Context menu handlers
Compared to shell entries, there isn't much to be tweaked via registry in context menu handlers.
Their general location is the `ContextMenuHandlers` subkey under the `shellex` key in the respective shell entry.
![Context Menu Handler 3.png](/images/blog/assets/the-windows-context-menu/context-menu-handler-3.png)
Most of the time, the only data they contain is a lonely GUID. That doesn't help much.
Most of the time, the only piece of data they contain is a lonely GUID of the respective handler.
![Context Menu Handler 4.png](/images/blog/assets/the-windows-context-menu/context-menu-handler-4.png)
So, to remove the Context Menu handler, you should delete the subkey under ContextMenuHandlers.
I strongly suggest you save the GUID it contained so that you could roll back at any time later.
#### Removing handlers
A context menu handler always directly corresponds to some child under the `ContextMenuHandlers` key.
Therefore, all that has to be done to remove a handler is removal of the **respective child key**.
I strongly suggest writing **the GUID** and **the location** of the removed entry down somewhere,
so that there is a way to roll back any time later.
![Context Menu Handler 5.png](/images/blog/assets/the-windows-context-menu/context-menu-handler-5.png)
Adding your own...
Well, that's complicated.
You actually have to write your own handler in a language supporting Windows API or any sort of abstraction of it.
For example, C# is a decent choice.
I don't suggest you waste time on this,
unless you're making full-on software that you want to make more accessible to Windows users.
#### Adding handlers
Adding a custom handler is complicated.
It's not as trivial as adding a shell entry —
it requires implementing a handler interface using a language
supporting Windows API or an abstraction layer on top of it.
C# would be a decent choice precisely for this task.
However, it's just a waste of time to implement a handler for a single shell entry,
unless there's software to go along with it.
The idea behind context menu handlers is to **make native application experience nicer** for Windows users.
In other words, Microsoft failed to implement an accessible API for the context menu,
so they did what they do best — shifted the responsibility to the developers writing third-party software.
This is how a partial implementation of the `IContextMenu` interface in C++ looks like:
```cpp
STDMETHODIMP CShellExtension::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) {
BOOL fEx = FALSE;
BOOL fUnicode = FALSE;
if(lpcmi->cbSize == sizeof(CMINVOKECOMMANDINFOEX)) {
fEx = TRUE;
if (lpcmi->fMask & CMIC_MASK_UNICODE) fUnicode = TRUE;
}
if (!fUnicode && HIWORD(lpcmi->lpVerb)) {
if (StrCmpIA(lpcmi->lpVerb, m_pszVerb)) return E_FAIL;
}
else if (fUnicode && HIWORD(((CMINVOKECOMMANDINFOEX *) lpcmi)->lpVerbW)) {
if (StrCmpIW(((CMINVOKECOMMANDINFOEX *)lpcmi)->lpVerbW, m_pwszVerb)) return E_FAIL;
}
else if (LOWORD(lpcmi->lpVerb) != IDM_DISPLAY) {
return E_FAIL;
}
else {
MessageBox(
lpcmi->hwnd,
"The File Name",
"File Name",
MB_OK | MB_ICONINFORMATION
);
}
return S_OK;
}
```
The `InvokeCommand()` method is called when a user clicks a context menu item.
I've taken that example from [Microsoft](https://go.enderman.ch/TArYX).
That whole thing isn't too bad — the logic is far more robust and understandable
compared to its surface-level registry counterpart, but it certainly requires getting used to WinAPI.
**By definition, it's a requirement to implement interfaces entirely.**
However, since we're dealing with Microsoft,
the «interface» in question is actually an _abstract class_ and can be implemented partially.
The `IContextMenu` interface has three methods:
* `GetCommandString()` — retrieves the canonical name of the command (optional);
* `InvokeCommand()` — handles the command (required);
* `QueryContextMenu()` — adds items to the context menu (required).
The `IContextMenu` interface is the most common one, but there are others,
such as `IContextMenu2` and `IContextMenu3`.
Essentially, this is how the context menu handlers work inside.
While all of this is just a brief overview of the API,
you can learn everything about them and more in the [Shell Developer's Guide](https://go.enderman.ch/W50xJ).
## Dealing with locked keys
If the registry key is locked, and you don't have write permissions for it, it's owned by TrustedInstaller,
and you have to manually reclaim ownership of the key and allow yourself to make edits to it.
If the registry key is locked, the user you're logged in as is excluded from the ACL.
Commonly, when the key is locked, it's owned by `TrustedInstaller`.
When that's the case, it's necessary to reclaim ownership of the key to allow making edits to the ACL.
There are plenty of ways to do that, I will list two common ones.
Optimal way: Using Process Hacker with the TrustedInstaller plugin or Winaero Tweaker,
run regedit as Trusted Installer and perform the necessary tweaks.
### Using external tools
The idea here is to run `regedit` — the registry editor as the `TrustedInstaller` user directly.
You can think of `TrustedInstaller` as the Windows equivalent of `root` in Unix-like systems —
the superuser.
General solution:
While Windows generally has more granular control over permissions,
and the idea of having a superuser — **the ultimate authority of the system** — is less prominent and unannounced,
`TrustedInstaller` is the closest object to a superuser Windows has.
Navigate to the key you want to take ownership of
Open the «Properties» window
Head over to the Advanced tab
At the top of the Advanced Security Settings it states Owner: TrustedInstaller. Click Change
Input your username into the Enter the object name to select (examples) text area.
Click OK
Check the «Replace owner on subcontainers and objects» checkbox
Check the «Replace all child object permission entries» checkbox
Click OK
Select Administrators (PC_NAME\Administrators) in the group selector and then check Full Control box in the Permissions window down below
Click OK
After performing above steps, you must have gotten full and almost complete (some registry values and keys are still protected after the general procedure) access to the desired key.
For those wondering, I've already explained [here](https://go.enderman.ch/o2KGt) why
«sudo for Windows» makes no sense.
##### Process Hacker <sub>[download](https://go.enderman.ch/process-hacker)</sub>
![Process Hacker.png](/images/blog/assets/the-windows-context-menu/process-hacker.png)
![Process Hacker 2.png](/images/blog/assets/the-windows-context-menu/process-hacker-2.png)
##### Winaero Tweaker <sub>[download](https://go.enderman.ch/winaero)</sub>
![winaero-tweaker.png](/images/blog/assets/the-windows-context-menu/winaero-tweaker.png)
[Sergey](https://go.enderman.ch/Dr0iS) makes an entirely valid point in his Winaero Tweaker:
> **Warning!!!**
>
> Running programs under TrustedInstaller privileges, especially a file manager app or Regedit,exe can be
> VERY risky and harmful for your OS. It is like a God mode in a first-person shooter game, where nothing can
> stop your actions, so if you execute a malware infected file as TrustedInstaller, it can cause damage to the
> Windows operating system. Use this mode only if you perfectly understand what you are doing and if there is
> no simpler way than running it as Trusted Installer.
This is exactly the reason I resort to setting permissions manually.
It's a bit more time-consuming, but it's safer.
### Setting permissions manually
The trusty old way to do it is to manually set permissions for the key.
Once you get the hang of it, it really isn't that difficult.
![Permissions.png](/images/blog/assets/the-windows-context-menu/permissions.png)
##### General procedure
1. Navigate to the key you want to claim ownership of;
2. Open the «Properties» window;
3. Head over to the «Advanced» tab;
4. The current owner is shown at the top of the «Advanced Security Settings» window. Click «Change»;
5. Type out your username in the text area with the «Enter the object name to select (examples)» label;
6. Click «OK»;
7. Tick the «Replace owner on subcontainers and objects» checkbox;
8. Tick the «Replace all child object permission entries» checkbox;
9. Click «OK»;
10. Pick `Administrators (PC_NAME\Administrators)` in the group selector and then tick «Full Control» checkbox
in the «Permissions» window at the bottom;
11. You're done! Click «OK» and dismiss any warnings.
## Common registry paths
Here is a list of the most common registry paths.
There are as many «sections» as there are extensions, but these are the most common ones.
They should cover most of your context menu.
#### Desktop Background — bottom rows
`Computer\HKEY_CLASSES_ROOT\DesktopBackground`
@ -497,7 +615,7 @@ Here is a list of the most common registry paths.
![Folder.png](/images/blog/assets/the-windows-context-menu/folder.png)
#### Folder Item
This extends [Folder](#folder).
Extends [Folder](#folder).
`Computer\HKEY_CLASSES_ROOT\Folder`
![File Item.png](/images/blog/assets/the-windows-context-menu/file-item.png)
@ -513,14 +631,15 @@ This extends [Folder](#folder).
![Library Item.png](/images/blog/assets/the-windows-context-menu/library-item.png)
#### Library Background
`Computer\HKEY_CLASSES_ROOT\LibraryFolder\background`
Library background inherits from Folder Background,
but can't parse the `%V` macro, which results in the following error.
This is Microsoft's fault.
To my knowledge, there is no way to fix that.
Inherits from [Folder Background](#folder-background).
`Computer\HKEY_CLASSES_ROOT\LibraryFolder\background`
![Library Background.png](/images/blog/assets/the-windows-context-menu/library-background.png)
Despite the inheritance, it cannot parse the `%V` macro, which results in the following error.
Blame Microsoft for being as consistent as ever.
To my knowledge, there is no way to fix that.
![Explorer Error.png](/images/blog/assets/the-windows-context-menu/explorer-error.png)
#### All Files
@ -529,12 +648,13 @@ To my knowledge, there is no way to fix that.
![All Files.png](/images/blog/assets/the-windows-context-menu/all-files.png)
#### All Filesystem Objects
That's different from [All Files](#all-files) — it's a further generalization that includes system drives and symbols.
Different from [All Files](#all-files) — it's a further generalization that includes system drives,
symbolic links and other objects.
`Computer\HKEY_CLASSES_ROOT\AllFilesystemObjects`
![All Filesystem Objects.png](/images/blog/assets/the-windows-context-menu/all-filesystem-objects.png)
#### Type associations
#### File type associations
Text: `Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\text`
Images: `Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\image`
Documents: `Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\document`
@ -542,36 +662,58 @@ Audio: `Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\audio`
Video: `Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\video`
## Cleaning up the context menu
Most obnoxious default entries can be cleaned up using Winaero Tweaker.
I suggest you use it to make the process way more bearable for yourself.
The least fan-favorite default entries can be removed using Winaero Tweaker.
I suggest using it to make the whole cleanup slightly more bearable.
![Winaero 1.png](/images/blog/assets/the-windows-context-menu/winaero-1.png)
![Winaero 2.png](/images/blog/assets/the-windows-context-menu/winaero-2.png)
#### Areas Winaero Tweaker is unable to reach to
Remove «Open PowerShell window here»
Navigate to Computer\HKEY_CLASSES_ROOT\Directory\shell\Powershell
Unlock key (The Windows Context Menu > Dealing with locked keys)
Create a new REG_SZ value ProgrammaticAccessOnly without any data
Navigate to Computer\HKEY_CLASSES_ROOT\Directory\Background\shell\Powershell
Unlock key
Create a new REG_SZ value ProgrammaticAccessOnly without any data
Remove «Open Linux shell here»
Navigate to Computer\HKEY_CLASSES_ROOT\Directory\shell\WSL
Unlock key
Delete WSL key altogether
Navigate to Computer\HKEY_CLASSES_ROOT\Directory\Background\shell\Powershell
Unlock key
Create a new REG_SZ value ProgrammaticAccessOnly without any data
Edit the «Edit» text context menu command
Navigate to Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\text\shell\edit
Make sure you've read the article thoroughly, then do anything you want with it.
### Some extra common areas
The following are fairly common areas Winaero Tweaker doesn't cover.
::card
---
icon: idea
title: Tip
---
As a rule of thumb, whenever you're dealing with existing shell entries, I _really_ suggest
**searching for a way to manage them online** before resorting to any measures I elaborated on in this article.
Now if you can't find anything useful online, then anything works.
::
#### Remove «Open PowerShell window here»
1. Navigate to `Computer\HKEY_CLASSES_ROOT\Directory\shell\Powershell`;
2. [Unlock the key](#dealing-with-locked-keys);
3. Create a new `REG_SZ` value called `ProgrammaticAccessOnly` and leave it empty;
4. Navigate to `Computer\HKEY_CLASSES_ROOT\Directory\Background\shell\Powershell`;
5. [Unlock the key](#dealing-with-locked-keys);
6. Create a new `REG_SZ` value called `ProgrammaticAccessOnly` and leave it empty.
#### Remove «Open Linux shell here»
1. Navigate to `Computer\HKEY_CLASSES_ROOT\Directory\shell\WSL`;
2. [Unlock the key](#dealing-with-locked-keys);
3. Remove the key;
4. Navigate to `Computer\HKEY_CLASSES_ROOT\Directory\Background\shell\WSL`;
5. [Unlock the key](#dealing-with-locked-keys);
6. Create a new `REG_SZ` value called `ProgrammaticAccessOnly` and leave it empty.
#### Edit the «Edit» text context menu command
1. Navigate to `Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\text\shell\edit`;
2. Replace all mentions of the previous editor in default values with **Notepad++**
or any other text editor you prefer.
## Bottom line
No matter how terrible the context menu API might be for Windows, there's still a way to customize it.
Hope you found the tricks useful!
The context menu is a mess, and it's not going to change.
It's a part of Windows that's been around for a long time and has been left behind by Microsoft.
Shell entries are like differential equations — there's never a general solution.
They're a pain to learn, but the acquired skill is worth it.
If you've spotted a mistake (be it orthographical, factual or any other)
in this article or want to add some important details or share any important knowledge on the subject,
please contact me on Twitter: @endermanch or hit me up on e-mail: blogs@enderman.ch
No matter how terrible the context menu API is in Windows, there's still a way to customize it to your liking.
Hopefully you learned something new from this article
and are now able to make your context menu **a bit** more bearable.
**Spotted a mistake?**
Want to add important details I missed or share extra knowledge on the subject?
Tag me on [Twitter](https://go.enderman.ch/twitter) or [e-mail me](mailto:contact@enderman.ch)!
All contributions welcome. 😉

View File

@ -59,34 +59,38 @@ export default defineNuxtConfig({
'nuxt-link-checker',
],
content: {
documentDriven: true,
markdown: {
remarkPlugins: ['remark-reading-time'],
},
highlight: {
theme: {
// Default theme (same as single string)
default: 'github-light',
// Theme used if `html.dark`
dark: 'github-dark',
// Theme used if `html.sepia`
sepia: 'monokai',
},
theme: 'github-dark',
langs: [
'shell',
'batch',
'vb',
'ini',
'asm',
'c',
'cpp',
'java',
'python',
'csv',
'xml',
'json',
'js',
'ts',
'yaml',
'html',
'css',
'sass',
'php',
'js',
'ts',
'vue',
'shell',
'mdc',
'md',
'yaml',
'mdc',
'pascal',
'lisp',
'sql',
],
},
},

View File

@ -1,24 +1,111 @@
<script setup lang="ts">
import { formatDate } from 'date-fns'
const { slug } = useRoute().params
const config = useAppConfig()
const content = useContent()
const meta = {
title: `${content.page.title}`,
description: content.page.description,
image: content.page.thumbnail,
url: `${config.url}/blog`,
}
defineOgImage()
// Hydrate the rendered items.
onMounted(() => {
document.querySelectorAll('pre').forEach((pre) => {
const icon = document.createElement('iconify-icon')
icon.setAttribute('icon', 'mdi:content-copy')
icon.setAttribute('inline', 'true')
icon.classList.add('button')
pre.appendChild(icon)
})
document
.querySelectorAll('code:not(pre *), pre > iconify-icon.button')
.forEach((code) => {
if (code instanceof HTMLElement) {
code.onclick = () => {
const area = document.createElement('textarea')
area.textContent =
code.nodeName && code.nodeName.toLowerCase() === 'code'
? code.textContent
: code.parentElement!.textContent
// It's necessary to create the textarea element every time you copy to get access to the select() method.
area.setSelectionRange(0, 99999) // An iOS gotcha.
area.select()
// Copy the text inside the textarea.
navigator.clipboard.writeText(area.value)
// TODO: Alert the user text has been successfully copied.
// Remove the textarea element.
area.remove()
}
}
})
})
onUnmounted(() => {
document.querySelectorAll('code').forEach((code) => {
code.onclick = null
})
document.querySelectorAll('pre').forEach((pre) => {
pre.querySelector('.clipboard')?.remove()
})
})
</script>
<template>
<article
class="scrollbar fade-mask-sm d-flex flex-column gap-3 flex-grow-1 overflow-x-hidden overflow-y-auto py-sm-4 pe-sm-3"
class="post scrollbar fade-mask-sm d-flex flex-column gap-3 flex-grow-1 overflow-x-hidden overflow-y-auto py-sm-4 pe-sm-3"
>
<ContentDoc :path="`/blog/${slug}`">
<template #default="{ doc }">
<div class="post-preamble">
<h3 class="alex">{{ doc.title }}</h3>
<img
draggable="false"
:src="doc.thumbnail"
:alt="doc.title"
class="post-preamble-thumb rounded-4"
/>
<div
class="post-preamble"
:style="{ backgroundImage: 'url(' + doc.thumbnail + ')' }"
>
<div class="p-2">
<h3 class="alex">{{ doc.title }}</h3>
<div class="d-flex flex-row row-gap-0 column-gap-2 flex-wrap">
<div class="d-flex flex-row gap-1 align-items-center">
<iconify-icon icon="mdi:calendar" />
<strong class="nobr font-small">
{{ formatDate(doc.created, 'LLLL do, y &ndash; HH:mm') }}
</strong>
</div>
<div class="d-flex flex-row gap-1 align-items-center">
<iconify-icon icon="mdi:clock-outline" />
<strong class="nobr font-small">
{{ doc.readingTime.text.split(' ')[0] + ' minutes to read' }}
</strong>
</div>
</div>
</div>
<NuxtLink
:href="`https://twitter.com/share?url=${config.url}/blog/${slug}&text=${doc.title}&hashtags=${doc.tags.slice(0, 3).join(',').replace(/ /g, '')}`"
target="_blank"
class="link post-preamble-share px-2 py-1"
>
<iconify-icon icon="mdi:twitter"></iconify-icon>
</NuxtLink>
<NuxtLink to="/blog" class="link post-preamble-control px-2 py-1">
<iconify-icon icon="icon-park-solid:back"></iconify-icon>
</NuxtLink>
</div>
<div class="post-content">
<Separator class="mt-0" />
<ContentRenderer :value="doc" />
</div>
</template>

View File

@ -1,5 +1,42 @@
<script setup lang="ts">
import { formatDate } from 'date-fns'
const config = useAppConfig()
const meta = {
title: 'The Enderchest',
description:
'A blog about software development, scientific research and Windows quirks.',
image: `${config.url}/images/chest.png`,
url: `${config.url}/blog`,
}
useSeoMeta({
title: meta.title,
description: meta.description,
ogTitle: meta.title,
ogDescription: meta.description,
ogImage: meta.image,
ogUrl: meta.url,
ogType: 'website',
twitterTitle: meta.title,
twitterDescription: meta.description,
twitterImage: meta.image,
twitterCard: 'summary',
})
useHead({
title: 'The Enderchest',
htmlAttrs: {
lang: config.locale || 'en',
},
link: [
{
rel: 'icon',
type: 'image/x-icon',
href: '/favicon.ico',
},
],
})
</script>
<template>

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
public/images/chest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB