Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fc0ebf9d5 | ||
|
|
a0e30ff982 | ||
|
|
c2a0d95851 | ||
|
|
34d5d2fff5 | ||
|
|
baa669fe1e | ||
|
|
67ecebbf6b | ||
|
|
e9a8b1962a | ||
|
|
3ded1573f4 | ||
|
|
d38adcfc70 | ||
|
|
5f1f5b3811 | ||
|
|
c18c70c2af | ||
|
|
9cdd76e1ac | ||
|
|
7db8a1e534 | ||
|
|
b93972c7f7 | ||
|
|
1bae00051b | ||
|
|
b75bae3c38 | ||
|
|
2e435dcdc0 | ||
|
|
fec33056cb | ||
|
|
0836b63439 | ||
|
|
2b5dbfa19f | ||
|
|
b6072f03bf | ||
|
|
4492a423b4 | ||
|
|
39f6f4de0d | ||
|
|
b16bcd0295 | ||
|
|
1caa814c95 | ||
|
|
bbf0f6e127 | ||
|
|
22bd5a5999 | ||
|
|
cb146c1cf1 | ||
|
|
1671cd6c3c | ||
|
|
541ac5f6d5 |
@@ -11,7 +11,7 @@ Public Class CSScriptAddon
|
|||||||
Implements IAddon
|
Implements IAddon
|
||||||
|
|
||||||
Sub New()
|
Sub New()
|
||||||
Dim scriptDir = mp.mpvConfFolderPath + "scripts"
|
Dim scriptDir = mp.MpvConfFolderPath + "scripts"
|
||||||
If Not Directory.Exists(scriptDir) Then Return
|
If Not Directory.Exists(scriptDir) Then Return
|
||||||
Dim csFiles = Directory.GetFiles(scriptDir, "*.cs").ToList
|
Dim csFiles = Directory.GetFiles(scriptDir, "*.cs").ToList
|
||||||
csFiles.AddRange(Directory.GetFiles(Application.StartupPath + "\\Scripts", "*.cs"))
|
csFiles.AddRange(Directory.GetFiles(Application.StartupPath + "\\Scripts", "*.cs"))
|
||||||
|
|||||||
75
README.md
@@ -19,15 +19,20 @@ Table of contents
|
|||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
- Customizable context menu defined in the same file as the keybindings
|
- Customizable context menu defined in the same file as the key bindings
|
||||||
- Addon API for .NET languages
|
- Searchable options dialog with modern UI as mpv compatible standalone application
|
||||||
- Scripting API for Python, C#, Lua, JavaScript and PowerShell
|
- Searchable input (key/mouse) binding editor with modern UI as mpv compatible standalone application
|
||||||
- mpv's OSC, IPC, conf files and more
|
- Modern UI using the OS theme color and dark mode
|
||||||
|
- Rich addon/extension API for .NET languages, over 700 available mpv properties
|
||||||
|
- Rich scripting API for Python, C#, Lua, JavaScript and PowerShell
|
||||||
|
- mpv's OSC (on screen controller (play control bar)), IPC, conf files
|
||||||
|
|
||||||
### Screenshots
|
### Screenshots
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
@@ -54,41 +59,53 @@ if it's missing mpv.net generates it with the following defaults:
|
|||||||
|
|
||||||
### Scripting
|
### Scripting
|
||||||
|
|
||||||
Scripting is supported for Python, C#, Lua, JavaScript and PowerShell
|
Scripting is supported via Python, C#, Lua, JavaScript and PowerShell
|
||||||
|
|
||||||
https://github.com/stax76/mpv.net/wiki/Scripting-(CSharp,-Python,-JavaScript,-Lua,-PowerShell)
|
[Scripting wiki page](https://github.com/stax76/mpv.net/wiki/Scripting-(CSharp,-Python,-JavaScript,-Lua,-PowerShell))
|
||||||
|
|
||||||
### Support
|
### Support
|
||||||
|
|
||||||
<https://forum.doom9.org/showthread.php?t=174841>
|
[Support thread in Doom9 forum](https://forum.doom9.org/showthread.php?t=174841)
|
||||||
|
|
||||||
<https://forum.videohelp.com/threads/392514-mpv-net-a-extendable-media-player-for-windows>
|
[Support thread in VideoHelp forum](https://forum.videohelp.com/threads/392514-mpv-net-a-extendable-media-player-for-windows)
|
||||||
|
|
||||||
<https://github.com/stax76/mpv.net/issues>
|
[Issue tracker to report bugs and request features](https://github.com/stax76/mpv.net/issues)
|
||||||
|
|
||||||
### Changelog
|
### Changelog
|
||||||
|
|
||||||
### 2.2
|
### 3.0 (2019-04-20)
|
||||||
|
|
||||||
- messages boxes had always the info icon even if a different icon (error, warning, question) was intended
|
- the history feature logs now only files that were opened longer than 90 seconds
|
||||||
- instead of silently do nothing on unknown commands there is now a error message listing available commands and showing the location of the default bindings, this helps when commands are removed or renamed
|
- the default input command for cycling the audio tracks was replaced with an
|
||||||
- there was a problem fixed that made the cursor hidden when it should be visible
|
mpv.net command that shows detailed track info and has no 'no audio' track
|
||||||
- dragging a youtube URL on mpv.net would break certain input related features
|
- new web site for mpv.net <https://mpv-net.github.io/mpv.net-web-site/>
|
||||||
- there is now an installer with file extension registration (limited on Win 10) available
|
- the Tracks menu supports now MKV edition selection. [Default binding](https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt#L106).
|
||||||
- WM_APPCOMMAND media keys were not working in the input (shortcut) editor and there were no defaults for prev and next defined
|
- the Navigate menu supports now chapter selection. [Default binding](https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt#L57).
|
||||||
|
- opening the context menu was crashing if the default binding for Tracks was missing
|
||||||
|
|
||||||
### 2.1 (2019-03-30)
|
[go to download page](https://github.com/stax76/mpv.net/releases)
|
||||||
|
|
||||||
- new input editor added, default key binding is here: <https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt#L89>
|
### 2.9 (2019-04-16)
|
||||||
|
|
||||||
### 2.0 (2019-03-28)
|
- clicking the right top corner in full screen mode
|
||||||
|
closes the player but it did not work on all displays
|
||||||
- setting track-auto-selection added to settings editor (<https://mpv.io/manual/master/#options-track-auto-selection>)
|
- the info display was changed to display the filename on top
|
||||||
- setting loop-playlist added to settings editor (<https://mpv.io/manual/master/#options-loop-playlist>)
|
so it's not displayed in the middle of the screen
|
||||||
- setting audio-file-auto added to settings editor (<https://mpv.io/manual/master/#options-audio-file-auto>)
|
- on start up of the conf editor all text is now selected in the
|
||||||
- setting video-sync added to settings editor (<https://mpv.io/manual/master/#options-video-sync>)
|
search text box so it's ready for a new search to be typed
|
||||||
- command execute-mpv-command added to menu: Tools > Enter a mpv command for execution
|
- the conf editor was changed to write the settings to disk
|
||||||
- added youtube-dl.exe, please note this will only work when a certain Visual C++ runtime is installed
|
only if the settings were actually modified, also the message
|
||||||
- added drag & drop support to drag & drop a youtube URL on mpv.net
|
that says that the settings will be available on next start
|
||||||
- added support to open a youtube URL from command line
|
is now only shown if the settings were actually modified.
|
||||||
- added support for opening a URL from the menu: Open > Open URL
|
- there was an instance in the context menu where the sub menu
|
||||||
|
arrow was overlapping with the text
|
||||||
|
- in the input editor when only one character is entered in the
|
||||||
|
search text box the search is performed only in the input and
|
||||||
|
not in the command or menu
|
||||||
|
- in the input editor the routine that generates the input string
|
||||||
|
was completely rewritten because it was adding Shift where it
|
||||||
|
wasn't necessary (it took a huge amount of time to implement)
|
||||||
|
- the context menu has a new track menu where the active track
|
||||||
|
can be seen and selected, it shows video, audio and subtitle
|
||||||
|
tracks with various metadata. [Menu default definition](https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt#L104).
|
||||||
|
The screenshots were updated showing the [new track menu](https://github.com/stax76/mpv.net#screenshots).
|
||||||
@@ -10,7 +10,7 @@ namespace RatingAddon
|
|||||||
[Export(typeof(IAddon))]
|
[Export(typeof(IAddon))]
|
||||||
public class RatingAddon : IAddon
|
public class RatingAddon : IAddon
|
||||||
{
|
{
|
||||||
private Dictionary<string, int> Dic = new Dictionary<string, int>();
|
Dictionary<string, int> Dic = new Dictionary<string, int>();
|
||||||
|
|
||||||
public RatingAddon()
|
public RatingAddon()
|
||||||
{
|
{
|
||||||
@@ -18,7 +18,7 @@ namespace RatingAddon
|
|||||||
mp.Shutdown += mpv_Shutdown;
|
mp.Shutdown += mpv_Shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mpv_Shutdown()
|
void mpv_Shutdown()
|
||||||
{
|
{
|
||||||
foreach (var i in Dic)
|
foreach (var i in Dic)
|
||||||
{
|
{
|
||||||
@@ -44,7 +44,7 @@ namespace RatingAddon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mpv_ClientMessage(string[] args)
|
void mpv_ClientMessage(string[] args)
|
||||||
{
|
{
|
||||||
int rating;
|
int rating;
|
||||||
|
|
||||||
|
|||||||
13
VBNET/My Project/Application.Designer.vb
generated
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
'------------------------------------------------------------------------------
|
||||||
|
' <auto-generated>
|
||||||
|
' This code was generated by a tool.
|
||||||
|
' Runtime Version:4.0.30319.42000
|
||||||
|
'
|
||||||
|
' Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
' the code is regenerated.
|
||||||
|
' </auto-generated>
|
||||||
|
'------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Option Strict On
|
||||||
|
Option Explicit On
|
||||||
|
|
||||||
10
VBNET/My Project/Application.myapp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||||
|
<MySubMain>false</MySubMain>
|
||||||
|
<SingleInstance>false</SingleInstance>
|
||||||
|
<ShutdownMode>0</ShutdownMode>
|
||||||
|
<EnableVisualStyles>true</EnableVisualStyles>
|
||||||
|
<AuthenticationMode>0</AuthenticationMode>
|
||||||
|
<ApplicationType>1</ApplicationType>
|
||||||
|
<SaveMySettingsOnExit>true</SaveMySettingsOnExit>
|
||||||
|
</MyApplicationData>
|
||||||
35
VBNET/My Project/AssemblyInfo.vb
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
Imports System
|
||||||
|
Imports System.Reflection
|
||||||
|
Imports System.Runtime.InteropServices
|
||||||
|
|
||||||
|
' General Information about an assembly is controlled through the following
|
||||||
|
' set of attributes. Change these attribute values to modify the information
|
||||||
|
' associated with an assembly.
|
||||||
|
|
||||||
|
' Review the values of the assembly attributes
|
||||||
|
|
||||||
|
<Assembly: AssemblyTitle("VBNET")>
|
||||||
|
<Assembly: AssemblyDescription("")>
|
||||||
|
<Assembly: AssemblyCompany("")>
|
||||||
|
<Assembly: AssemblyProduct("VBNET")>
|
||||||
|
<Assembly: AssemblyCopyright("Copyright © 2019")>
|
||||||
|
<Assembly: AssemblyTrademark("")>
|
||||||
|
|
||||||
|
<Assembly: ComVisible(False)>
|
||||||
|
|
||||||
|
'The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
<Assembly: Guid("a5571ff4-12ae-4e1a-ad2b-863b07d1b952")>
|
||||||
|
|
||||||
|
' Version information for an assembly consists of the following four values:
|
||||||
|
'
|
||||||
|
' Major Version
|
||||||
|
' Minor Version
|
||||||
|
' Build Number
|
||||||
|
' Revision
|
||||||
|
'
|
||||||
|
' You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
' by using the '*' as shown below:
|
||||||
|
' <Assembly: AssemblyVersion("1.0.*")>
|
||||||
|
|
||||||
|
<Assembly: AssemblyVersion("1.0.0.0")>
|
||||||
|
<Assembly: AssemblyFileVersion("1.0.0.0")>
|
||||||
62
VBNET/My Project/Resources.Designer.vb
generated
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
'------------------------------------------------------------------------------
|
||||||
|
' <auto-generated>
|
||||||
|
' This code was generated by a tool.
|
||||||
|
' Runtime Version:4.0.30319.42000
|
||||||
|
'
|
||||||
|
' Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
' the code is regenerated.
|
||||||
|
' </auto-generated>
|
||||||
|
'------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Option Strict On
|
||||||
|
Option Explicit On
|
||||||
|
|
||||||
|
|
||||||
|
Namespace My.Resources
|
||||||
|
|
||||||
|
'This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
'class via a tool like ResGen or Visual Studio.
|
||||||
|
'To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
'with the /str option, or rebuild your VS project.
|
||||||
|
'''<summary>
|
||||||
|
''' A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
'''</summary>
|
||||||
|
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0"), _
|
||||||
|
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||||
|
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||||
|
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
|
||||||
|
Friend Module Resources
|
||||||
|
|
||||||
|
Private resourceMan As Global.System.Resources.ResourceManager
|
||||||
|
|
||||||
|
Private resourceCulture As Global.System.Globalization.CultureInfo
|
||||||
|
|
||||||
|
'''<summary>
|
||||||
|
''' Returns the cached ResourceManager instance used by this class.
|
||||||
|
'''</summary>
|
||||||
|
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||||
|
Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
|
||||||
|
Get
|
||||||
|
If Object.ReferenceEquals(resourceMan, Nothing) Then
|
||||||
|
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("VBNET.Resources", GetType(Resources).Assembly)
|
||||||
|
resourceMan = temp
|
||||||
|
End If
|
||||||
|
Return resourceMan
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
|
||||||
|
'''<summary>
|
||||||
|
''' Overrides the current thread's CurrentUICulture property for all
|
||||||
|
''' resource lookups using this strongly typed resource class.
|
||||||
|
'''</summary>
|
||||||
|
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||||
|
Friend Property Culture() As Global.System.Globalization.CultureInfo
|
||||||
|
Get
|
||||||
|
Return resourceCulture
|
||||||
|
End Get
|
||||||
|
Set(ByVal value As Global.System.Globalization.CultureInfo)
|
||||||
|
resourceCulture = value
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
End Module
|
||||||
|
End Namespace
|
||||||
117
VBNET/My Project/Resources.resx
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
||||||
73
VBNET/My Project/Settings.Designer.vb
generated
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
'------------------------------------------------------------------------------
|
||||||
|
' <auto-generated>
|
||||||
|
' This code was generated by a tool.
|
||||||
|
' Runtime Version:4.0.30319.42000
|
||||||
|
'
|
||||||
|
' Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
' the code is regenerated.
|
||||||
|
' </auto-generated>
|
||||||
|
'------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Option Strict On
|
||||||
|
Option Explicit On
|
||||||
|
|
||||||
|
|
||||||
|
Namespace My
|
||||||
|
|
||||||
|
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||||
|
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0"), _
|
||||||
|
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||||
|
Partial Friend NotInheritable Class MySettings
|
||||||
|
Inherits Global.System.Configuration.ApplicationSettingsBase
|
||||||
|
|
||||||
|
Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings), MySettings)
|
||||||
|
|
||||||
|
#Region "My.Settings Auto-Save Functionality"
|
||||||
|
#If _MyType = "WindowsForms" Then
|
||||||
|
Private Shared addedHandler As Boolean
|
||||||
|
|
||||||
|
Private Shared addedHandlerLockObject As New Object
|
||||||
|
|
||||||
|
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||||
|
Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs)
|
||||||
|
If My.Application.SaveMySettingsOnExit Then
|
||||||
|
My.Settings.Save()
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
#End If
|
||||||
|
#End Region
|
||||||
|
|
||||||
|
Public Shared ReadOnly Property [Default]() As MySettings
|
||||||
|
Get
|
||||||
|
|
||||||
|
#If _MyType = "WindowsForms" Then
|
||||||
|
If Not addedHandler Then
|
||||||
|
SyncLock addedHandlerLockObject
|
||||||
|
If Not addedHandler Then
|
||||||
|
AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
|
||||||
|
addedHandler = True
|
||||||
|
End If
|
||||||
|
End SyncLock
|
||||||
|
End If
|
||||||
|
#End If
|
||||||
|
Return defaultInstance
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
End Class
|
||||||
|
End Namespace
|
||||||
|
|
||||||
|
Namespace My
|
||||||
|
|
||||||
|
<Global.Microsoft.VisualBasic.HideModuleNameAttribute(), _
|
||||||
|
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||||
|
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _
|
||||||
|
Friend Module MySettingsProperty
|
||||||
|
|
||||||
|
<Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")> _
|
||||||
|
Friend ReadOnly Property Settings() As Global.VBNET.My.MySettings
|
||||||
|
Get
|
||||||
|
Return Global.VBNET.My.MySettings.Default
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
End Module
|
||||||
|
End Namespace
|
||||||
7
VBNET/My Project/Settings.settings
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" UseMySettingsClassName="true">
|
||||||
|
<Profiles>
|
||||||
|
<Profile Name="(Default)" />
|
||||||
|
</Profiles>
|
||||||
|
<Settings />
|
||||||
|
</SettingsFile>
|
||||||
678
VBNET/TaskDialog.vb
Normal file
@@ -0,0 +1,678 @@
|
|||||||
|
Imports System.IO
|
||||||
|
Imports System.Reflection
|
||||||
|
Imports System.Runtime.InteropServices
|
||||||
|
Imports System.Text
|
||||||
|
Imports System.Text.RegularExpressions
|
||||||
|
Imports System.Threading
|
||||||
|
|
||||||
|
Public Delegate Function PFTASKDIALOGCALLBACK(hwnd As IntPtr,
|
||||||
|
msg As UInteger,
|
||||||
|
wParam As IntPtr,
|
||||||
|
lParam As IntPtr,
|
||||||
|
lpRefData As IntPtr) As Integer
|
||||||
|
Public Class Msg
|
||||||
|
Public Shared Property SupportURL As String
|
||||||
|
|
||||||
|
Public Shared Sub Show(mainInstruction As String, Optional content As String = Nothing)
|
||||||
|
Show(mainInstruction, content, MsgIcon.Info, MsgButtons.Ok)
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Public Shared Sub ShowError(mainInstruction As String, Optional content As String = Nothing)
|
||||||
|
If mainInstruction = "" Then mainInstruction = content
|
||||||
|
If mainInstruction = "" Then Exit Sub
|
||||||
|
|
||||||
|
Using td As New TaskDialog(Of String)
|
||||||
|
td.AllowCancel = False
|
||||||
|
|
||||||
|
If content = "" Then
|
||||||
|
If mainInstruction.Length < 80 Then
|
||||||
|
td.MainInstruction = mainInstruction
|
||||||
|
Else
|
||||||
|
td.Content = mainInstruction
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
td.MainInstruction = mainInstruction
|
||||||
|
td.Content = content
|
||||||
|
End If
|
||||||
|
|
||||||
|
td.MainIcon = MsgIcon.Error
|
||||||
|
td.Footer = "[copymsg Copy Message]"
|
||||||
|
If SupportURL <> "" Then td.Footer += $" [{SupportURL} Contact Support]"
|
||||||
|
td.Show()
|
||||||
|
End Using
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Public Shared Sub ShowException(e As Exception)
|
||||||
|
Try
|
||||||
|
Using td As New TaskDialog(Of String)
|
||||||
|
td.MainInstruction = e.GetType.Name
|
||||||
|
td.Content = e.Message
|
||||||
|
td.MainIcon = MsgIcon.Error
|
||||||
|
td.ExpandedInformation = e.ToString
|
||||||
|
td.Footer = "[copymsg Copy Message]"
|
||||||
|
If SupportURL <> "" Then td.Footer += $" [{SupportURL} Contact Support]"
|
||||||
|
td.Show()
|
||||||
|
End Using
|
||||||
|
Catch
|
||||||
|
MsgBox(e.GetType.Name + vbCrLf + vbCrLf + e.Message + vbCrLf + vbCrLf + e.ToString, MsgBoxStyle.Critical)
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Shared ShownMessages As String
|
||||||
|
|
||||||
|
Public Shared Sub ShowWarning(mainInstruction As String,
|
||||||
|
Optional content As String = Nothing,
|
||||||
|
Optional onlyOnce As Boolean = False)
|
||||||
|
|
||||||
|
If onlyOnce AndAlso ShownMessages?.Contains(mainInstruction + content) Then Exit Sub
|
||||||
|
Show(mainInstruction, content, MsgIcon.Warning, MsgButtons.Ok)
|
||||||
|
If onlyOnce Then ShownMessages += mainInstruction + content
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Public Shared Function ShowQuestion(mainInstruction As String,
|
||||||
|
Optional buttons As MsgButtons = MsgButtons.OkCancel) As MsgResult
|
||||||
|
|
||||||
|
Return Show(mainInstruction, Nothing, MsgIcon.None, buttons)
|
||||||
|
End Function
|
||||||
|
|
||||||
|
Public Shared Function ShowQuestion(mainInstruction As String,
|
||||||
|
content As String,
|
||||||
|
Optional buttons As MsgButtons = MsgButtons.OkCancel) As MsgResult
|
||||||
|
Return Show(mainInstruction, content, MsgIcon.None, buttons)
|
||||||
|
End Function
|
||||||
|
|
||||||
|
Public Shared Function Show(mainInstruction As String,
|
||||||
|
content As String,
|
||||||
|
icon As MsgIcon,
|
||||||
|
buttons As MsgButtons,
|
||||||
|
Optional defaultButton As MsgResult = MsgResult.None) As MsgResult
|
||||||
|
|
||||||
|
If mainInstruction Is Nothing Then mainInstruction = ""
|
||||||
|
|
||||||
|
Using td As New TaskDialog(Of MsgResult)
|
||||||
|
td.AllowCancel = False
|
||||||
|
td.DefaultButton = defaultButton
|
||||||
|
td.MainIcon = icon
|
||||||
|
|
||||||
|
If content Is Nothing Then
|
||||||
|
If mainInstruction.Length < 80 Then
|
||||||
|
td.MainInstruction = mainInstruction
|
||||||
|
Else
|
||||||
|
td.Content = mainInstruction
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
td.MainInstruction = mainInstruction
|
||||||
|
td.Content = content
|
||||||
|
End If
|
||||||
|
|
||||||
|
If buttons = MsgButtons.OkCancel Then
|
||||||
|
td.AddButton("OK", MsgResult.OK)
|
||||||
|
td.AddButton("Cancel", MsgResult.Cancel) 'don't use system language
|
||||||
|
Else
|
||||||
|
td.CommonButtons = buttons
|
||||||
|
End If
|
||||||
|
|
||||||
|
Return td.Show()
|
||||||
|
End Using
|
||||||
|
End Function
|
||||||
|
End Class
|
||||||
|
|
||||||
|
Public Class TaskDialog(Of T)
|
||||||
|
Inherits TaskDialogNative
|
||||||
|
Implements IDisposable
|
||||||
|
|
||||||
|
Private IdValueDic As New Dictionary(Of Integer, T)
|
||||||
|
Private IdTextDic As New Dictionary(Of Integer, String)
|
||||||
|
Private CommandLinkShieldList As New List(Of Integer)
|
||||||
|
Private ButtonArray As IntPtr, RadioButtonArray As IntPtr
|
||||||
|
Private Buttons As New List(Of TASKDIALOG_BUTTON)
|
||||||
|
Private RadioButtons As New List(Of TASKDIALOG_BUTTON)
|
||||||
|
|
||||||
|
Private Config As TASKDIALOGCONFIG
|
||||||
|
|
||||||
|
Sub New()
|
||||||
|
Config = New TASKDIALOGCONFIG()
|
||||||
|
|
||||||
|
Config.cbSize = CUInt(Marshal.SizeOf(Config))
|
||||||
|
Config.hwndParent = GetHandle()
|
||||||
|
Config.hInstance = IntPtr.Zero
|
||||||
|
Config.dwFlags = TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION
|
||||||
|
Config.dwCommonButtons = MsgButtons.None
|
||||||
|
Config.MainIcon = New TASKDIALOGCONFIG_ICON_UNION(0)
|
||||||
|
Config.FooterIcon = New TASKDIALOGCONFIG_ICON_UNION(0)
|
||||||
|
Config.cxWidth = 0
|
||||||
|
|
||||||
|
Config.cButtons = 0
|
||||||
|
Config.cRadioButtons = 0
|
||||||
|
Config.pButtons = IntPtr.Zero
|
||||||
|
Config.pRadioButtons = IntPtr.Zero
|
||||||
|
Config.nDefaultButton = 0
|
||||||
|
Config.nDefaultRadioButton = 0
|
||||||
|
|
||||||
|
Config.pszWindowTitle = DirectCast(Assembly.GetEntryAssembly().GetCustomAttributes(GetType(AssemblyProductAttribute), True)(0), AssemblyProductAttribute).Product
|
||||||
|
Config.pszMainInstruction = ""
|
||||||
|
Config.pszContent = ""
|
||||||
|
Config.pszVerificationText = Nothing
|
||||||
|
Config.pszExpandedInformation = Nothing
|
||||||
|
Config.pszExpandedControlText = Nothing
|
||||||
|
Config.pszCollapsedControlText = Nothing
|
||||||
|
Config.pszFooter = Nothing
|
||||||
|
|
||||||
|
Config.pfCallback = New PFTASKDIALOGCALLBACK(AddressOf DialogProc)
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Function GetHandle() As IntPtr
|
||||||
|
Dim sb As New StringBuilder(260)
|
||||||
|
Dim foregroundHandle = GetForegroundWindow()
|
||||||
|
GetWindowModuleFileName(foregroundHandle, sb, 260)
|
||||||
|
|
||||||
|
If Path.GetFileName(sb.ToString.Replace(".vshost", "")) =
|
||||||
|
Path.GetFileName(System.Reflection.Assembly.GetEntryAssembly().Location) Then
|
||||||
|
|
||||||
|
Return foregroundHandle
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
|
||||||
|
#Region "Constants"
|
||||||
|
Const TDE_CONTENT As Integer = 0
|
||||||
|
Const TDE_EXPANDED_INFORMATION As Integer = 1
|
||||||
|
Const TDE_FOOTER As Integer = 2
|
||||||
|
Const TDE_MAIN_INSTRUCTION As Integer = 3
|
||||||
|
|
||||||
|
Const TDN_CREATED As Integer = 0
|
||||||
|
Const TDN_NAVIGATED As Integer = 1
|
||||||
|
Const TDN_BUTTON_CLICKED As Integer = 2
|
||||||
|
Const TDN_HYPERLINK_CLICKED As Integer = 3
|
||||||
|
Const TDN_TIMER As Integer = 4
|
||||||
|
Const TDN_DESTROYED As Integer = 5
|
||||||
|
Const TDN_RADIO_BUTTON_CLICKED As Integer = 6
|
||||||
|
Const TDN_DIALOG_CONSTRUCTED As Integer = 7
|
||||||
|
Const TDN_VERIFICATION_CLICKED As Integer = 8
|
||||||
|
Const TDN_HELP As Integer = 9
|
||||||
|
Const TDN_EXPANDO_BUTTON_CLICKED As Integer = 10
|
||||||
|
|
||||||
|
Const TDM_NAVIGATE_PAGE As Integer = &H400 + 101
|
||||||
|
Const TDM_CLICK_BUTTON As Integer = &H400 + 102 'wParam = Button ID
|
||||||
|
Const TDM_SET_MARQUEE_PROGRESS_BAR As Integer = &H400 + 103 'wParam = 0 (nonMarque) wParam != 0 (Marquee)
|
||||||
|
Const TDM_SET_PROGRESS_BAR_STATE As Integer = &H400 + 104 'wParam = new progress state
|
||||||
|
Const TDM_SET_PROGRESS_BAR_RANGE As Integer = &H400 + 105 'lParam = MAKELPARAM(nMinRange, nMaxRange)
|
||||||
|
Const TDM_SET_PROGRESS_BAR_POS As Integer = &H400 + 106 'wParam = new position
|
||||||
|
Const TDM_SET_PROGRESS_BAR_MARQUEE As Integer = &H400 + 107 'wParam = 0 (stop marquee), wParam != 0 (start marquee), lparam = speed (milliseconds between repaints)
|
||||||
|
Const TDM_SET_ELEMENT_TEXT As Integer = &H400 + 108 'wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR)
|
||||||
|
Const TDM_CLICK_RADIO_BUTTON As Integer = &H400 + 110 'wParam = Radio Button ID
|
||||||
|
Const TDM_ENABLE_BUTTON As Integer = &H400 + 111 'lParam = 0 (disable), lParam != 0 (enable), wParam = Button ID
|
||||||
|
Const TDM_ENABLE_RADIO_BUTTON As Integer = &H400 + 112 'lParam = 0 (disable), lParam != 0 (enable), wParam = Radio Button ID
|
||||||
|
Const TDM_CLICK_VERIFICATION As Integer = &H400 + 113 'wParam = 0 (unchecked), 1 (checked), lParam = 1 (set key focus)
|
||||||
|
Const TDM_UPDATE_ELEMENT_TEXT As Integer = &H400 + 114 'wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR)
|
||||||
|
Const TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE As Integer = &H400 + 115 'wParam = Button ID, lParam = 0 (elevation not required), lParam != 0 (elevation required)
|
||||||
|
Const TDM_UPDATE_ICON As Integer = &H400 + 116 'wParam = icon element (TASKDIALOG_ICON_ELEMENTS), lParam = new icon (hIcon if TDF_USE_HICON_* was set, PCWSTR otherwise)
|
||||||
|
#End Region
|
||||||
|
|
||||||
|
#Region "Properties"
|
||||||
|
|
||||||
|
Private AllowCancelValue As Boolean
|
||||||
|
|
||||||
|
WriteOnly Property AllowCancel() As Boolean
|
||||||
|
Set(Value As Boolean)
|
||||||
|
If Value Then
|
||||||
|
Config.dwFlags = Config.dwFlags Or TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION
|
||||||
|
ElseIf (Config.dwFlags And TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION) = TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION Then
|
||||||
|
Config.dwFlags = Config.dwFlags Xor TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION
|
||||||
|
End If
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
|
||||||
|
Property MainInstruction() As String
|
||||||
|
Get
|
||||||
|
Return Config.pszMainInstruction
|
||||||
|
End Get
|
||||||
|
Set(Value As String)
|
||||||
|
Config.pszMainInstruction = Value
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
|
||||||
|
Property Content() As String
|
||||||
|
Get
|
||||||
|
Return Config.pszContent
|
||||||
|
End Get
|
||||||
|
Set(Value As String)
|
||||||
|
Config.pszContent = ExpandWikiMarkup(Value)
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
|
||||||
|
Property ExpandedInformation() As String
|
||||||
|
Get
|
||||||
|
Return Config.pszExpandedInformation
|
||||||
|
End Get
|
||||||
|
Set(Value As String)
|
||||||
|
Config.pszExpandedInformation = ExpandWikiMarkup(Value)
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
|
||||||
|
Property VerificationText() As String
|
||||||
|
Get
|
||||||
|
Return Config.pszVerificationText
|
||||||
|
End Get
|
||||||
|
Set(Value As String)
|
||||||
|
Config.pszVerificationText = Value
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
|
||||||
|
Property DefaultButton() As MsgResult
|
||||||
|
Get
|
||||||
|
Return CType(Config.nDefaultButton, MsgResult)
|
||||||
|
End Get
|
||||||
|
Set(Value As MsgResult)
|
||||||
|
Config.nDefaultButton = Value
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
|
||||||
|
Property Footer() As String
|
||||||
|
Get
|
||||||
|
Return Config.pszFooter
|
||||||
|
End Get
|
||||||
|
Set(Value As String)
|
||||||
|
Config.pszFooter = ExpandWikiMarkup(Value)
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
|
||||||
|
WriteOnly Property MainIcon() As MsgIcon
|
||||||
|
Set(Value As MsgIcon)
|
||||||
|
Config.MainIcon = New TASKDIALOGCONFIG_ICON_UNION(Value)
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
|
||||||
|
Private SelectedIDValue As Integer = -1
|
||||||
|
|
||||||
|
Property SelectedID As Integer
|
||||||
|
Get
|
||||||
|
Return SelectedIDValue
|
||||||
|
End Get
|
||||||
|
Set(value As Integer)
|
||||||
|
For Each i In IdValueDic
|
||||||
|
If i.Key = value Then SelectedIDValue = value
|
||||||
|
Next
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
|
||||||
|
Private SelectedValueValue As T
|
||||||
|
|
||||||
|
Property SelectedValue() As T
|
||||||
|
Get
|
||||||
|
If IdValueDic.ContainsKey(SelectedID) Then Return IdValueDic(SelectedID)
|
||||||
|
Return SelectedValueValue
|
||||||
|
End Get
|
||||||
|
Set(value As T)
|
||||||
|
SelectedValueValue = value
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
|
||||||
|
Private SelectedTextValue As String
|
||||||
|
|
||||||
|
Property SelectedText() As String
|
||||||
|
Get
|
||||||
|
If IdTextDic.ContainsKey(SelectedID) Then Return IdTextDic(SelectedID)
|
||||||
|
Return SelectedTextValue
|
||||||
|
End Get
|
||||||
|
Set(value As String)
|
||||||
|
SelectedTextValue = value
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
|
||||||
|
Property CheckBoxChecked() As Boolean
|
||||||
|
Get
|
||||||
|
Return (Config.dwFlags And TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED) = TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED
|
||||||
|
End Get
|
||||||
|
Set(value As Boolean)
|
||||||
|
If value Then
|
||||||
|
Config.dwFlags = Config.dwFlags Or TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED
|
||||||
|
ElseIf CheckBoxChecked Then
|
||||||
|
Config.dwFlags = Config.dwFlags Xor TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED
|
||||||
|
End If
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
|
||||||
|
Private CommonButtonsValue As MsgButtons
|
||||||
|
|
||||||
|
Property CommonButtons() As MsgButtons
|
||||||
|
Get
|
||||||
|
Return Config.dwCommonButtons
|
||||||
|
End Get
|
||||||
|
Set(Value As MsgButtons)
|
||||||
|
Config.dwCommonButtons = Value
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
|
||||||
|
Private TimeoutValue As Integer
|
||||||
|
|
||||||
|
Property Timeout As Integer
|
||||||
|
Get
|
||||||
|
Return CInt(TimeoutValue / 1000)
|
||||||
|
End Get
|
||||||
|
Set(Value As Integer)
|
||||||
|
TimeoutValue = Value * 1000
|
||||||
|
|
||||||
|
If Value > 0 Then
|
||||||
|
Config.dwFlags = Config.dwFlags Or TASKDIALOG_FLAGS.TDF_CALLBACK_TIMER
|
||||||
|
End If
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
#End Region
|
||||||
|
|
||||||
|
#Region "Methods"
|
||||||
|
|
||||||
|
Sub AddButton(text As String, value As T)
|
||||||
|
Dim id = 1000 + IdValueDic.Count + 1
|
||||||
|
IdValueDic(id) = value
|
||||||
|
Buttons.Add(New TASKDIALOG_BUTTON(id, text))
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Function ExpandWikiMarkup(value As String) As String
|
||||||
|
If value.Contains("[") Then
|
||||||
|
Dim re As New Regex("\[(.*?) (.+?)\]")
|
||||||
|
Dim m = re.Match(value)
|
||||||
|
|
||||||
|
If m.Success Then
|
||||||
|
Config.dwFlags = Config.dwFlags Or TASKDIALOG_FLAGS.TDF_ENABLE_HYPERLINKS
|
||||||
|
value = re.Replace(value, "<a href=""$1"">$2</a>")
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
|
||||||
|
Return value
|
||||||
|
End Function
|
||||||
|
|
||||||
|
Sub AddCommandLink(text As String, Optional value As T = Nothing)
|
||||||
|
Dim id = 1000 + IdValueDic.Count + 1
|
||||||
|
Dim temp As Object = text
|
||||||
|
IdValueDic(id) = If(value Is Nothing, CType(temp, T), value)
|
||||||
|
IdTextDic(id) = text
|
||||||
|
Buttons.Add(New TASKDIALOG_BUTTON(id, text))
|
||||||
|
Config.dwFlags = Config.dwFlags Or TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Sub AddCommandLink(text As String,
|
||||||
|
description As String,
|
||||||
|
value As T,
|
||||||
|
Optional setShield As Boolean = False)
|
||||||
|
|
||||||
|
Dim id = 1000 + IdValueDic.Count + 1
|
||||||
|
IdValueDic(id) = value
|
||||||
|
If setShield Then CommandLinkShieldList.Add(id)
|
||||||
|
If description <> "" Then text = text + vbCrLf + description
|
||||||
|
Buttons.Add(New TASKDIALOG_BUTTON(id, text))
|
||||||
|
Config.dwFlags = Config.dwFlags Or TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Sub AddRadioButton(text As String, value As T)
|
||||||
|
Dim id = 1000 + IdValueDic.Count + 1
|
||||||
|
IdValueDic(id) = value
|
||||||
|
RadioButtons.Add(New TASKDIALOG_BUTTON(id, text))
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Function Show() As T
|
||||||
|
MarshalDialogControlStructs()
|
||||||
|
Dim isChecked As Boolean
|
||||||
|
Dim hr = TaskDialogIndirect(Config, Nothing, Nothing, isChecked)
|
||||||
|
CheckBoxChecked = isChecked
|
||||||
|
If hr < 0 Then Marshal.ThrowExceptionForHR(hr)
|
||||||
|
If TypeOf SelectedValue Is MsgResult Then SelectedValue = DirectCast(CObj(SelectedID), T)
|
||||||
|
Return SelectedValue
|
||||||
|
End Function
|
||||||
|
|
||||||
|
Private ExitTickCount As Integer
|
||||||
|
|
||||||
|
Function DialogProc(hwnd As IntPtr,
|
||||||
|
msg As UInteger,
|
||||||
|
wParam As IntPtr,
|
||||||
|
lParam As IntPtr,
|
||||||
|
lpRefData As IntPtr) As Integer
|
||||||
|
Select Case msg
|
||||||
|
Case TDN_BUTTON_CLICKED, TDN_RADIO_BUTTON_CLICKED
|
||||||
|
If TypeOf SelectedValue Is MsgResult Then
|
||||||
|
SelectedIDValue = wParam.ToInt32
|
||||||
|
Else
|
||||||
|
SelectedID = wParam.ToInt32
|
||||||
|
End If
|
||||||
|
Case TDN_TIMER
|
||||||
|
If ExitTickCount = 0 Then
|
||||||
|
ExitTickCount = Environment.TickCount + Timeout * 1000
|
||||||
|
End If
|
||||||
|
|
||||||
|
If Environment.TickCount > ExitTickCount Then
|
||||||
|
SendMessage(hwnd, TDM_CLICK_BUTTON, New IntPtr(MsgResult.OK), IntPtr.Zero)
|
||||||
|
End If
|
||||||
|
Case TDN_HYPERLINK_CLICKED
|
||||||
|
Dim url = Marshal.PtrToStringUni(lParam)
|
||||||
|
|
||||||
|
If url.StartsWith("mailto") OrElse url.StartsWith("http") Then
|
||||||
|
Process.Start(url)
|
||||||
|
ElseIf url = "copymsg" Then
|
||||||
|
Dim thread As New Thread(
|
||||||
|
New ThreadStart(Sub()
|
||||||
|
System.Windows.Forms.Clipboard.SetText(MainInstruction + vbCrLf + vbCrLf + Content + vbCrLf + vbCrLf + ExpandedInformation)
|
||||||
|
MsgBox("Message was copied to clipboard.",
|
||||||
|
MsgBoxStyle.Information,
|
||||||
|
DirectCast(Assembly.GetEntryAssembly().GetCustomAttributes(GetType(AssemblyProductAttribute), True)(0), AssemblyProductAttribute).Product)
|
||||||
|
End Sub))
|
||||||
|
thread.SetApartmentState(ApartmentState.STA)
|
||||||
|
thread.Start()
|
||||||
|
End If
|
||||||
|
Case TDN_CREATED
|
||||||
|
For Each i In CommandLinkShieldList
|
||||||
|
SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, New IntPtr(i), New IntPtr(1))
|
||||||
|
Next
|
||||||
|
End Select
|
||||||
|
End Function
|
||||||
|
|
||||||
|
Sub MarshalDialogControlStructs()
|
||||||
|
If Not Buttons Is Nothing AndAlso Buttons.Count > 0 Then
|
||||||
|
ButtonArray = AllocateAndMarshalButtons(Buttons)
|
||||||
|
Config.pButtons = ButtonArray
|
||||||
|
Config.cButtons = CUInt(Buttons.Count)
|
||||||
|
End If
|
||||||
|
|
||||||
|
If Not RadioButtons Is Nothing AndAlso RadioButtons.Count > 0 Then
|
||||||
|
RadioButtonArray = AllocateAndMarshalButtons(RadioButtons)
|
||||||
|
Config.pRadioButtons = RadioButtonArray
|
||||||
|
Config.cRadioButtons = CUInt(RadioButtons.Count)
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Shared Function AllocateAndMarshalButtons(structs As List(Of TASKDIALOG_BUTTON)) As IntPtr
|
||||||
|
Dim initialPtr = Marshal.AllocHGlobal(Marshal.SizeOf(GetType(TASKDIALOG_BUTTON)) * structs.Count)
|
||||||
|
Dim currentPtr = initialPtr
|
||||||
|
|
||||||
|
For Each button In structs
|
||||||
|
Marshal.StructureToPtr(button, currentPtr, False)
|
||||||
|
currentPtr = CType((currentPtr.ToInt64 + Marshal.SizeOf(button)), IntPtr)
|
||||||
|
Next
|
||||||
|
|
||||||
|
Return initialPtr
|
||||||
|
End Function
|
||||||
|
|
||||||
|
#End Region
|
||||||
|
|
||||||
|
#Region "IDispose Pattern"
|
||||||
|
|
||||||
|
Private disposed As Boolean
|
||||||
|
|
||||||
|
Sub Dispose() Implements IDisposable.Dispose
|
||||||
|
Dispose(True)
|
||||||
|
GC.SuppressFinalize(Me)
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Protected Overrides Sub Finalize()
|
||||||
|
Try
|
||||||
|
Dispose(False)
|
||||||
|
Finally
|
||||||
|
MyBase.Finalize()
|
||||||
|
End Try
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Protected Sub Dispose(disposing As Boolean)
|
||||||
|
If Not disposed Then
|
||||||
|
disposed = True
|
||||||
|
|
||||||
|
If ButtonArray <> IntPtr.Zero Then
|
||||||
|
Marshal.FreeHGlobal(ButtonArray)
|
||||||
|
ButtonArray = IntPtr.Zero
|
||||||
|
End If
|
||||||
|
|
||||||
|
If RadioButtonArray <> IntPtr.Zero Then
|
||||||
|
Marshal.FreeHGlobal(RadioButtonArray)
|
||||||
|
RadioButtonArray = IntPtr.Zero
|
||||||
|
End If
|
||||||
|
|
||||||
|
If disposing Then
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
#End Region
|
||||||
|
|
||||||
|
End Class
|
||||||
|
|
||||||
|
Public Class TaskDialogNative
|
||||||
|
<DllImport("comctl32", CharSet:=CharSet.Unicode, SetLastError:=True)>
|
||||||
|
Shared Function TaskDialogIndirect(<[In]()> pTaskConfig As TASKDIALOGCONFIG, <Out()> ByRef pnButton As Integer, <Out()> ByRef pnRadioButton As Integer, <MarshalAs(UnmanagedType.Bool)> <Out()> ByRef pVerificationFlagChecked As Boolean) As Integer
|
||||||
|
End Function
|
||||||
|
|
||||||
|
<DllImport("user32.dll")>
|
||||||
|
Shared Function GetForegroundWindow() As IntPtr
|
||||||
|
End Function
|
||||||
|
|
||||||
|
<DllImport("user32.dll", CharSet:=CharSet.Unicode)>
|
||||||
|
Shared Function GetWindowModuleFileName(hwnd As IntPtr,
|
||||||
|
lpszFileName As StringBuilder,
|
||||||
|
cchFileNameMax As UInteger) As UInteger
|
||||||
|
End Function
|
||||||
|
|
||||||
|
<DllImport("user32.dll")>
|
||||||
|
Shared Function SendMessage(handle As IntPtr,
|
||||||
|
message As Int32,
|
||||||
|
wParam As IntPtr,
|
||||||
|
lParam As IntPtr) As IntPtr
|
||||||
|
End Function
|
||||||
|
|
||||||
|
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode, Pack:=4)>
|
||||||
|
Public Class TASKDIALOGCONFIG
|
||||||
|
Public cbSize As UInteger
|
||||||
|
Public hwndParent As IntPtr
|
||||||
|
Public hInstance As IntPtr
|
||||||
|
Public dwFlags As TASKDIALOG_FLAGS
|
||||||
|
Public dwCommonButtons As MsgButtons
|
||||||
|
<MarshalAs(UnmanagedType.LPWStr)>
|
||||||
|
Public pszWindowTitle As String
|
||||||
|
Public MainIcon As TASKDIALOGCONFIG_ICON_UNION
|
||||||
|
<MarshalAs(UnmanagedType.LPWStr)>
|
||||||
|
Public pszMainInstruction As String
|
||||||
|
<MarshalAs(UnmanagedType.LPWStr)>
|
||||||
|
Public pszContent As String
|
||||||
|
Public cButtons As UInteger
|
||||||
|
Public pButtons As IntPtr
|
||||||
|
Public nDefaultButton As Integer
|
||||||
|
Public cRadioButtons As UInteger
|
||||||
|
Public pRadioButtons As IntPtr
|
||||||
|
Public nDefaultRadioButton As Integer
|
||||||
|
<MarshalAs(UnmanagedType.LPWStr)>
|
||||||
|
Public pszVerificationText As String
|
||||||
|
<MarshalAs(UnmanagedType.LPWStr)>
|
||||||
|
Public pszExpandedInformation As String
|
||||||
|
<MarshalAs(UnmanagedType.LPWStr)>
|
||||||
|
Public pszExpandedControlText As String
|
||||||
|
<MarshalAs(UnmanagedType.LPWStr)>
|
||||||
|
Public pszCollapsedControlText As String
|
||||||
|
Public FooterIcon As TASKDIALOGCONFIG_ICON_UNION
|
||||||
|
<MarshalAs(UnmanagedType.LPWStr)>
|
||||||
|
Public pszFooter As String
|
||||||
|
Public pfCallback As PFTASKDIALOGCALLBACK
|
||||||
|
Public lpCallbackData As IntPtr
|
||||||
|
Public cxWidth As UInteger
|
||||||
|
End Class
|
||||||
|
|
||||||
|
Public Enum TASKDIALOG_FLAGS
|
||||||
|
NONE = 0
|
||||||
|
TDF_ENABLE_HYPERLINKS = &H1
|
||||||
|
TDF_USE_HICON_MAIN = &H2
|
||||||
|
TDF_USE_HICON_FOOTER = &H4
|
||||||
|
TDF_ALLOW_DIALOG_CANCELLATION = &H8
|
||||||
|
TDF_USE_COMMAND_LINKS = &H10
|
||||||
|
TDF_USE_COMMAND_LINKS_NO_ICON = &H20
|
||||||
|
TDF_EXPAND_FOOTER_AREA = &H40
|
||||||
|
TDF_EXPANDED_BY_DEFAULT = &H80
|
||||||
|
TDF_VERIFICATION_FLAG_CHECKED = &H100
|
||||||
|
TDF_SHOW_PROGRESS_BAR = &H200
|
||||||
|
TDF_SHOW_MARQUEE_PROGRESS_BAR = &H400
|
||||||
|
TDF_CALLBACK_TIMER = &H800
|
||||||
|
TDF_POSITION_RELATIVE_TO_WINDOW = &H1000
|
||||||
|
TDF_RTL_LAYOUT = &H2000
|
||||||
|
TDF_NO_DEFAULT_RADIO_BUTTON = &H4000
|
||||||
|
End Enum
|
||||||
|
|
||||||
|
<StructLayout(LayoutKind.Explicit, CharSet:=CharSet.Unicode)>
|
||||||
|
Public Structure TASKDIALOGCONFIG_ICON_UNION
|
||||||
|
Sub New(i As Integer)
|
||||||
|
spacer = IntPtr.Zero
|
||||||
|
pszIcon = 0
|
||||||
|
hMainIcon = i
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
<FieldOffset(0)>
|
||||||
|
Public hMainIcon As Integer
|
||||||
|
<FieldOffset(0)>
|
||||||
|
Public pszIcon As Integer
|
||||||
|
<FieldOffset(0)>
|
||||||
|
Public spacer As IntPtr
|
||||||
|
End Structure
|
||||||
|
|
||||||
|
<StructLayout(LayoutKind.Sequential,
|
||||||
|
CharSet:=CharSet.Unicode, Pack:=4)>
|
||||||
|
Public Structure TASKDIALOG_BUTTON
|
||||||
|
Sub New(n As Integer, txt As String)
|
||||||
|
nButtonID = n
|
||||||
|
pszButtonText = txt
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Public nButtonID As Integer
|
||||||
|
<MarshalAs(UnmanagedType.LPWStr)>
|
||||||
|
Public pszButtonText As String
|
||||||
|
End Structure
|
||||||
|
End Class
|
||||||
|
|
||||||
|
Public Enum MsgButtons
|
||||||
|
None = &H0
|
||||||
|
Ok = &H1
|
||||||
|
Yes = &H2
|
||||||
|
No = &H4
|
||||||
|
Cancel = &H8
|
||||||
|
Retry = &H10
|
||||||
|
RetryCancel = Retry Or Cancel
|
||||||
|
Close = &H20
|
||||||
|
OkCancel = Ok Or Cancel
|
||||||
|
YesNo = Yes Or No
|
||||||
|
YesNoCancel = YesNo Or Cancel
|
||||||
|
End Enum
|
||||||
|
|
||||||
|
Public Enum MsgIcon
|
||||||
|
None = 0
|
||||||
|
Warning = 65535 'TD_WARNING_ICON
|
||||||
|
[Error] = 65534 'TD_ERROR_ICON
|
||||||
|
Info = 65533 'TD_INFORMATION_ICON
|
||||||
|
Shield = 65532 'TD_SHIELD_ICON
|
||||||
|
SecurityShieldBlue = 65531
|
||||||
|
SecurityWarning = 65530
|
||||||
|
SecurityError = 65529
|
||||||
|
SecuritySuccess = 65528
|
||||||
|
SecurityShieldGray = 65527
|
||||||
|
End Enum
|
||||||
|
|
||||||
|
Public Enum MsgResult
|
||||||
|
None = 0
|
||||||
|
OK = 1
|
||||||
|
Cancel = 2
|
||||||
|
Abort = 3
|
||||||
|
Retry = 4
|
||||||
|
Ignore = 5
|
||||||
|
Yes = 6
|
||||||
|
No = 7
|
||||||
|
End Enum
|
||||||
109
VBNET/VBNET.vbproj
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{A1D11294-05BF-4D77-B008-AECF1AA93C9F}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<RootNamespace>VBNET</RootNamespace>
|
||||||
|
<AssemblyName>VBNET</AssemblyName>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<MyType>Windows</MyType>
|
||||||
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<DefineDebug>true</DefineDebug>
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DocumentationFile>
|
||||||
|
</DocumentationFile>
|
||||||
|
<NoWarn>42353,42354,42355</NoWarn>
|
||||||
|
<WarningsAsErrors>41999,42016,42017,42018,42019,42020,42021,42022,42032,42036</WarningsAsErrors>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<DefineDebug>false</DefineDebug>
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DocumentationFile>
|
||||||
|
</DocumentationFile>
|
||||||
|
<NoWarn>42353,42354,42355</NoWarn>
|
||||||
|
<WarningsAsErrors>41999,42016,42017,42018,42019,42020,42021,42022,42032,42036</WarningsAsErrors>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<OptionExplicit>On</OptionExplicit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<OptionCompare>Binary</OptionCompare>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<OptionStrict>On</OptionStrict>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<OptionInfer>On</OptionInfer>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Import Include="Microsoft.VisualBasic" />
|
||||||
|
<Import Include="System" />
|
||||||
|
<Import Include="System.Collections" />
|
||||||
|
<Import Include="System.Collections.Generic" />
|
||||||
|
<Import Include="System.Data" />
|
||||||
|
<Import Include="System.Diagnostics" />
|
||||||
|
<Import Include="System.Linq" />
|
||||||
|
<Import Include="System.Xml.Linq" />
|
||||||
|
<Import Include="System.Threading.Tasks" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="My Project\AssemblyInfo.vb" />
|
||||||
|
<Compile Include="My Project\Application.Designer.vb">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Application.myapp</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="My Project\Resources.Designer.vb">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="My Project\Settings.Designer.vb">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Settings.settings</DependentUpon>
|
||||||
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="TaskDialog.vb" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="My Project\Resources.resx">
|
||||||
|
<Generator>VbMyResourcesResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resources.Designer.vb</LastGenOutput>
|
||||||
|
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="My Project\Application.myapp">
|
||||||
|
<Generator>MyApplicationCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Application.Designer.vb</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
<None Include="My Project\Settings.settings">
|
||||||
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
|
<CustomToolNamespace>My</CustomToolNamespace>
|
||||||
|
<LastGenOutput>Settings.Designer.vb</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
|
||||||
|
</Project>
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
"C:\Program Files (x86)\Inno Setup 6\ISCC.exe" setup\mpvnet.iss
|
|
||||||
pause
|
|
||||||
18
mpv.net.sln
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 15.0.26730.8
|
VisualStudioVersion = 16.0.28729.10
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mpv.net", "mpv.net\mpv.net.csproj", "{1751F378-8EDF-4B62-BE6D-304C7C287089}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mpv.net", "mpv.net\mpv.net.csproj", "{1751F378-8EDF-4B62-BE6D-304C7C287089}"
|
||||||
EndProject
|
EndProject
|
||||||
@@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RatingAddon", "RatingAddon\
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CSScriptAddon", "CSScriptAddon\CSScriptAddon.vbproj", "{71808A87-8B1C-4DF8-957C-D79C3B164CCA}"
|
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CSScriptAddon", "CSScriptAddon\CSScriptAddon.vbproj", "{71808A87-8B1C-4DF8-957C-D79C3B164CCA}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "VBNET", "VBNET\VBNET.vbproj", "{A1D11294-05BF-4D77-B008-AECF1AA93C9F}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -55,6 +57,18 @@ Global
|
|||||||
{71808A87-8B1C-4DF8-957C-D79C3B164CCA}.Release|x64.Build.0 = Release|Any CPU
|
{71808A87-8B1C-4DF8-957C-D79C3B164CCA}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{71808A87-8B1C-4DF8-957C-D79C3B164CCA}.Release|x86.ActiveCfg = Release|Any CPU
|
{71808A87-8B1C-4DF8-957C-D79C3B164CCA}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{71808A87-8B1C-4DF8-957C-D79C3B164CCA}.Release|x86.Build.0 = Release|Any CPU
|
{71808A87-8B1C-4DF8-957C-D79C3B164CCA}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ using System.ComponentModel.Composition.Hosting;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
using VBNET;
|
||||||
|
|
||||||
namespace mpvnet
|
namespace mpvnet
|
||||||
{
|
{
|
||||||
public class Addon
|
public class Addon
|
||||||
@@ -12,7 +14,7 @@ namespace mpvnet
|
|||||||
[ImportMany]
|
[ImportMany]
|
||||||
public IEnumerable<IAddon> Addons = null;
|
public IEnumerable<IAddon> Addons = null;
|
||||||
|
|
||||||
private readonly CompositionContainer CompositionContainer;
|
readonly CompositionContainer CompositionContainer;
|
||||||
|
|
||||||
public Addon()
|
public Addon()
|
||||||
{
|
{
|
||||||
@@ -26,7 +28,7 @@ namespace mpvnet
|
|||||||
foreach (string i in Directory.GetDirectories(dir))
|
foreach (string i in Directory.GetDirectories(dir))
|
||||||
catalog.Catalogs.Add(new DirectoryCatalog(i, "*Addon.dll"));
|
catalog.Catalogs.Add(new DirectoryCatalog(i, "*Addon.dll"));
|
||||||
|
|
||||||
dir = mp.mpvConfFolderPath + "\\Addons";
|
dir = mp.MpvConfFolderPath + "\\Addons";
|
||||||
|
|
||||||
if (Directory.Exists(dir))
|
if (Directory.Exists(dir))
|
||||||
foreach (string i in Directory.GetDirectories(dir))
|
foreach (string i in Directory.GetDirectories(dir))
|
||||||
@@ -38,9 +40,9 @@ namespace mpvnet
|
|||||||
CompositionContainer.ComposeParts(this);
|
CompositionContainer.ComposeParts(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
MainForm.Instance.ShowMsgBox(e.ToString(), MessageBoxIcon.Error);
|
Msg.ShowException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
using VBNET;
|
||||||
|
|
||||||
namespace mpvnet
|
namespace mpvnet
|
||||||
{
|
{
|
||||||
public class Command
|
public class Command
|
||||||
@@ -12,7 +15,7 @@ namespace mpvnet
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public Action<string[]> Action { get; set; }
|
public Action<string[]> Action { get; set; }
|
||||||
|
|
||||||
private static List<Command> commands;
|
static List<Command> commands;
|
||||||
|
|
||||||
public static List<Command> Commands
|
public static List<Command> Commands
|
||||||
{
|
{
|
||||||
@@ -53,9 +56,9 @@ namespace mpvnet
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void open_config_folder(string[] args)
|
public static void open_conf_folder(string[] args)
|
||||||
{
|
{
|
||||||
Process.Start(mp.mpvConfFolderPath);
|
Process.Start(mp.MpvConfFolderPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void show_input_editor(string[] args)
|
public static void show_input_editor(string[] args)
|
||||||
@@ -70,50 +73,25 @@ namespace mpvnet
|
|||||||
|
|
||||||
public static void show_history(string[] args)
|
public static void show_history(string[] args)
|
||||||
{
|
{
|
||||||
var fp = mp.mpvConfFolderPath + "history.txt";
|
var fp = mp.MpvConfFolderPath + "history.txt";
|
||||||
|
|
||||||
if (File.Exists(fp))
|
if (File.Exists(fp))
|
||||||
Process.Start(fp);
|
Process.Start(fp);
|
||||||
else
|
else
|
||||||
if (MainForm.Instance.ShowMsgBox("Create history.txt file in config folder?\n\nmpv.net will write the date, time and filename of opened files to it.", MessageBoxIcon.Question) == DialogResult.OK)
|
if (Msg.ShowQuestion("Create history.txt file in config folder?",
|
||||||
|
"mpv.net will write the date, time and filename of opened files to it.") == MsgResult.OK)
|
||||||
File.WriteAllText(fp, "");
|
File.WriteAllText(fp, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void shell_execute(string[] args)
|
public static void shell_execute(string[] args) => Process.Start(args[0]);
|
||||||
{
|
|
||||||
Process.Start(args[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void set_setting(string[] args)
|
|
||||||
{
|
|
||||||
bool changed = false;
|
|
||||||
var lines = File.ReadAllLines(mp.mpvConfPath);
|
|
||||||
|
|
||||||
for (int i = 0; i < lines.Length; i++)
|
|
||||||
{
|
|
||||||
if (lines[i].Contains("=") &&
|
|
||||||
lines[i].Substring(0, lines[i].IndexOf("=")).Trim("# ".ToCharArray()) == args[0])
|
|
||||||
{
|
|
||||||
lines[i] = args[0] + " = " + args[1];
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changed)
|
|
||||||
File.WriteAllText(mp.mpvConfPath, String.Join(Environment.NewLine, lines));
|
|
||||||
else
|
|
||||||
File.WriteAllText(mp.mpvConfPath, File.ReadAllText(mp.mpvConfPath) + Environment.NewLine + args[0] + " = " + args[1]);
|
|
||||||
|
|
||||||
MainForm.Instance.ShowMsgBox("Please restart mpv.net", MessageBoxIcon.Information);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void show_info(string[] args)
|
public static void show_info(string[] args)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var fileInfo = new FileInfo(mp.get_property_string("path"));
|
FileInfo fileInfo = new FileInfo(mp.get_property_string("path"));
|
||||||
|
|
||||||
using (var mediaInfo = new MediaInfo(fileInfo.FullName))
|
using (MediaInfo mediaInfo = new MediaInfo(fileInfo.FullName))
|
||||||
{
|
{
|
||||||
string width = mediaInfo.GetInfo(MediaInfoStreamKind.Video, "Width");
|
string width = mediaInfo.GetInfo(MediaInfoStreamKind.Video, "Width");
|
||||||
|
|
||||||
@@ -129,11 +107,11 @@ namespace mpvnet
|
|||||||
string text = "";
|
string text = "";
|
||||||
|
|
||||||
if (performer != "") text += "Artist: " + performer + "\n";
|
if (performer != "") text += "Artist: " + performer + "\n";
|
||||||
if (title != "") text += "Title: " + title + "\n";
|
if (title != "") text += "Title: " + title + "\n";
|
||||||
if (album != "") text += "Album: " + album + "\n";
|
if (album != "") text += "Album: " + album + "\n";
|
||||||
if (genre != "") text += "Genre: " + genre + "\n";
|
if (genre != "") text += "Genre: " + genre + "\n";
|
||||||
if (date != "") text += "Year: " + date + "\n";
|
if (date != "") text += "Year: " + date + "\n";
|
||||||
if (duration != "") text += "Length: " + duration + "\n";
|
if (duration != "") text += "Length: " + duration + "\n";
|
||||||
|
|
||||||
mp.commandv("show-text", text, "5000");
|
mp.commandv("show-text", text, "5000");
|
||||||
}
|
}
|
||||||
@@ -147,17 +125,19 @@ namespace mpvnet
|
|||||||
if (bitrate == "")
|
if (bitrate == "")
|
||||||
bitrate = "0";
|
bitrate = "0";
|
||||||
|
|
||||||
var bitrate2 = Convert.ToDouble(bitrate) / 1000.0 / 1000.0;
|
double bitrate2 = Convert.ToDouble(bitrate) / 1000.0 / 1000.0;
|
||||||
var videoCodec = mp.get_property_string("video-format").ToUpper();
|
string videoCodec = mp.get_property_string("video-format").ToUpper();
|
||||||
var filename = fileInfo.Name;
|
string filename = fileInfo.Name;
|
||||||
|
|
||||||
var text =
|
string text = filename + "\n" +
|
||||||
FormatTime(position.TotalMinutes) + ":" +
|
FormatTime(position.TotalMinutes) + ":" +
|
||||||
FormatTime(position.Seconds) + " / " +
|
FormatTime(position.Seconds) + " / " +
|
||||||
FormatTime(duration.TotalMinutes) + ":" +
|
FormatTime(duration.TotalMinutes) + ":" +
|
||||||
FormatTime(duration.Seconds) + "\n" +
|
FormatTime(duration.Seconds) + "\n" +
|
||||||
Convert.ToInt32(fileInfo.Length / 1024 / 1024).ToString() +
|
$"{width} x {height}\n" +
|
||||||
$" MB - {width} x {height}\n{videoCodec} - {bitrate2.ToString("f1")} Mb/s" + "\n" + filename;
|
$"{bitrate2.ToString("f1")} Mb/s\n" +
|
||||||
|
Convert.ToInt32(fileInfo.Length / 1024 / 1024).ToString() + " MB\n" +
|
||||||
|
$"{videoCodec}\n";
|
||||||
|
|
||||||
mp.commandv("show-text", text, "5000");
|
mp.commandv("show-text", text, "5000");
|
||||||
}
|
}
|
||||||
@@ -187,5 +167,52 @@ namespace mpvnet
|
|||||||
mp.LoadURL(command);
|
mp.LoadURL(command);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void load_sub(string[] args)
|
||||||
|
{
|
||||||
|
MainForm.Instance.BeginInvoke(new Action(() => {
|
||||||
|
using (var d = new OpenFileDialog())
|
||||||
|
{
|
||||||
|
d.InitialDirectory = Path.GetDirectoryName(mp.get_property_string("path", false));
|
||||||
|
d.Multiselect = true;
|
||||||
|
|
||||||
|
if (d.ShowDialog() == DialogResult.OK)
|
||||||
|
foreach (string i in d.FileNames)
|
||||||
|
mp.commandv("sub-add", i);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void load_audio(string[] args)
|
||||||
|
{
|
||||||
|
MainForm.Instance.BeginInvoke(new Action(() => {
|
||||||
|
using (var d = new OpenFileDialog())
|
||||||
|
{
|
||||||
|
d.InitialDirectory = Path.GetDirectoryName(mp.get_property_string("path", false));
|
||||||
|
d.Multiselect = true;
|
||||||
|
|
||||||
|
if (d.ShowDialog() == DialogResult.OK)
|
||||||
|
foreach (string i in d.FileNames)
|
||||||
|
mp.commandv("audio-add", i);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void cycle_audio(string[] args)
|
||||||
|
{
|
||||||
|
string filePath = mp.get_property_string("path", false);
|
||||||
|
if (!File.Exists(filePath)) return;
|
||||||
|
|
||||||
|
using (MediaInfo mi = new MediaInfo(filePath))
|
||||||
|
{
|
||||||
|
MediaTrack[] audTracks = mp.MediaTracks.Where(track => track.Type == "a").ToArray();
|
||||||
|
if (audTracks.Length < 2) return;
|
||||||
|
int aid = mp.get_property_int("aid");
|
||||||
|
aid += 1;
|
||||||
|
if (aid > audTracks.Length) aid = 1;
|
||||||
|
mp.commandv("set", "aid", aid.ToString());
|
||||||
|
mp.commandv("show-text", audTracks[aid - 1].Text.Substring(3), "5000");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
2
mpv.net/MainForm.Designer.cs
generated
@@ -45,7 +45,7 @@
|
|||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(288F, 288F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(288F, 288F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||||
this.BackColor = System.Drawing.Color.Black;
|
this.BackColor = System.Drawing.Color.Black;
|
||||||
this.ClientSize = new System.Drawing.Size(1012, 615);
|
this.ClientSize = new System.Drawing.Size(606, 368);
|
||||||
this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
|||||||
@@ -6,19 +6,35 @@ using System.Threading;
|
|||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
|
using VBNET;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
namespace mpvnet
|
namespace mpvnet
|
||||||
{
|
{
|
||||||
public partial class MainForm : Form
|
public partial class MainForm : Form
|
||||||
{
|
{
|
||||||
public static MainForm Instance { get; set; }
|
public static MainForm Instance { get; set; }
|
||||||
public static IntPtr Hwnd;
|
public static IntPtr Hwnd { get; set; }
|
||||||
|
|
||||||
private Point LastCursorPosChanged;
|
public new ContextMenuStripEx ContextMenu;
|
||||||
private int LastCursorChangedTickCount;
|
|
||||||
private bool IgnoreDpiChanged = true;
|
|
||||||
|
|
||||||
public ContextMenuStripEx CMS;
|
MenuItemEx TracksMenu;
|
||||||
|
MenuItemEx ChaptersMenu;
|
||||||
|
|
||||||
|
Point LastCursorPosChanged;
|
||||||
|
int LastCursorChangedTickCount;
|
||||||
|
bool IgnoreDpiChanged = true;
|
||||||
|
|
||||||
|
float MpvAutofit = 0.50f;
|
||||||
|
bool MpvFullscreen;
|
||||||
|
int MpvScreen = -1;
|
||||||
|
string MpvNetDarkMode = "system";
|
||||||
|
string MpvSid = "";
|
||||||
|
string MpvAid = "";
|
||||||
|
string MpvVid = "";
|
||||||
|
int MpvEdition;
|
||||||
|
|
||||||
public MainForm()
|
public MainForm()
|
||||||
{
|
{
|
||||||
@@ -26,31 +42,110 @@ namespace mpvnet
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||||
Application.ThreadException += Application_ThreadException;
|
Application.ThreadException += Application_ThreadException;
|
||||||
|
Msg.SupportURL = "https://github.com/stax76/mpv.net#support";
|
||||||
|
|
||||||
Instance = this;
|
Instance = this;
|
||||||
Hwnd = Handle;
|
Hwnd = Handle;
|
||||||
|
MinimumSize = new Size(FontHeight * 16, FontHeight * 9);
|
||||||
Text += " " + Application.ProductVersion;
|
Text += " " + Application.ProductVersion;
|
||||||
|
|
||||||
if (mp.mpvConf.ContainsKey("screen"))
|
foreach (var i in mp.mpvConf)
|
||||||
SetScreen(Convert.ToInt32(mp.mpvConf["screen"]));
|
ProcessMpvProperty(i.Key, i.Value);
|
||||||
else
|
|
||||||
SetScreen(Screen.PrimaryScreen);
|
|
||||||
|
|
||||||
ChangeFullscreen((mp.mpvConf.ContainsKey("fullscreen") && mp.mpvConf["fullscreen"] == "yes") ||
|
foreach (var i in mp.mpvNetConf)
|
||||||
(mp.mpvConf.ContainsKey("fs") && mp.mpvConf["fs"] == "yes"));
|
ProcessMpvNetProperty(i.Key, i.Value);
|
||||||
|
|
||||||
ProcessCommandLineEarly();
|
ProcessCommandLineEarly();
|
||||||
|
|
||||||
|
if (MpvScreen == -1) MpvScreen = Array.IndexOf(Screen.AllScreens, Screen.PrimaryScreen);
|
||||||
|
SetScreen(MpvScreen);
|
||||||
|
|
||||||
|
ChangeFullscreen(MpvFullscreen);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
MainForm.Instance.ShowMsgBox(e.ToString(), MessageBoxIcon.Error);
|
Msg.ShowException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextMenu_Opening(object sender, CancelEventArgs e)
|
||||||
|
{
|
||||||
|
lock (mp.MediaTracks)
|
||||||
|
{
|
||||||
|
if (TracksMenu != null)
|
||||||
|
TracksMenu.DropDownItems.Clear();
|
||||||
|
|
||||||
|
MediaTrack[] audTracks = mp.MediaTracks.Where(track => track.Type == "a").ToArray();
|
||||||
|
MediaTrack[] subTracks = mp.MediaTracks.Where(track => track.Type == "s").ToArray();
|
||||||
|
MediaTrack[] vidTracks = mp.MediaTracks.Where(track => track.Type == "v").ToArray();
|
||||||
|
MediaTrack[] ediTracks = mp.MediaTracks.Where(track => track.Type == "e").ToArray();
|
||||||
|
|
||||||
|
foreach (MediaTrack track in vidTracks)
|
||||||
|
{
|
||||||
|
MenuItemEx mi = ContextMenu.Add("Track > " + track.Text);
|
||||||
|
mi.Action = () => { mp.commandv("set", "vid", track.ID.ToString()); };
|
||||||
|
mi.Checked = MpvVid == track.ID.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vidTracks.Length > 0)
|
||||||
|
ContextMenu.Add("Track > -");
|
||||||
|
|
||||||
|
foreach (MediaTrack track in audTracks)
|
||||||
|
{
|
||||||
|
MenuItemEx mi = ContextMenu.Add("Track > " + track.Text);
|
||||||
|
mi.Action = () => { mp.commandv("set", "aid", track.ID.ToString()); };
|
||||||
|
mi.Checked = MpvAid == track.ID.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subTracks.Length > 0)
|
||||||
|
ContextMenu.Add("Track > -");
|
||||||
|
|
||||||
|
foreach (MediaTrack track in subTracks)
|
||||||
|
{
|
||||||
|
MenuItemEx mi = ContextMenu.Add("Track > " + track.Text);
|
||||||
|
mi.Action = () => { mp.commandv("set", "sid", track.ID.ToString()); };
|
||||||
|
mi.Checked = MpvSid == track.ID.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subTracks.Length > 0)
|
||||||
|
{
|
||||||
|
MenuItemEx mi = ContextMenu.Add("Track > S: No subtitles");
|
||||||
|
mi.Action = () => { mp.commandv("set", "sid", "no"); };
|
||||||
|
mi.Checked = MpvSid == "no";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ediTracks.Length > 0)
|
||||||
|
ContextMenu.Add("Track > -");
|
||||||
|
|
||||||
|
foreach (MediaTrack track in ediTracks)
|
||||||
|
{
|
||||||
|
MenuItemEx mi = ContextMenu.Add("Track > " + track.Text);
|
||||||
|
mi.Action = () => { mp.commandv("set", "edition", track.ID.ToString()); };
|
||||||
|
mi.Checked = MpvEdition == track.ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (mp.Chapters)
|
||||||
|
{
|
||||||
|
if (ChaptersMenu != null)
|
||||||
|
ChaptersMenu.DropDownItems.Clear();
|
||||||
|
|
||||||
|
foreach (var i in mp.Chapters)
|
||||||
|
{
|
||||||
|
MenuItemEx mi = ContextMenu.Add("Navigate > Chapters > " + i.Key);
|
||||||
|
mi.ShortcutKeyDisplayString = TimeSpan.FromSeconds(i.Value).ToString().Substring(0, 8) + " ";
|
||||||
|
mi.Action = () => { mp.commandv("seek", i.Value.ToString(CultureInfo.InvariantCulture), "absolute"); };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SetScreen(int targetIndex)
|
protected void SetScreen(int targetIndex)
|
||||||
{
|
{
|
||||||
Screen[] screens = Screen.AllScreens;
|
Screen[] screens = Screen.AllScreens;
|
||||||
if (targetIndex < 0 || targetIndex > screens.Length - 1) return;
|
if (targetIndex < 0) targetIndex = 0;
|
||||||
|
if (targetIndex > screens.Length - 1) targetIndex = screens.Length - 1;
|
||||||
SetScreen(screens[Array.IndexOf(screens, screens[targetIndex])]);
|
SetScreen(screens[Array.IndexOf(screens, screens[targetIndex])]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +161,7 @@ namespace mpvnet
|
|||||||
{
|
{
|
||||||
if (IsFullscreen || mp.VideoSize.Width == 0) return;
|
if (IsFullscreen || mp.VideoSize.Width == 0) return;
|
||||||
Screen screen = Screen.FromControl(this);
|
Screen screen = Screen.FromControl(this);
|
||||||
int height = Convert.ToInt32(screen.Bounds.Height * 0.6);
|
int height = Convert.ToInt32(screen.Bounds.Height * MpvAutofit);
|
||||||
int width = Convert.ToInt32(height * mp.VideoSize.Width / (double)mp.VideoSize.Height);
|
int width = Convert.ToInt32(height * mp.VideoSize.Width / (double)mp.VideoSize.Height);
|
||||||
Point middlePos = new Point(Left + Width / 2, Top + Height / 2);
|
Point middlePos = new Point(Left + Width / 2, Top + Height / 2);
|
||||||
var rect = new Native.RECT(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height));
|
var rect = new Native.RECT(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height));
|
||||||
@@ -81,6 +176,7 @@ namespace mpvnet
|
|||||||
if (IsFullscreen || mp.VideoSize.Width == 0) return;
|
if (IsFullscreen || mp.VideoSize.Width == 0) return;
|
||||||
Screen screen = Screen.FromControl(this);
|
Screen screen = Screen.FromControl(this);
|
||||||
int height = ClientSize.Height;
|
int height = ClientSize.Height;
|
||||||
|
if (height > screen.Bounds.Height * 0.9) height = Convert.ToInt32(screen.Bounds.Height * MpvAutofit);
|
||||||
int width = Convert.ToInt32(height * mp.VideoSize.Width / (double)mp.VideoSize.Height);
|
int width = Convert.ToInt32(height * mp.VideoSize.Width / (double)mp.VideoSize.Height);
|
||||||
Point middlePos = new Point(Left + Width / 2, Top + Height / 2);
|
Point middlePos = new Point(Left + Width / 2, Top + Height / 2);
|
||||||
var rect = new Native.RECT(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height));
|
var rect = new Native.RECT(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height));
|
||||||
@@ -88,15 +184,9 @@ namespace mpvnet
|
|||||||
int left = middlePos.X - rect.Width / 2;
|
int left = middlePos.X - rect.Width / 2;
|
||||||
int top = middlePos.Y - rect.Height / 2;
|
int top = middlePos.Y - rect.Height / 2;
|
||||||
Screen[] screens = Screen.AllScreens;
|
Screen[] screens = Screen.AllScreens;
|
||||||
|
if (left < screens[0].Bounds.Left) left = screens[0].Bounds.Left;
|
||||||
if (left < screens[0].Bounds.Left)
|
|
||||||
left = screens[0].Bounds.Left;
|
|
||||||
|
|
||||||
int maxLeft = screens[0].Bounds.Left + screens.Select((sc) => sc.Bounds.Width).Sum() - rect.Width - SystemInformation.CaptionHeight;
|
int maxLeft = screens[0].Bounds.Left + screens.Select((sc) => sc.Bounds.Width).Sum() - rect.Width - SystemInformation.CaptionHeight;
|
||||||
|
if (left > maxLeft) left = maxLeft;
|
||||||
if (left > maxLeft)
|
|
||||||
left = maxLeft;
|
|
||||||
|
|
||||||
Native.SetWindowPos(Handle, IntPtr.Zero /* HWND_TOP */, left, top, rect.Width, rect.Height, 4 /* SWP_NOZORDER */);
|
Native.SetWindowPos(Handle, IntPtr.Zero /* HWND_TOP */, left, top, rect.Width, rect.Height, 4 /* SWP_NOZORDER */);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,11 +202,8 @@ namespace mpvnet
|
|||||||
{
|
{
|
||||||
string left = i.Substring(2, i.IndexOf("=") - 2);
|
string left = i.Substring(2, i.IndexOf("=") - 2);
|
||||||
string right = i.Substring(left.Length + 3);
|
string right = i.Substring(left.Length + 3);
|
||||||
|
ProcessMpvProperty(left, right);
|
||||||
if (left == "screen")
|
ProcessMpvNetProperty(left, right);
|
||||||
SetScreen(Convert.ToInt32(right));
|
|
||||||
|
|
||||||
ChangeFullscreen((left == "fs" || left == "fullscreen") && right == "yes");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -126,7 +213,7 @@ namespace mpvnet
|
|||||||
{
|
{
|
||||||
case "fs":
|
case "fs":
|
||||||
case "fullscreen":
|
case "fullscreen":
|
||||||
ChangeFullscreen(true);
|
MpvFullscreen = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,86 +221,133 @@ namespace mpvnet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProcessMpvProperty(string name, string value)
|
||||||
|
{
|
||||||
|
switch (name)
|
||||||
|
{
|
||||||
|
case "autofit":
|
||||||
|
if (value.Length == 3 && value.EndsWith("%"))
|
||||||
|
if (int.TryParse(value.Substring(0, 2), out int result))
|
||||||
|
MpvAutofit = result / 100f;
|
||||||
|
break;
|
||||||
|
case "fs":
|
||||||
|
case "fullscreen":
|
||||||
|
MpvFullscreen = value == "yes";
|
||||||
|
break;
|
||||||
|
case "screen":
|
||||||
|
MpvScreen = Convert.ToInt32(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessMpvNetProperty(string name, string value)
|
||||||
|
{
|
||||||
|
switch (name)
|
||||||
|
{
|
||||||
|
case "dark-mode":
|
||||||
|
MpvNetDarkMode = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void BuildMenu()
|
public void BuildMenu()
|
||||||
{
|
{
|
||||||
foreach (var i in File.ReadAllText(mp.InputConfPath).Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
|
string content = File.ReadAllText(mp.InputConfPath);
|
||||||
|
List<string> lines = null;
|
||||||
|
Dictionary<string, string> commandInputDic = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
if (content.Contains("#menu:"))
|
||||||
|
lines = content.Split("\r\n".ToCharArray()).ToList();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lines = Properties.Resources.input_conf.Split("\r\n".ToCharArray()).ToList();
|
||||||
|
|
||||||
|
foreach (string i in content.Split("\r\n".ToCharArray()))
|
||||||
|
{
|
||||||
|
string line = i.Trim();
|
||||||
|
if (line.StartsWith("#") || !line.Contains(" ")) continue;
|
||||||
|
string input = line.Substring(0, line.IndexOf(" ")).Trim();
|
||||||
|
string command = line.Substring(line.IndexOf(" ") + 1).Trim();
|
||||||
|
commandInputDic[command] = input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string i in lines)
|
||||||
{
|
{
|
||||||
if (!i.Contains("#menu:")) continue;
|
if (!i.Contains("#menu:")) continue;
|
||||||
var left = i.Substring(0, i.IndexOf("#menu:")).Trim();
|
string left = i.Substring(0, i.IndexOf("#menu:")).Trim();
|
||||||
if (left.StartsWith("#")) continue;
|
if (left.StartsWith("#")) continue;
|
||||||
var cmd = left.Substring(left.IndexOf(" ") + 1).Trim();
|
string command = left.Substring(left.IndexOf(" ") + 1).Trim();
|
||||||
var menu = i.Substring(i.IndexOf("#menu:") + "#menu:".Length).Trim();
|
string menu = i.Substring(i.IndexOf("#menu:") + "#menu:".Length).Trim();
|
||||||
var key = left.Substring(0, left.IndexOf(" "));
|
string input = left.Substring(0, left.IndexOf(" "));
|
||||||
if (key == "_") key = "";
|
if (input == "_") input = "";
|
||||||
if (menu.Contains(";")) key = menu.Substring(0, menu.IndexOf(";")).Trim();
|
if (menu.Contains(";")) input = menu.Substring(0, menu.IndexOf(";")).Trim();
|
||||||
var path = menu.Substring(menu.IndexOf(";") + 1).Trim().Replace("&", "&&");
|
string path = menu.Substring(menu.IndexOf(";") + 1).Trim().Replace("&", "&&");
|
||||||
if (path == "" || cmd == "") continue;
|
if (path == "" || command == "") continue;
|
||||||
|
|
||||||
var menuItem = CMS.Add(path, () => {
|
if (commandInputDic.Count > 0)
|
||||||
try
|
if (commandInputDic.ContainsKey(command))
|
||||||
{
|
input = commandInputDic[command];
|
||||||
mp.command_string(cmd);
|
else
|
||||||
|
input = "";
|
||||||
|
|
||||||
|
MenuItemEx menuItem = ContextMenu.Add(path, () => {
|
||||||
|
try {
|
||||||
|
mp.command_string(command);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception ex) {
|
||||||
{
|
Msg.ShowException(ex);
|
||||||
MainForm.Instance.ShowMsgBox(e.ToString(), MessageBoxIcon.Error);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (menuItem != null)
|
if (menuItem != null)
|
||||||
menuItem.ShortcutKeyDisplayString = key.Replace("_","") + " ";
|
{
|
||||||
|
menuItem.ShortcutKeyDisplayString = input.Replace("_", "") + " ";
|
||||||
|
|
||||||
|
if (TracksMenu == null && menuItem.Text.StartsWith("Track ") &&
|
||||||
|
menuItem.Text.Trim() == "Track")
|
||||||
|
|
||||||
|
TracksMenu = menuItem;
|
||||||
|
|
||||||
|
if (ChaptersMenu == null && menuItem.Text.StartsWith("Chapters ") &&
|
||||||
|
menuItem.Text.Trim() == "Chapters")
|
||||||
|
|
||||||
|
ChaptersMenu = menuItem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CMS_Opened(object sender, EventArgs e)
|
void ContextMenu_Opened(object sender, EventArgs e) => CursorHelp.Show();
|
||||||
|
|
||||||
|
void mp_PlaybackRestart() => BeginInvoke(new Action(() => { Text = Path.GetFileName(mp.get_property_string("path")) + " - mpv.net " + Application.ProductVersion; }));
|
||||||
|
|
||||||
|
void Mp_Idle() => BeginInvoke(new Action(() => { Text = "mpv.net " + Application.ProductVersion; }));
|
||||||
|
|
||||||
|
void CM_Popup(object sender, EventArgs e) => CursorHelp.Show();
|
||||||
|
|
||||||
|
void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
CursorHelp.Show();
|
Msg.ShowException(e.Exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string LastHistory;
|
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||||
|
|
||||||
private void mp_PlaybackRestart()
|
|
||||||
{
|
{
|
||||||
var filename = mp.get_property_string("filename");
|
Msg.ShowError(e.ExceptionObject.ToString());
|
||||||
BeginInvoke(new Action(() => { Text = filename + " - mpv.net " + Application.ProductVersion; }));
|
|
||||||
var historyFilepath = mp.mpvConfFolderPath + "history.txt";
|
|
||||||
|
|
||||||
if (LastHistory != filename && File.Exists(historyFilepath))
|
|
||||||
{
|
|
||||||
File.AppendAllText(historyFilepath, DateTime.Now.ToString() + " " +
|
|
||||||
Path.GetFileNameWithoutExtension(filename) + "\r\n");
|
|
||||||
LastHistory = filename;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Mp_Idle()
|
void mp_VideoSizeChanged()
|
||||||
{
|
|
||||||
BeginInvoke(new Action(() => { Text = "mpv.net " + Application.ProductVersion; }));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CM_Popup(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
CursorHelp.Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
|
|
||||||
{
|
|
||||||
ShowMsgBox(e.Exception.ToString(), MessageBoxIcon.Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mp_VideoSizeChanged()
|
|
||||||
{
|
{
|
||||||
BeginInvoke(new Action(() => SetFormPositionAndSizeKeepHeight()));
|
BeginInvoke(new Action(() => SetFormPositionAndSizeKeepHeight()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mp_Shutdown()
|
void mp_Shutdown()
|
||||||
{
|
{
|
||||||
BeginInvoke(new Action(() => Close()));
|
BeginInvoke(new Action(() => Close()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsFullscreen => WindowState == FormWindowState.Maximized;
|
public bool IsFullscreen => WindowState == FormWindowState.Maximized;
|
||||||
|
|
||||||
void mp_ChangeFullscreen(bool value)
|
void mpPropChangeFullscreen(bool value)
|
||||||
{
|
{
|
||||||
BeginInvoke(new Action(() => ChangeFullscreen(value)));
|
BeginInvoke(new Action(() => ChangeFullscreen(value)));
|
||||||
}
|
}
|
||||||
@@ -288,7 +422,6 @@ namespace mpvnet
|
|||||||
m.Result = new IntPtr(1);
|
m.Result = new IntPtr(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.WndProc(ref m);
|
base.WndProc(ref m);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,12 +434,11 @@ namespace mpvnet
|
|||||||
|
|
||||||
protected override void OnDragDrop(DragEventArgs e)
|
protected override void OnDragDrop(DragEventArgs e)
|
||||||
{
|
{
|
||||||
|
base.OnDragDrop(e);
|
||||||
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
||||||
mp.LoadFiles(e.Data.GetData(DataFormats.FileDrop) as String[]);
|
mp.LoadFiles(e.Data.GetData(DataFormats.FileDrop) as String[]);
|
||||||
if (e.Data.GetDataPresent(DataFormats.Text))
|
if (e.Data.GetDataPresent(DataFormats.Text))
|
||||||
mp.LoadURL(e.Data.GetData(DataFormats.Text).ToString());
|
mp.LoadURL(e.Data.GetData(DataFormats.Text).ToString());
|
||||||
|
|
||||||
base.OnDragDrop(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnMouseDown(MouseEventArgs e)
|
protected override void OnMouseDown(MouseEventArgs e)
|
||||||
@@ -322,11 +454,7 @@ namespace mpvnet
|
|||||||
Native.PostMessage(Handle, 0xA1 /* WM_NCLBUTTONDOWN */, HTCAPTION, IntPtr.Zero);
|
Native.PostMessage(Handle, 0xA1 /* WM_NCLBUTTONDOWN */, HTCAPTION, IntPtr.Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
var sb = Screen.FromControl(this).Bounds;
|
if (Width - e.Location.X < 10 && e.Location.Y < 10)
|
||||||
var p1 = new Point(sb.Width, 0);
|
|
||||||
var p2 = PointToScreen(e.Location);
|
|
||||||
|
|
||||||
if (Math.Abs(p1.X - p2.X) < 10 && Math.Abs(p1.Y - p2.Y) < 10)
|
|
||||||
mp.commandv("quit");
|
mp.commandv("quit");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,12 +467,9 @@ namespace mpvnet
|
|||||||
CursorHelp.Show();
|
CursorHelp.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsMouseInOSC()
|
bool IsMouseInOSC() => PointToClient(Control.MousePosition).Y > ClientSize.Height * 0.9;
|
||||||
{
|
|
||||||
return PointToClient(Control.MousePosition).Y > ClientSize.Height * 0.9;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Timer_Tick(object sender, EventArgs e)
|
void Timer_Tick(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (CursorHelp.IsPosDifferent(LastCursorPosChanged))
|
if (CursorHelp.IsPosDifferent(LastCursorPosChanged))
|
||||||
{
|
{
|
||||||
@@ -353,7 +478,7 @@ namespace mpvnet
|
|||||||
}
|
}
|
||||||
else if (Environment.TickCount - LastCursorChangedTickCount > 1500 &&
|
else if (Environment.TickCount - LastCursorChangedTickCount > 1500 &&
|
||||||
!IsMouseInOSC() && ClientRectangle.Contains(PointToClient(MousePosition)) &&
|
!IsMouseInOSC() && ClientRectangle.Contains(PointToClient(MousePosition)) &&
|
||||||
Form.ActiveForm == this && !CMS.Visible)
|
Form.ActiveForm == this && !ContextMenu.Visible)
|
||||||
{
|
{
|
||||||
CursorHelp.Hide();
|
CursorHelp.Hide();
|
||||||
}
|
}
|
||||||
@@ -371,21 +496,40 @@ namespace mpvnet
|
|||||||
{
|
{
|
||||||
base.OnLoad(e);
|
base.OnLoad(e);
|
||||||
mp.Init();
|
mp.Init();
|
||||||
mp.observe_property_bool("fullscreen", mp_ChangeFullscreen);
|
mp.observe_property_bool("fullscreen", mpPropChangeFullscreen);
|
||||||
|
mp.observe_property_bool("ontop", mpPropChangeOnTop);
|
||||||
|
mp.observe_property_string("sid", mpPropChangeSid);
|
||||||
|
mp.observe_property_string("aid", mpPropChangeAid);
|
||||||
|
mp.observe_property_string("vid", mpPropChangeVid);
|
||||||
|
mp.observe_property_int("edition", mpPropChangeEdition);
|
||||||
mp.Shutdown += mp_Shutdown;
|
mp.Shutdown += mp_Shutdown;
|
||||||
mp.VideoSizeChanged += mp_VideoSizeChanged;
|
mp.VideoSizeChanged += mp_VideoSizeChanged;
|
||||||
mp.PlaybackRestart += mp_PlaybackRestart;
|
mp.PlaybackRestart += mp_PlaybackRestart;
|
||||||
mp.Idle += Mp_Idle;
|
mp.Idle += Mp_Idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mpPropChangeOnTop(bool value) => BeginInvoke(new Action(() => TopMost = value));
|
||||||
|
|
||||||
|
void mpPropChangeAid(string value) => MpvAid = value;
|
||||||
|
|
||||||
|
void mpPropChangeSid(string value) => MpvSid = value;
|
||||||
|
|
||||||
|
void mpPropChangeVid(string value) => MpvVid = value;
|
||||||
|
|
||||||
|
void mpPropChangeEdition(int value) => MpvEdition = value;
|
||||||
|
|
||||||
protected override void OnShown(EventArgs e)
|
protected override void OnShown(EventArgs e)
|
||||||
{
|
{
|
||||||
base.OnShown(e);
|
base.OnShown(e);
|
||||||
CMS = new ContextMenuStripEx(components);
|
if ((MpvNetDarkMode == "system" && Misc.IsDarkTheme) || MpvNetDarkMode == "always")
|
||||||
CMS.Opened += CMS_Opened;
|
ToolStripRendererEx.ColorTheme = Color.Black;
|
||||||
ContextMenuStrip = CMS;
|
ContextMenu = new ContextMenuStripEx(components);
|
||||||
|
ContextMenu.Opened += ContextMenu_Opened;
|
||||||
|
ContextMenu.Opening += ContextMenu_Opening;
|
||||||
BuildMenu();
|
BuildMenu();
|
||||||
|
ContextMenuStrip = ContextMenu;
|
||||||
IgnoreDpiChanged = false;
|
IgnoreDpiChanged = false;
|
||||||
|
CheckYouTube();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnFormClosed(FormClosedEventArgs e)
|
protected override void OnFormClosed(FormClosedEventArgs e)
|
||||||
@@ -400,5 +544,24 @@ namespace mpvnet
|
|||||||
base.OnLostFocus(e);
|
base.OnLostFocus(e);
|
||||||
CursorHelp.Show();
|
CursorHelp.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnActivated(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnActivated(e);
|
||||||
|
CheckYouTube();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckYouTube()
|
||||||
|
{
|
||||||
|
string clipboard = Clipboard.GetText();
|
||||||
|
|
||||||
|
if (clipboard.StartsWith("https://www.youtube.com/watch?") && RegistryHelp.GetValue("HKCU\\Software\\" + Application.ProductName, "LastYouTubeURL") != clipboard && Visible)
|
||||||
|
{
|
||||||
|
RegistryHelp.SetValue("HKCU\\Software\\" + Application.ProductName, "LastYouTubeURL", clipboard);
|
||||||
|
|
||||||
|
if (Msg.ShowQuestion("Play YouTube URL?") == MsgResult.OK)
|
||||||
|
mp.LoadURL(clipboard);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,8 +3,8 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
public class MediaInfo : IDisposable
|
public class MediaInfo : IDisposable
|
||||||
{
|
{
|
||||||
private IntPtr Handle;
|
IntPtr Handle;
|
||||||
private static bool Loaded;
|
static bool Loaded;
|
||||||
|
|
||||||
public MediaInfo(string sourcepath)
|
public MediaInfo(string sourcepath)
|
||||||
{
|
{
|
||||||
@@ -25,7 +25,24 @@ public class MediaInfo : IDisposable
|
|||||||
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, streamKind, 0, parameter, MediaInfoInfoKind.Text, MediaInfoInfoKind.Name));
|
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, streamKind, 0, parameter, MediaInfoInfoKind.Text, MediaInfoInfoKind.Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool Disposed;
|
public int GetCount(MediaInfoStreamKind streamKind) => MediaInfo_Count_Get(Handle, streamKind, -1);
|
||||||
|
|
||||||
|
public string GetVideo(int streamNumber, string parameter)
|
||||||
|
{
|
||||||
|
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, MediaInfoStreamKind.Video, streamNumber, parameter, MediaInfoInfoKind.Text, MediaInfoInfoKind.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetAudio(int streamNumber, string parameter)
|
||||||
|
{
|
||||||
|
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, MediaInfoStreamKind.Audio, streamNumber, parameter, MediaInfoInfoKind.Text, MediaInfoInfoKind.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetText(int streamNumber, string parameter)
|
||||||
|
{
|
||||||
|
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, MediaInfoStreamKind.Text, streamNumber, parameter, MediaInfoInfoKind.Text, MediaInfoInfoKind.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Disposed;
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
@@ -37,28 +54,35 @@ public class MediaInfo : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~MediaInfo()
|
~MediaInfo() { Dispose(); }
|
||||||
{
|
|
||||||
Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||||
private static extern IntPtr LoadLibrary(string path);
|
static extern IntPtr LoadLibrary(string path);
|
||||||
|
|
||||||
[DllImport("MediaInfo.dll")]
|
[DllImport("MediaInfo.dll")]
|
||||||
private static extern IntPtr MediaInfo_New();
|
static extern IntPtr MediaInfo_New();
|
||||||
|
|
||||||
[DllImport("MediaInfo.dll")]
|
[DllImport("MediaInfo.dll")]
|
||||||
private static extern void MediaInfo_Delete(IntPtr Handle);
|
static extern void MediaInfo_Delete(IntPtr handle);
|
||||||
|
|
||||||
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
|
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
|
||||||
private static extern int MediaInfo_Open(IntPtr Handle, string FileName);
|
static extern int MediaInfo_Open(IntPtr handle, string fileName);
|
||||||
|
|
||||||
[DllImport("MediaInfo.dll")]
|
[DllImport("MediaInfo.dll")]
|
||||||
private static extern int MediaInfo_Close(IntPtr Handle);
|
static extern int MediaInfo_Close(IntPtr handle);
|
||||||
|
|
||||||
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
|
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
|
||||||
private static extern IntPtr MediaInfo_Get(IntPtr Handle, MediaInfoStreamKind StreamKind, int StreamNumber, string Parameter, MediaInfoInfoKind KindOfInfo, MediaInfoInfoKind KindOfSearch);
|
static extern IntPtr MediaInfo_Get(IntPtr handle,
|
||||||
|
MediaInfoStreamKind streamKind,
|
||||||
|
int streamNumber,
|
||||||
|
string parameter,
|
||||||
|
MediaInfoInfoKind kindOfInfo,
|
||||||
|
MediaInfoInfoKind kindOfSearch);
|
||||||
|
|
||||||
|
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
|
||||||
|
static extern int MediaInfo_Count_Get(IntPtr handle,
|
||||||
|
MediaInfoStreamKind streamKind,
|
||||||
|
int streamNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum MediaInfoStreamKind
|
public enum MediaInfoStreamKind
|
||||||
@@ -67,8 +91,10 @@ public enum MediaInfoStreamKind
|
|||||||
Video,
|
Video,
|
||||||
Audio,
|
Audio,
|
||||||
Text,
|
Text,
|
||||||
Chapters,
|
Other,
|
||||||
Image
|
Image,
|
||||||
|
Menu,
|
||||||
|
Max,
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum MediaInfoInfoKind
|
public enum MediaInfoInfoKind
|
||||||
|
|||||||
428
mpv.net/Menu.cs
@@ -23,110 +23,23 @@ public class ContextMenuStripEx : ContextMenuStrip
|
|||||||
Renderer = new ToolStripRendererEx();
|
Renderer = new ToolStripRendererEx();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionMenuItem Add(string path)
|
public MenuItemEx Add(string path)
|
||||||
{
|
{
|
||||||
return Add(path, null);
|
return Add(path, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionMenuItem Add(string path, Action action)
|
public MenuItemEx Add(string path, Action action, bool enabled = true)
|
||||||
{
|
{
|
||||||
return Add(path, action, true);
|
MenuItemEx ret = MenuItemEx.Add(Items, path, action);
|
||||||
}
|
if (ret == null) return null;
|
||||||
|
|
||||||
public ActionMenuItem Add(string path, Action action, bool enabled)
|
|
||||||
{
|
|
||||||
var ret = ActionMenuItem.Add(Items, path, action);
|
|
||||||
if (ret == null)
|
|
||||||
return null;
|
|
||||||
ret.Enabled = enabled;
|
ret.Enabled = enabled;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionMenuItem Add(string path, Action action, Func<bool> enabledFunc)
|
|
||||||
{
|
|
||||||
var ret = ActionMenuItem.Add(Items, path, action);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ActionMenuItem : MenuItemEx
|
|
||||||
{
|
|
||||||
private Action Action;
|
|
||||||
|
|
||||||
public ActionMenuItem()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionMenuItem(string text, Action action)
|
|
||||||
{
|
|
||||||
this.Text = text;
|
|
||||||
this.Action = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnClick(EventArgs e)
|
|
||||||
{
|
|
||||||
Application.DoEvents();
|
|
||||||
if (Action != null)
|
|
||||||
Action();
|
|
||||||
base.OnClick(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ActionMenuItem Add<T>(ToolStripItemCollection items, string path, Action<T> action, T value)
|
|
||||||
{
|
|
||||||
return Add(items, path, () => action(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ActionMenuItem Add(ToolStripItemCollection items, string path, Action action)
|
|
||||||
{
|
|
||||||
var a = path.Split(new[] { " > ", " | " }, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
var l = items;
|
|
||||||
|
|
||||||
for (var x = 0; x <= a.Length - 1; x++)
|
|
||||||
{
|
|
||||||
var found = false;
|
|
||||||
|
|
||||||
foreach (var i in l.OfType<ToolStripMenuItem>())
|
|
||||||
{
|
|
||||||
if (x < a.Length - 1)
|
|
||||||
{
|
|
||||||
if (i.Text == a[x] + " ")
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
l = i.DropDownItems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
if (x == a.Length - 1)
|
|
||||||
{
|
|
||||||
if (a[x] == "-")
|
|
||||||
l.Add(new ToolStripSeparator());
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ActionMenuItem item = new ActionMenuItem(a[x] + " ", action);
|
|
||||||
l.Add(item);
|
|
||||||
l = item.DropDownItems;
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ActionMenuItem item = new ActionMenuItem();
|
|
||||||
item.Text = a[x] + " ";
|
|
||||||
l.Add(item);
|
|
||||||
l = item.DropDownItems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MenuItemEx : ToolStripMenuItem
|
public class MenuItemEx : ToolStripMenuItem
|
||||||
{
|
{
|
||||||
public static bool UseTooltips { get; set; }
|
public Action Action { get; set; }
|
||||||
|
|
||||||
public MenuItemEx()
|
public MenuItemEx()
|
||||||
{
|
{
|
||||||
@@ -136,20 +49,81 @@ public class MenuItemEx : ToolStripMenuItem
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MenuItemEx(string text, Action action) : base(text)
|
||||||
|
{
|
||||||
|
Action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnClick(EventArgs e)
|
||||||
|
{
|
||||||
|
Application.DoEvents();
|
||||||
|
Action?.Invoke();
|
||||||
|
base.OnClick(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MenuItemEx Add<T>(ToolStripItemCollection items, string path, Action<T> action, T value)
|
||||||
|
{
|
||||||
|
return Add(items, path, () => action(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MenuItemEx Add(ToolStripItemCollection items, string path, Action action)
|
||||||
|
{
|
||||||
|
string[] a = path.Split(new[] { " > ", " | " }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
var itemsCollection = items;
|
||||||
|
|
||||||
|
for (int x = 0; x < a.Length; x++)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
foreach (var i in itemsCollection.OfType<ToolStripMenuItem>())
|
||||||
|
{
|
||||||
|
if (x < a.Length - 1)
|
||||||
|
{
|
||||||
|
if (i.Text == a[x] + " ")
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
itemsCollection = i.DropDownItems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
if (x == a.Length - 1)
|
||||||
|
{
|
||||||
|
if (a[x] == "-")
|
||||||
|
itemsCollection.Add(new ToolStripSeparator());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MenuItemEx item = new MenuItemEx(a[x] + " ", action);
|
||||||
|
itemsCollection.Add(item);
|
||||||
|
itemsCollection = item.DropDownItems;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MenuItemEx item = new MenuItemEx();
|
||||||
|
item.Text = a[x] + " ";
|
||||||
|
itemsCollection.Add(item);
|
||||||
|
itemsCollection = item.DropDownItems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public override Size GetPreferredSize(Size constrainingSize)
|
public override Size GetPreferredSize(Size constrainingSize)
|
||||||
{
|
{
|
||||||
var ret = base.GetPreferredSize(constrainingSize);
|
Size size = base.GetPreferredSize(constrainingSize);
|
||||||
ret.Height = Convert.ToInt32(Font.Height * 1.4);
|
size.Height = Convert.ToInt32(Font.Height * 1.4);
|
||||||
return ret;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CloseAll(object item)
|
public void CloseAll(object item)
|
||||||
{
|
{
|
||||||
if (item is ToolStripItem)
|
if (item is ToolStripItem)
|
||||||
{
|
CloseAll(((ToolStripItem)item).Owner);
|
||||||
var d = (ToolStripItem)item;
|
|
||||||
CloseAll(d.Owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item is ToolStripDropDown)
|
if (item is ToolStripDropDown)
|
||||||
{
|
{
|
||||||
@@ -158,20 +132,16 @@ public class MenuItemEx : ToolStripMenuItem
|
|||||||
CloseAll(d.OwnerItem);
|
CloseAll(d.OwnerItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnClick(EventArgs e)
|
|
||||||
{
|
|
||||||
Application.DoEvents();
|
|
||||||
base.OnClick(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ToolStripRendererEx : ToolStripSystemRenderer
|
public class ToolStripRendererEx : ToolStripSystemRenderer
|
||||||
{
|
{
|
||||||
|
public static Color ColorForeground { get; set; } = Color.Black;
|
||||||
|
public static Color ColorTheme { get; set; } = Color.Empty;
|
||||||
public static Color ColorChecked { get; set; }
|
public static Color ColorChecked { get; set; }
|
||||||
public static Color ColorBorder { get; set; }
|
public static Color ColorBorder { get; set; }
|
||||||
public static Color ColorTop { get; set; }
|
public static Color ColorTop { get; set; }
|
||||||
public static Color ColorBottom { get; set; }
|
public static Color ColorSelection { get; set; }
|
||||||
public static Color ColorBackground { get; set; }
|
public static Color ColorBackground { get; set; }
|
||||||
|
|
||||||
public static Color ColorToolStrip1 { get; set; }
|
public static Color ColorToolStrip1 { get; set; }
|
||||||
@@ -179,24 +149,37 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
|
|||||||
public static Color ColorToolStrip3 { get; set; }
|
public static Color ColorToolStrip3 { get; set; }
|
||||||
public static Color ColorToolStrip4 { get; set; }
|
public static Color ColorToolStrip4 { get; set; }
|
||||||
|
|
||||||
private int TextOffset;
|
int TextOffset;
|
||||||
|
|
||||||
public ToolStripRendererEx()
|
public ToolStripRendererEx()
|
||||||
{
|
{
|
||||||
var argb = Convert.ToInt32(Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM", "ColorizationColor", 0));
|
var argb = Convert.ToInt32(Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM", "ColorizationColor", 0));
|
||||||
|
|
||||||
if (argb == 0)
|
if (argb == 0)
|
||||||
argb = Color.LightBlue.ToArgb();
|
argb = Color.LightBlue.ToArgb();
|
||||||
InitColors(Color.FromArgb(argb));
|
if (ColorTheme == Color.Empty)
|
||||||
|
InitColors(Color.FromArgb(argb));
|
||||||
|
else
|
||||||
|
InitColors(ColorTheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void InitColors(Color c)
|
public static void InitColors(Color c)
|
||||||
{
|
{
|
||||||
ColorBorder = HSLColor.Convert(c).ToColorSetLuminosity(100);
|
ColorBorder = HSLColor.Convert(c).ToColorSetLuminosity(100);
|
||||||
ColorChecked = HSLColor.Convert(c).ToColorSetLuminosity(200);
|
ColorChecked = HSLColor.Convert(c).ToColorSetLuminosity(160);
|
||||||
ColorBottom = HSLColor.Convert(c).ToColorSetLuminosity(220);
|
ColorSelection = HSLColor.Convert(c).ToColorSetLuminosity(180);
|
||||||
ColorBackground = HSLColor.Convert(c).ToColorSetLuminosity(230);
|
ColorBackground = HSLColor.Convert(c).ToColorSetLuminosity(210);
|
||||||
ColorTop = HSLColor.Convert(c).ToColorSetLuminosity(240);
|
ColorTop = HSLColor.Convert(c).ToColorSetLuminosity(240);
|
||||||
|
|
||||||
|
if (ColorTheme == Color.Black)
|
||||||
|
{
|
||||||
|
ColorBorder = Color.White;
|
||||||
|
ColorBackground = Color.FromArgb(50, 50, 50);
|
||||||
|
ColorSelection = Color.FromArgb(80, 80, 80);
|
||||||
|
ColorForeground = Color.White;
|
||||||
|
ColorChecked = Color.FromArgb(90, 90, 90);
|
||||||
|
}
|
||||||
|
|
||||||
ColorToolStrip1 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 1)));
|
ColorToolStrip1 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 1)));
|
||||||
ColorToolStrip2 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.7f)));
|
ColorToolStrip2 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.7f)));
|
||||||
ColorToolStrip3 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.1f)));
|
ColorToolStrip3 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.1f)));
|
||||||
@@ -205,7 +188,10 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
|
|||||||
|
|
||||||
protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
|
protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
|
||||||
{
|
{
|
||||||
ControlPaint.DrawBorder(e.Graphics, e.AffectedBounds, Color.FromArgb(160, 175, 195), ButtonBorderStyle.Solid);
|
Rectangle r = e.AffectedBounds;
|
||||||
|
r.Inflate(-1, -1);
|
||||||
|
ControlPaint.DrawBorder(e.Graphics, r, ColorBackground, ButtonBorderStyle.Solid);
|
||||||
|
ControlPaint.DrawBorder(e.Graphics, e.AffectedBounds, ColorBorder, ButtonBorderStyle.Solid);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
|
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
|
||||||
@@ -222,6 +208,7 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
|
|||||||
else
|
else
|
||||||
TextOffset = Convert.ToInt32(e.Item.Height * 0.2);
|
TextOffset = Convert.ToInt32(e.Item.Height * 0.2);
|
||||||
|
|
||||||
|
e.TextColor = ColorForeground;
|
||||||
e.TextRectangle = new Rectangle(TextOffset, Convert.ToInt32((e.Item.Height - rect.Height) / 2.0), rect.Width, rect.Height);
|
e.TextRectangle = new Rectangle(TextOffset, Convert.ToInt32((e.Item.Height - rect.Height) / 2.0), rect.Width, rect.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,118 +222,88 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
|
|||||||
Rectangle r = new Rectangle(-1, -1, e.AffectedBounds.Width, e.AffectedBounds.Height);
|
Rectangle r = new Rectangle(-1, -1, e.AffectedBounds.Width, e.AffectedBounds.Height);
|
||||||
|
|
||||||
using (SolidBrush b = new SolidBrush(ColorToolStrip2))
|
using (SolidBrush b = new SolidBrush(ColorToolStrip2))
|
||||||
{
|
|
||||||
e.Graphics.FillRectangle(b, r);
|
e.Graphics.FillRectangle(b, r);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
|
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
|
||||||
{
|
{
|
||||||
e.Item.ForeColor = Color.Black;
|
Rectangle rect = new Rectangle(Point.Empty, e.Item.Size);
|
||||||
|
|
||||||
var r = new Rectangle(Point.Empty, e.Item.Size);
|
|
||||||
var g = e.Graphics;
|
|
||||||
|
|
||||||
if (!(e.Item.Owner is MenuStrip))
|
if (!(e.Item.Owner is MenuStrip))
|
||||||
g.Clear(ColorBackground);
|
e.Graphics.Clear(ColorBackground);
|
||||||
|
|
||||||
if (e.Item.Selected && e.Item.Enabled)
|
if (e.Item.Selected && e.Item.Enabled)
|
||||||
{
|
{
|
||||||
if (e.Item.Owner is MenuStrip)
|
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||||
DrawButton(e);
|
rect = new Rectangle(rect.X + 2, rect.Y, rect.Width - 4, rect.Height - 1);
|
||||||
else
|
rect.Inflate(-1, -1);
|
||||||
{
|
using (SolidBrush b = new SolidBrush(ColorSelection))
|
||||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
e.Graphics.FillRectangle(b, rect);
|
||||||
|
|
||||||
var r2 = new Rectangle(r.X + 2, r.Y, r.Width - 4, r.Height - 1);
|
|
||||||
|
|
||||||
using (Pen pen = new Pen(ColorBorder))
|
|
||||||
{
|
|
||||||
g.DrawRectangle(pen, r2);
|
|
||||||
}
|
|
||||||
|
|
||||||
r2.Inflate(-1, -1);
|
|
||||||
|
|
||||||
using (SolidBrush b = new SolidBrush(ColorBottom))
|
|
||||||
{
|
|
||||||
g.FillRectangle(b, r2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawButton(ToolStripItemRenderEventArgs e)
|
|
||||||
{
|
|
||||||
var gx = e.Graphics;
|
|
||||||
var rect = new Rectangle(Point.Empty, e.Item.Size);
|
|
||||||
var rect2 = new Rectangle(rect.X, rect.Y, rect.Width - 1, rect.Height - 1);
|
|
||||||
|
|
||||||
using (Pen pen = new Pen(ColorBorder))
|
|
||||||
gx.DrawRectangle(pen, rect2);
|
|
||||||
|
|
||||||
rect2.Inflate(-1, -1);
|
|
||||||
var tsb = e.Item as ToolStripButton;
|
|
||||||
|
|
||||||
if (tsb != null && tsb.Checked)
|
|
||||||
using (SolidBrush brush = new SolidBrush(ColorChecked))
|
|
||||||
gx.FillRectangle(brush, rect2);
|
|
||||||
else
|
|
||||||
using (SolidBrush brush = new SolidBrush(ColorBottom))
|
|
||||||
gx.FillRectangle(brush, rect2);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnRenderDropDownButtonBackground(ToolStripItemRenderEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.Item.Selected)
|
|
||||||
DrawButton(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnRenderButtonBackground(ToolStripItemRenderEventArgs e)
|
|
||||||
{
|
|
||||||
var button = (ToolStripButton)e.Item;
|
|
||||||
if (e.Item.Selected || button.Checked)
|
|
||||||
DrawButton(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e)
|
protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e)
|
||||||
{
|
{
|
||||||
var value = e.Direction == ArrowDirection.Down ? 0x36 : 0x34;
|
if (e.Direction == ArrowDirection.Down) throw new NotImplementedException();
|
||||||
var s = Convert.ToChar(value).ToString();
|
float x1 = e.Item.Width - e.Item.Height * 0.6f;
|
||||||
var font = new Font("Marlett", e.Item.Font.Size - 2);
|
float y1 = e.Item.Height * 0.25f;
|
||||||
var size = e.Graphics.MeasureString(s, font);
|
float x2 = x1 + e.Item.Height * 0.25f;
|
||||||
var x = Convert.ToInt32(e.Item.Width - size.Width);
|
float y2 = e.Item.Height / 2f;
|
||||||
var y = Convert.ToInt32((e.Item.Height - size.Height) / 2.0) + 1;
|
float x3 = x1;
|
||||||
e.Graphics.DrawString(s, font, Brushes.Black, x, y);
|
float y3 = e.Item.Height * 0.75f;
|
||||||
|
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||||
|
|
||||||
|
using (Brush b = new SolidBrush(ColorForeground))
|
||||||
|
{
|
||||||
|
using (Pen p = new Pen(b, Control.DefaultFont.Height / 20f))
|
||||||
|
{
|
||||||
|
e.Graphics.DrawLine(p, x1, y1, x2, y2);
|
||||||
|
e.Graphics.DrawLine(p, x2, y2, x3, y3);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e)
|
protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e)
|
||||||
{
|
{
|
||||||
int x = Convert.ToInt32(e.ImageRectangle.Height * 0.2);
|
if (e.Item.GetType() != typeof(MenuItemEx))
|
||||||
e.Graphics.DrawImage(e.Image, new Point(x, x));
|
return;
|
||||||
|
|
||||||
|
MenuItemEx item = e.Item as MenuItemEx;
|
||||||
|
|
||||||
|
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||||
|
|
||||||
|
if (!item.Checked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Rectangle rect = new Rectangle(Point.Empty, e.Item.Size);
|
||||||
|
rect = new Rectangle(rect.X + 2, rect.Y, rect.Height - 1, rect.Height - 1);
|
||||||
|
rect.Inflate(-1, -1);
|
||||||
|
|
||||||
|
using (Brush brush = new SolidBrush(ColorChecked))
|
||||||
|
e.Graphics.FillRectangle(brush, rect);
|
||||||
|
|
||||||
|
float ellipseWidth = rect.Height / 3f;
|
||||||
|
|
||||||
|
RectangleF rectF = new RectangleF(rect.X + rect.Height / 2f - ellipseWidth / 2f,
|
||||||
|
rect.Y + rect.Height / 2f - ellipseWidth / 2f,
|
||||||
|
ellipseWidth,
|
||||||
|
ellipseWidth);
|
||||||
|
|
||||||
|
using (Brush brush = new SolidBrush(ColorForeground))
|
||||||
|
e.Graphics.FillEllipse(brush, rectF);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e)
|
protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.Item.IsOnDropDown)
|
e.Graphics.Clear(ColorBackground);
|
||||||
{
|
int top = e.Item.Height / 2;
|
||||||
e.Graphics.Clear(ColorBackground);
|
top -= 1;
|
||||||
int right = e.Item.Width - Convert.ToInt32(TextOffset / 5.0);
|
int offset = Convert.ToInt32(e.Item.Font.Height * 0.7);
|
||||||
int top = e.Item.Height / 2;
|
using (Pen p = new Pen(ColorBorder))
|
||||||
top -= 1;
|
e.Graphics.DrawLine(p,
|
||||||
using (Pen p = new Pen(Color.Gray))
|
new Point(offset, top),
|
||||||
e.Graphics.DrawLine(p, new Point(TextOffset, top), new Point(right, top));
|
new Point(e.Item.Width - offset, top));
|
||||||
}
|
|
||||||
else if (e.Vertical)
|
|
||||||
{
|
|
||||||
var bounds = e.Item.Bounds;
|
|
||||||
using (Pen p = new Pen(SystemColors.ControlDarkDark))
|
|
||||||
e.Graphics.DrawLine(p,
|
|
||||||
Convert.ToInt32(bounds.Width / 2.0),
|
|
||||||
Convert.ToInt32(bounds.Height * 0.15),
|
|
||||||
Convert.ToInt32(bounds.Width / 2.0),
|
|
||||||
Convert.ToInt32(bounds.Height * 0.85));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,31 +321,28 @@ public struct HSLColor
|
|||||||
Luminosity = l;
|
Luminosity = l;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double hue;
|
double _Hue;
|
||||||
|
|
||||||
public int Hue
|
public int Hue {
|
||||||
{
|
get => System.Convert.ToInt32(_Hue * 240);
|
||||||
get => System.Convert.ToInt32(hue * 240);
|
set => _Hue = CheckRange(value / 240.0);
|
||||||
set => hue = CheckRange(value / 240.0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private double saturation;
|
double _Saturation;
|
||||||
|
|
||||||
public int Saturation
|
public int Saturation {
|
||||||
{
|
get => System.Convert.ToInt32(_Saturation * 240);
|
||||||
get => System.Convert.ToInt32(saturation * 240);
|
set => _Saturation = CheckRange(value / 240.0);
|
||||||
set => saturation = CheckRange(value / 240.0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private double luminosity;
|
double _Luminosity;
|
||||||
|
|
||||||
public int Luminosity
|
public int Luminosity {
|
||||||
{
|
get => System.Convert.ToInt32(_Luminosity * 240);
|
||||||
get => System.Convert.ToInt32(luminosity * 240);
|
set => _Luminosity = CheckRange(value / 240.0);
|
||||||
set => luminosity = CheckRange(value / 240.0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private double CheckRange(double value)
|
double CheckRange(double value)
|
||||||
{
|
{
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
value = 0;
|
value = 0;
|
||||||
@@ -413,21 +367,21 @@ public struct HSLColor
|
|||||||
{
|
{
|
||||||
double r = 0, g = 0, b = 0;
|
double r = 0, g = 0, b = 0;
|
||||||
|
|
||||||
if (luminosity != 0)
|
if (_Luminosity != 0)
|
||||||
{
|
{
|
||||||
if (saturation == 0)
|
if (_Saturation == 0)
|
||||||
{
|
{
|
||||||
b = luminosity;
|
b = _Luminosity;
|
||||||
g = luminosity;
|
g = _Luminosity;
|
||||||
r = luminosity;
|
r = _Luminosity;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
double temp2 = GetTemp2(this);
|
double temp2 = GetTemp2(this);
|
||||||
double temp1 = 2.0 * luminosity - temp2;
|
double temp1 = 2.0 * _Luminosity - temp2;
|
||||||
r = GetColorComponent(temp1, temp2, hue + 1.0 / 3.0);
|
r = GetColorComponent(temp1, temp2, _Hue + 1.0 / 3.0);
|
||||||
g = GetColorComponent(temp1, temp2, hue);
|
g = GetColorComponent(temp1, temp2, _Hue);
|
||||||
b = GetColorComponent(temp1, temp2, hue - 1.0 / 3.0);
|
b = GetColorComponent(temp1, temp2, _Hue - 1.0 / 3.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,7 +391,7 @@ public struct HSLColor
|
|||||||
System.Convert.ToInt32(255 * b));
|
System.Convert.ToInt32(255 * b));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double GetColorComponent(double temp1, double temp2, double temp3)
|
static double GetColorComponent(double temp1, double temp2, double temp3)
|
||||||
{
|
{
|
||||||
temp3 = MoveIntoRange(temp3);
|
temp3 = MoveIntoRange(temp3);
|
||||||
|
|
||||||
@@ -451,7 +405,7 @@ public struct HSLColor
|
|||||||
return temp1;
|
return temp1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double MoveIntoRange(double temp3)
|
static double MoveIntoRange(double temp3)
|
||||||
{
|
{
|
||||||
if (temp3 < 0)
|
if (temp3 < 0)
|
||||||
temp3 += 1;
|
temp3 += 1;
|
||||||
@@ -460,14 +414,14 @@ public struct HSLColor
|
|||||||
return temp3;
|
return temp3;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double GetTemp2(HSLColor hslColor)
|
static double GetTemp2(HSLColor hslColor)
|
||||||
{
|
{
|
||||||
double temp2;
|
double temp2;
|
||||||
|
|
||||||
if (hslColor.luminosity < 0.5)
|
if (hslColor._Luminosity < 0.5)
|
||||||
temp2 = hslColor.luminosity * (1.0 + hslColor.saturation);
|
temp2 = hslColor._Luminosity * (1.0 + hslColor._Saturation);
|
||||||
else
|
else
|
||||||
temp2 = hslColor.luminosity + hslColor.saturation - (hslColor.luminosity * hslColor.saturation);
|
temp2 = hslColor._Luminosity + hslColor._Saturation - (hslColor._Luminosity * hslColor._Saturation);
|
||||||
|
|
||||||
return temp2;
|
return temp2;
|
||||||
}
|
}
|
||||||
@@ -475,17 +429,17 @@ public struct HSLColor
|
|||||||
public static HSLColor Convert(Color c)
|
public static HSLColor Convert(Color c)
|
||||||
{
|
{
|
||||||
HSLColor r = new HSLColor();
|
HSLColor r = new HSLColor();
|
||||||
r.hue = c.GetHue() / 360.0;
|
r._Hue = c.GetHue() / 360.0;
|
||||||
r.luminosity = c.GetBrightness();
|
r._Luminosity = c.GetBrightness();
|
||||||
r.saturation = c.GetSaturation();
|
r._Saturation = c.GetSaturation();
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRGB(int red, int green, int blue)
|
public void SetRGB(int red, int green, int blue)
|
||||||
{
|
{
|
||||||
HSLColor hc = HSLColor.Convert(Color.FromArgb(red, green, blue));
|
HSLColor hc = HSLColor.Convert(Color.FromArgb(red, green, blue));
|
||||||
hue = hc.hue;
|
_Hue = hc._Hue;
|
||||||
saturation = hc.saturation;
|
_Saturation = hc._Saturation;
|
||||||
luminosity = hc.luminosity;
|
_Luminosity = hc._Luminosity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
118
mpv.net/Misc.cs
@@ -1,6 +1,9 @@
|
|||||||
using System;
|
using Microsoft.Win32;
|
||||||
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
@@ -12,6 +15,14 @@ namespace mpvnet
|
|||||||
|
|
||||||
public static string GetFilter(IEnumerable<string> values) => "*." +
|
public static string GetFilter(IEnumerable<string> values) => "*." +
|
||||||
String.Join(";*.", values) + "|*." + String.Join(";*.", values) + "|All Files|*.*";
|
String.Join(";*.", values) + "|*." + String.Join(";*.", values) + "|All Files|*.*";
|
||||||
|
|
||||||
|
public static bool IsDarkTheme {
|
||||||
|
get {
|
||||||
|
object value = Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", "AppsUseLightTheme", 1);
|
||||||
|
if (value is null) value = 1;
|
||||||
|
return (int)value == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StringLogicalComparer : IComparer, IComparer<string>
|
public class StringLogicalComparer : IComparer, IComparer<string>
|
||||||
@@ -25,13 +36,106 @@ namespace mpvnet
|
|||||||
int IComparer<string>.Compare(string x, string y) => IComparerOfString_Compare(x, y);
|
int IComparer<string>.Compare(string x, string y) => IComparerOfString_Compare(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OSVersion
|
public class FileAssociation
|
||||||
{
|
{
|
||||||
public static float Windows7 { get; } = 6.1f;
|
static string ExePath = Application.ExecutablePath;
|
||||||
public static float Windows8 { get; } = 6.2f;
|
static string ExeFilename = Path.GetFileName(Application.ExecutablePath);
|
||||||
public static float Windows81 { get; } = 6.3f;
|
static string ExeFilenameNoExt = Path.GetFileNameWithoutExtension(Application.ExecutablePath);
|
||||||
public static float Windows10 { get; } = 10f;
|
static string[] Types;
|
||||||
|
public static string[] VideoTypes = "mpg avi vob mp4 mkv avs 264 mov wmv flv h264 asf webm mpeg mpv y4m avc hevc 265 h265 m2v m2ts vpy mts webm m4v".Split(" ".ToCharArray());
|
||||||
|
public static string[] AudioTypes = "mp2 mp3 ac3 wav w64 m4a dts dtsma dtshr dtshd eac3 thd thd+ac3 ogg mka aac opus flac mpa".Split(" ".ToCharArray());
|
||||||
|
|
||||||
public static float Current => Environment.OSVersion.Version.Major + Environment.OSVersion.Version.Minor / 10f;
|
public static void Register(string[] types)
|
||||||
|
{
|
||||||
|
Types = types;
|
||||||
|
|
||||||
|
RegistryHelp.SetValue(@"HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\" + ExeFilename, null, ExePath);
|
||||||
|
RegistryHelp.SetValue($"HKCR\\Applications\\{ExeFilename}", "FriendlyAppName", "mpv.net media player");
|
||||||
|
RegistryHelp.SetValue($"HKCR\\Applications\\{ExeFilename}\\shell\\open\\command", null, $"\"{ExePath}\" \"%1\"");
|
||||||
|
RegistryHelp.SetValue(@"HKLM\SOFTWARE\Clients\Media\mpv\Capabilities", "ApplicationDescription", "mpv.net media player");
|
||||||
|
RegistryHelp.SetValue(@"HKLM\SOFTWARE\Clients\Media\mpv\Capabilities", "ApplicationName", "mpv.net");
|
||||||
|
RegistryHelp.SetValue($"HKCR\\SystemFileAssociations\\video\\OpenWithList\\{ExeFilename}", null, "");
|
||||||
|
RegistryHelp.SetValue($"HKCR\\SystemFileAssociations\\audio\\OpenWithList\\{ExeFilename}", null, "");
|
||||||
|
|
||||||
|
foreach (string ext in Types)
|
||||||
|
{
|
||||||
|
RegistryHelp.SetValue($"HKCR\\Applications\\{ExeFilename}\\SupportedTypes", "." + ext, "");
|
||||||
|
RegistryHelp.SetValue($"HKCR\\" + "." + ext, null, ExeFilenameNoExt + "." + ext);
|
||||||
|
RegistryHelp.SetValue($"HKCR\\" + "." + ext + "\\OpenWithProgIDs", ExeFilenameNoExt + "." + ext, "");
|
||||||
|
if (VideoTypes.Contains(ext))
|
||||||
|
RegistryHelp.SetValue($"HKCR\\" + "." + ext, "PerceivedType", "video");
|
||||||
|
if (AudioTypes.Contains(ext))
|
||||||
|
RegistryHelp.SetValue($"HKCR\\" + "." + ext, "PerceivedType", "audio");
|
||||||
|
RegistryHelp.SetValue($"HKCR\\" + ExeFilenameNoExt + "." + ext + "\\shell\\open", null, "Play with " + Application.ProductName);
|
||||||
|
RegistryHelp.SetValue($"HKCR\\" + ExeFilenameNoExt + "." + ext + "\\shell\\open\\command", null, $"\"{ExePath}\" \"%1\"");
|
||||||
|
RegistryHelp.SetValue(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities\FileAssociations", "." + ext, ExeFilenameNoExt + "." + ext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Unregister()
|
||||||
|
{
|
||||||
|
RegistryHelp.RemoveKey(@"HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\" + ExeFilename);
|
||||||
|
RegistryHelp.RemoveKey($"HKCR\\Applications\\{ExeFilename}");
|
||||||
|
RegistryHelp.RemoveKey(@"HKLM\SOFTWARE\Clients\Media\mpv.net");
|
||||||
|
RegistryHelp.RemoveKey($"HKCR\\SystemFileAssociations\\video\\OpenWithList\\{ExeFilename}");
|
||||||
|
RegistryHelp.RemoveKey($"HKCR\\SystemFileAssociations\\audio\\OpenWithList\\{ExeFilename}");
|
||||||
|
|
||||||
|
foreach (string id in Registry.ClassesRoot.GetSubKeyNames())
|
||||||
|
{
|
||||||
|
if (id.StartsWith(ExeFilenameNoExt + "."))
|
||||||
|
Registry.ClassesRoot.DeleteSubKeyTree(id);
|
||||||
|
|
||||||
|
RegistryHelp.RemoveValue($"HKCR\\Software\\Classes\\" + id + "\\OpenWithProgIDs", ExeFilenameNoExt + id);
|
||||||
|
RegistryHelp.RemoveValue($"HKLM\\Software\\Classes\\" + id + "\\OpenWithProgIDs", ExeFilenameNoExt + id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RegistryHelp
|
||||||
|
{
|
||||||
|
public static void SetValue(string path, string name, string value)
|
||||||
|
{
|
||||||
|
using (RegistryKey rk = GetRootKey(path).CreateSubKey(path.Substring(5), RegistryKeyPermissionCheck.ReadWriteSubTree))
|
||||||
|
rk.SetValue(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetValue(string path, string name)
|
||||||
|
{
|
||||||
|
using (RegistryKey rk = GetRootKey(path).OpenSubKey(path.Substring(5)))
|
||||||
|
if (rk != null)
|
||||||
|
return rk.GetValue(name, "").ToString();
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RemoveKey(string path)
|
||||||
|
{
|
||||||
|
GetRootKey(path).DeleteSubKeyTree(path.Substring(5), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RemoveValue(string path, string name)
|
||||||
|
{
|
||||||
|
using (RegistryKey rk = GetRootKey(path).OpenSubKey(path.Substring(5), true))
|
||||||
|
if (!(rk is null))
|
||||||
|
rk.DeleteValue(name, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static RegistryKey GetRootKey(string path)
|
||||||
|
{
|
||||||
|
switch (path.Substring(0, 4))
|
||||||
|
{
|
||||||
|
case "HKLM": return Registry.LocalMachine;
|
||||||
|
case "HKCU": return Registry.CurrentUser;
|
||||||
|
case "HKCR": return Registry.ClassesRoot;
|
||||||
|
default: throw new Exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MediaTrack
|
||||||
|
{
|
||||||
|
public string Text { get; set; }
|
||||||
|
public string Type { get; set; }
|
||||||
|
public int ID { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@ using System.Management.Automation.Runspaces;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using VBNET;
|
||||||
|
|
||||||
namespace mpvnet
|
namespace mpvnet
|
||||||
{
|
{
|
||||||
@@ -47,12 +48,12 @@ Using namespace System;
|
|||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex2)
|
||||||
{
|
{
|
||||||
MainForm.Instance.ShowMsgBox("PowerShell Setup Problem\n\nEnsure you have at least PowerShell 5.1 installed.", MessageBoxIcon.Error);
|
Msg.ShowError("PowerShell Setup Problem\n\nEnsure you have at least PowerShell 5.1 installed.", ex2.ToString());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
MainForm.Instance.ShowMsgBox(ex.ToString(), MessageBoxIcon.Error);
|
Msg.ShowException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,24 @@ namespace mpvnet
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
static void Main()
|
static void Main()
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string[] args = Environment.GetCommandLineArgs();
|
||||||
|
|
||||||
|
if (args.Length == 3 && args[1] == "--reg-file-assoc")
|
||||||
|
{
|
||||||
|
if (args[2] == "audio") FileAssociation.Register(FileAssociation.AudioTypes);
|
||||||
|
if (args[2] == "video") FileAssociation.Register(FileAssociation.VideoTypes);
|
||||||
|
if (args[2] == "unregister") FileAssociation.Unregister();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show(ex.ToString(), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Application.EnableVisualStyles();
|
Application.EnableVisualStyles();
|
||||||
Application.SetCompatibleTextRenderingDefault(false);
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
Application.Run(new MainForm());
|
Application.Run(new MainForm());
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
|
|||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("")]
|
||||||
[assembly: AssemblyProduct("mpv.net")]
|
[assembly: AssemblyProduct("mpv.net")]
|
||||||
[assembly: AssemblyCopyright("Copyright © stax76")]
|
[assembly: AssemblyCopyright("Copyright © 2017-2019 stax76")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("2.2.0.0")]
|
[assembly: AssemblyVersion("3.0.0.0")]
|
||||||
[assembly: AssemblyFileVersion("2.2.0.0")]
|
[assembly: AssemblyFileVersion("3.0.0.0")]
|
||||||
|
|||||||
35
mpv.net/Properties/Resources.Designer.cs
generated
@@ -61,16 +61,20 @@ namespace mpvnet.Properties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to # mpv.net key bindings, mouse bindings and context menu configuration
|
/// Looks up a localized string similar to
|
||||||
|
/// # This file defines the input (keys and mouse) bindings of mpv and mpv.net
|
||||||
|
/// # and it also defines the context menu of mpv.net. mpv.net has an input
|
||||||
|
/// # editor and an conf editor as alternatives to editing conf text files.
|
||||||
|
/// # The input and conf editors can be found in mpv.net's context menu at:
|
||||||
///
|
///
|
||||||
/// o script-message mpv.net open-files #menu: O ; Open Files...
|
/// # Settings > Show Config Editor
|
||||||
/// _ ignore #menu: _ ; -
|
/// # Settings > Show Input Editor
|
||||||
/// Space cycle pause #menu: Space, Enter ; Play/Pause
|
///
|
||||||
/// Enter cycle pause
|
/// # The defaults of this file can be found at:
|
||||||
/// s stop #menu: S ; Stop
|
///
|
||||||
/// _ ignore #menu: _ ; -
|
/// # https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt
|
||||||
/// f cycle fullscreen #menu: F ; Toggle Fullscreen
|
///
|
||||||
/// [rest of string was truncated]";.
|
/// # the [rest of string was truncated]";.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string input_conf {
|
internal static string input_conf {
|
||||||
get {
|
get {
|
||||||
@@ -79,15 +83,20 @@ namespace mpvnet.Properties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to input-ar-delay = 500
|
/// Looks up a localized string similar to
|
||||||
|
///# mpv manual: https://mpv.io/manual/master/
|
||||||
|
///
|
||||||
|
///# mpv.net mpv.conf defaults: https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/mpv.conf.txt
|
||||||
|
///
|
||||||
|
///input-ar-delay = 500
|
||||||
///input-ar-rate = 20
|
///input-ar-rate = 20
|
||||||
///volume = 50
|
///volume = 50
|
||||||
///hwdec = yes
|
///hwdec = yes
|
||||||
///vo = direct3d
|
|
||||||
///keep-open = yes
|
///keep-open = yes
|
||||||
///keep-open-pause = no
|
///keep-open-pause = no
|
||||||
///osd-playing-msg = '${filename}'
|
///osd-playing-msg = ${filename}
|
||||||
///screenshot-directory = ~~desktop/.
|
///screenshot-directory = ~~desktop/
|
||||||
|
///input-default-bindings = no.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string mpv_conf {
|
internal static string mpv_conf {
|
||||||
get {
|
get {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System.Reflection;
|
|||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using IronPython.Hosting;
|
using IronPython.Hosting;
|
||||||
using Microsoft.Scripting.Hosting;
|
using Microsoft.Scripting.Hosting;
|
||||||
|
using VBNET;
|
||||||
using PyRT = IronPython.Runtime;
|
using PyRT = IronPython.Runtime;
|
||||||
|
|
||||||
namespace mpvnet
|
namespace mpvnet
|
||||||
@@ -27,7 +27,7 @@ namespace mpvnet
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
MainForm.Instance.ShowMsgBox(ex.ToString(), MessageBoxIcon.Error);
|
Msg.ShowException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,61 @@
|
|||||||
|
|
||||||
|
# This file defines the input (keys and mouse) bindings of mpv and mpv.net
|
||||||
|
# and it also defines the context menu of mpv.net. mpv.net has an input
|
||||||
|
# editor and an conf editor as alternatives to editing conf text files.
|
||||||
|
# The input and conf editors can be found in mpv.net's context menu at:
|
||||||
|
|
||||||
|
# Settings > Show Config Editor
|
||||||
|
# Settings > Show Input Editor
|
||||||
|
|
||||||
|
# The defaults of this file can be found at:
|
||||||
|
|
||||||
|
# https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt
|
||||||
|
|
||||||
|
# the defaults of mpv can be found at:
|
||||||
|
|
||||||
|
# https://github.com/mpv-player/mpv/blob/master/etc/input.conf
|
||||||
|
|
||||||
|
# mpv.net's defaults of mpv.conf contain: 'input-default-bindings = no'
|
||||||
|
# which disables mpv's input defaults. Every line in this file begins with a
|
||||||
|
# space character to make it easier to do a text search, so if you want to know
|
||||||
|
# if 'o' has already a binding you can make a text search on ' o '.
|
||||||
|
|
||||||
|
# mpv input commands: https://github.com/stax76/mpv.net/wiki/mpv-input-commands
|
||||||
|
|
||||||
|
# mpv input keys: https://github.com/stax76/mpv.net/wiki/mpv-input-keys
|
||||||
|
|
||||||
o script-message mpv.net open-files #menu: Open > Open Files...
|
o script-message mpv.net open-files #menu: Open > Open Files...
|
||||||
u script-message mpv.net open-url #menu: Open > Open URL...
|
u script-message mpv.net open-url #menu: Open > Open URL...
|
||||||
|
_ ignore #menu: Open > -
|
||||||
|
Alt+a script-message mpv.net load-audio #menu: Open > Load external audio files...
|
||||||
|
Alt+s script-message mpv.net load-sub #menu: Open > Load external subtitle files...
|
||||||
|
|
||||||
_ ignore #menu: -
|
_ ignore #menu: -
|
||||||
Space cycle pause #menu: Play/Pause
|
Space cycle pause #menu: Play/Pause
|
||||||
s stop #menu: Stop
|
s stop #menu: Stop
|
||||||
_ ignore #menu: -
|
_ ignore #menu: -
|
||||||
f cycle fullscreen #menu: Toggle Fullscreen
|
Enter cycle fullscreen #menu: Toggle Fullscreen
|
||||||
|
|
||||||
F11 playlist-prev #menu: Navigate > Previous
|
F11 playlist-prev #menu: Navigate > Previous
|
||||||
F12 playlist-next #menu: Navigate > Next
|
F12 playlist-next #menu: Navigate > Next
|
||||||
_ ignore #menu: Navigate > -
|
_ ignore #menu: Navigate > -
|
||||||
PGUP add chapter 1 #menu: Navigate > Next Chapter
|
PGUP add chapter 1 #menu: Navigate > Next Chapter
|
||||||
PGDWN add chapter -1 #menu: Navigate > Previous Chapter
|
PGDWN add chapter -1 #menu: Navigate > Previous Chapter
|
||||||
|
_ ignore #menu: Navigate > -
|
||||||
|
. frame-step #menu: Navigate > Jump Next Frame
|
||||||
|
, frame-back-step #menu: Navigate > Jump Previous Frame
|
||||||
|
_ ignore #menu: Navigate > -
|
||||||
|
Right no-osd seek 7 #menu: Navigate > Jump 7 sec forward
|
||||||
|
Left no-osd seek -7 #menu: Navigate > Jump 7 sec backward
|
||||||
|
_ ignore #menu: Navigate > -
|
||||||
|
Up no-osd seek 40 #menu: Navigate > Jump 40 sec forward
|
||||||
|
Down no-osd seek -40 #menu: Navigate > Jump 40 sec backward
|
||||||
|
_ ignore #menu: Navigate > -
|
||||||
|
Ctrl+Right no-osd seek 300 #menu: Navigate > Jump 5 min forward
|
||||||
|
Ctrl+Left no-osd seek -300 #menu: Navigate > Jump 5 min backward
|
||||||
|
_ ignore #menu: Navigate > -
|
||||||
|
_ ignore #menu: Navigate > Chapters
|
||||||
|
|
||||||
. frame-step #menu: Seek > Next Frame
|
|
||||||
, frame-back-step #menu: Seek > Previous Frame
|
|
||||||
_ ignore #menu: Seek > -
|
|
||||||
Right no-osd seek 7 #menu: Seek > 7 sec forward
|
|
||||||
Left no-osd seek -7 #menu: Seek > 7 sec backward
|
|
||||||
_ ignore #menu: Seek > -
|
|
||||||
Up no-osd seek 40 #menu: Seek > 40 sec forward
|
|
||||||
Down no-osd seek -40 #menu: Seek > 40 sec backward
|
|
||||||
_ ignore #menu: Seek > -
|
|
||||||
Ctrl+Right no-osd seek 300 #menu: Seek > 5 min forward
|
|
||||||
Ctrl+Left no-osd seek -300 #menu: Seek > 5 min backward
|
|
||||||
Ctrl++ add video-zoom 0.1 #menu: Pan & Scan > Increase Size
|
Ctrl++ add video-zoom 0.1 #menu: Pan & Scan > Increase Size
|
||||||
Ctrl+- add video-zoom -0.1 #menu: Pan & Scan > Decrease Size
|
Ctrl+- add video-zoom -0.1 #menu: Pan & Scan > Decrease Size
|
||||||
_ ignore #menu: Pan & Scan > -
|
_ ignore #menu: Pan & Scan > -
|
||||||
@@ -33,43 +66,50 @@
|
|||||||
Ctrl+KP2 add video-pan-y 0.01 #menu: Pan & Scan > Move Down
|
Ctrl+KP2 add video-pan-y 0.01 #menu: Pan & Scan > Move Down
|
||||||
_ ignore #menu: Pan & Scan > -
|
_ ignore #menu: Pan & Scan > -
|
||||||
w add panscan -0.1 #menu: Pan & Scan > Decrease Height
|
w add panscan -0.1 #menu: Pan & Scan > Decrease Height
|
||||||
W add panscan +0.1 #menu: Pan & Scan > Increase Height
|
W add panscan 0.1 #menu: Pan & Scan > Increase Height
|
||||||
_ ignore #menu: Pan & Scan > -
|
_ ignore #menu: Pan & Scan > -
|
||||||
Ctrl+BS set video-zoom 0 ; set video-pan-x 0 ; set video-pan-y 0 #menu: Pan & Scan > Reset
|
Ctrl+BS set video-zoom 0; set video-pan-x 0; set video-pan-y 0 #menu: Pan & Scan > Reset
|
||||||
|
|
||||||
Ctrl+1 add contrast -1 #menu: Video > Decrease Contrast
|
Ctrl+1 add contrast -1 #menu: Video > Decrease Contrast
|
||||||
Ctrl+2 add contrast 1 #menu: Video > Increase Contrast
|
Ctrl+2 add contrast #menu: Video > Increase Contrast
|
||||||
_ ignore #menu: Video > -
|
_ ignore #menu: Video > -
|
||||||
Ctrl+3 add brightness -1 #menu: Video > Decrease Brightness
|
Ctrl+3 add brightness -1 #menu: Video > Decrease Brightness
|
||||||
Ctrl+4 add brightness 1 #menu: Video > Increase Brightness
|
Ctrl+4 add brightness 1 #menu: Video > Increase Brightness
|
||||||
_ ignore #menu: Video > -
|
_ ignore #menu: Video > -
|
||||||
Ctrl+5 add gamma -1 #menu: Video > Decrease Gamma
|
Ctrl+5 add gamma -1 #menu: Video > Decrease Gamma
|
||||||
Ctrl+6 add gamma 1 #menu: Video > Increase Gamma
|
Ctrl+6 add gamma 1 #menu: Video > Increase Gamma
|
||||||
_ ignore #menu: Video > -
|
_ ignore #menu: Video > -
|
||||||
Ctrl+7 add saturation -1 #menu: Video > Decrease Saturation
|
Ctrl+7 add saturation -1 #menu: Video > Decrease Saturation
|
||||||
Ctrl+8 add saturation 1 #menu: Video > Increase Saturation
|
Ctrl+8 add saturation 1 #menu: Video > Increase Saturation
|
||||||
_ ignore #menu: Video > -
|
_ ignore #menu: Video > -
|
||||||
Ctrl+s async screenshot #menu: Video > Take Screenshot
|
Ctrl+s async screenshot #menu: Video > Take Screenshot
|
||||||
d cycle deinterlace #menu: Video > Toggle Deinterlace
|
d cycle deinterlace #menu: Video > Toggle Deinterlace
|
||||||
a cycle-values video-aspect "16:9" "4:3" "2.35:1" "-1" #menu: Video > Cycle Aspect Ratio
|
a cycle-values video-aspect "16:9" "4:3" "2.35:1" "-1" #menu: Video > Cycle Aspect Ratio
|
||||||
KP7 cycle audio #menu: Audio > Cycle/Next
|
|
||||||
|
KP7 script-message mpv.net cycle-audio #menu: Audio > Cycle/Next
|
||||||
_ ignore #menu: Audio > -
|
_ ignore #menu: Audio > -
|
||||||
KP6 add audio-delay 0.100 #menu: Audio > Delay +0.1
|
KP6 add audio-delay 0.100 #menu: Audio > Delay +0.1
|
||||||
KP9 add audio-delay -0.100 #menu: Audio > Delay -0.1
|
KP9 add audio-delay -0.100 #menu: Audio > Delay -0.1
|
||||||
|
|
||||||
KP8 cycle sub #menu: Subtitle > Cycle/Next
|
KP8 cycle sub #menu: Subtitle > Cycle/Next
|
||||||
v cycle sub-visibility #menu: Subtitle > Toggle Visibility
|
v cycle sub-visibility #menu: Subtitle > Toggle Visibility
|
||||||
_ ignore #menu: Subtitle > -
|
_ ignore #menu: Subtitle > -
|
||||||
z add sub-delay -0.1 #menu: Subtitle > Delay -0.1
|
z add sub-delay -0.1 #menu: Subtitle > Delay -0.1
|
||||||
Z add sub-delay +0.1 #menu: Subtitle > Delay +0.1
|
Z add sub-delay 0.1 #menu: Subtitle > Delay +0.1
|
||||||
_ ignore #menu: Subtitle > -
|
_ ignore #menu: Subtitle > -
|
||||||
r add sub-pos -1 #menu: Subtitle > Move Up
|
r add sub-pos -1 #menu: Subtitle > Move Up
|
||||||
R add sub-pos +1 #menu: Subtitle > Move Down
|
R add sub-pos +1 #menu: Subtitle > Move Down
|
||||||
_ ignore #menu: Subtitle > -
|
_ ignore #menu: Subtitle > -
|
||||||
_ add sub-scale -0.1 #menu: Subtitle > Decrease Subtitle Font Size
|
_ add sub-scale -0.1 #menu: Subtitle > Decrease Subtitle Font Size
|
||||||
_ add sub-scale +0.1 #menu: Subtitle > Increase Subtitle Font Size
|
_ add sub-scale 0.1 #menu: Subtitle > Increase Subtitle Font Size
|
||||||
|
|
||||||
|
_ ignore #menu: Track
|
||||||
|
|
||||||
+ add volume 10 #menu: Volume > Up
|
+ add volume 10 #menu: Volume > Up
|
||||||
- add volume -10 #menu: Volume > Down
|
- add volume -10 #menu: Volume > Down
|
||||||
_ ignore #menu: Volume > -
|
_ ignore #menu: Volume > -
|
||||||
m cycle mute #menu: Volume > Mute
|
m cycle mute #menu: Volume > Mute
|
||||||
|
|
||||||
[ multiply speed 0.9 #menu: Speed > -10%
|
[ multiply speed 0.9 #menu: Speed > -10%
|
||||||
] multiply speed 1.1 #menu: Speed > +10%
|
] multiply speed 1.1 #menu: Speed > +10%
|
||||||
_ ignore #menu: Speed > -
|
_ ignore #menu: Speed > -
|
||||||
@@ -77,39 +117,43 @@
|
|||||||
} multiply speed 2.0 #menu: Speed > Double
|
} multiply speed 2.0 #menu: Speed > Double
|
||||||
_ ignore #menu: Speed > -
|
_ ignore #menu: Speed > -
|
||||||
BS set speed 1 #menu: Speed > Reset
|
BS set speed 1 #menu: Speed > Reset
|
||||||
KP0 script-message rate-file 0 #menu: Addons > Rating > 0stars
|
|
||||||
KP1 script-message rate-file 1 #menu: Addons > Rating > 1stars
|
KP0 script-message rate-file 0 #menu: Extensions > Rating > 0stars
|
||||||
KP2 script-message rate-file 2 #menu: Addons > Rating > 2stars
|
KP1 script-message rate-file 1 #menu: Extensions > Rating > 1stars
|
||||||
KP3 script-message rate-file 3 #menu: Addons > Rating > 3stars
|
KP2 script-message rate-file 2 #menu: Extensions > Rating > 2stars
|
||||||
KP4 script-message rate-file 4 #menu: Addons > Rating > 4stars
|
KP3 script-message rate-file 3 #menu: Extensions > Rating > 3stars
|
||||||
KP5 script-message rate-file 5 #menu: Addons > Rating > 5stars
|
KP4 script-message rate-file 4 #menu: Extensions > Rating > 4stars
|
||||||
_ script-message mpv.net set-setting hwdec yes #menu: Settings > Hardware Decoding > Enable
|
KP5 script-message rate-file 5 #menu: Extensions > Rating > 5stars
|
||||||
_ script-message mpv.net set-setting hwdec no #menu: Settings > Hardware Decoding > Disable
|
|
||||||
e script-message mpv.net show-conf-editor #menu: Settings > Show Config Editor
|
Ctrl+t set ontop yes #menu: View > On Top > Enable
|
||||||
Ctrl+i script-message mpv.net show-input-editor #menu: Settings > Show Input Editor
|
Ctrl+T set ontop no #menu: View > On Top > Disable
|
||||||
c script-message mpv.net open-config-folder #menu: Settings > Open Config Folder
|
i script-message mpv.net show-info #menu: View > File Info
|
||||||
i script-message mpv.net show-info #menu: Tools > Info
|
t script-binding stats/display-stats #menu: View > Show Statistics
|
||||||
t script-binding stats/display-stats #menu: Tools > Show Statistics
|
T script-binding stats/display-stats-toggle #menu: View > Toggle Statistics
|
||||||
T script-binding stats/display-stats-toggle #menu: Tools > Toggle Statistics
|
Del script-binding osc/visibility #menu: View > Toggle OSC Visibility
|
||||||
_ ignore #menu: Tools > -
|
F8 show-text ${playlist} 5000 #menu: View > Show Playlist
|
||||||
h script-message mpv.net show-history #menu: Tools > Show History
|
F9 show-text ${track-list} 5000 #menu: View > Show Audio/Video/Subtitle List
|
||||||
l ab-loop #menu: Tools > Set/clear A-B loop points
|
|
||||||
L cycle-values loop-file "inf" "no" #menu: Tools > Toggle Infinite Looping
|
Ctrl+c script-message mpv.net show-conf-editor #menu: Settings > Show Config Editor
|
||||||
Del script-binding osc/visibility #menu: Tools > Toggle OSC Visibility
|
Ctrl+i script-message mpv.net show-input-editor #menu: Settings > Show Input Editor
|
||||||
Ctrl+h cycle-values hwdec "auto" "no" #menu: Tools > Cycle Hardware Decoding
|
Ctrl+f script-message mpv.net open-conf-folder #menu: Settings > Open Config Folder
|
||||||
F8 show-text ${playlist} 5000 #menu: Tools > Show Playlist
|
|
||||||
F9 show-text ${track-list} 5000 #menu: Tools > Show Audio/Video/Subtitle List
|
h script-message mpv.net show-history #menu: Tools > Show History
|
||||||
_ script-message mpv.net execute-mpv-command #menu: Tools > Execute mpv command...
|
l ab-loop #menu: Tools > Set/clear A-B loop points
|
||||||
|
L cycle-values loop-file "inf" "no" #menu: Tools > Toggle infinite file looping
|
||||||
|
Ctrl+h cycle-values hwdec "auto" "no" #menu: Tools > Cycle Hardware Decoding
|
||||||
|
_ script-message mpv.net execute-mpv-command #menu: Tools > Execute mpv command...
|
||||||
|
|
||||||
_ script-message mpv.net shell-execute https://mpv.io/manual/stable/ #menu: Help > Show mpv manual
|
_ script-message mpv.net shell-execute https://mpv.io/manual/stable/ #menu: Help > Show mpv manual
|
||||||
_ script-message mpv.net shell-execute https://github.com/mpv-player/mpv/blob/master/etc/input.conf #menu: Help > Show mpv default keys
|
_ script-message mpv.net shell-execute https://github.com/mpv-player/mpv/blob/master/etc/input.conf #menu: Help > Show mpv default keys
|
||||||
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt #menu: Help > Show mpv.net default keys
|
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt #menu: Help > Show mpv.net default keys
|
||||||
_ script-message mpv.net shell-execute https://github.com/stax76/mpvnet #menu: Help > Show mpv.net web site
|
_ script-message mpv.net shell-execute https://github.com/stax76/mpvnet #menu: Help > Show mpv.net web site
|
||||||
_ ignore #menu: -
|
|
||||||
Esc quit #menu: Exit
|
_ ignore #menu: -
|
||||||
Q quit-watch-later #menu: Exit Watch Later
|
Esc quit #menu: Exit
|
||||||
|
Q quit-watch-later #menu: Exit Watch Later
|
||||||
> playlist-next
|
> playlist-next
|
||||||
< playlist-prev
|
< playlist-prev
|
||||||
Enter cycle pause
|
|
||||||
Power quit
|
Power quit
|
||||||
Play cycle pause
|
Play cycle pause
|
||||||
Pause cycle pause
|
Pause cycle pause
|
||||||
@@ -118,7 +162,7 @@
|
|||||||
Forward seek 60
|
Forward seek 60
|
||||||
Rewind seek -60
|
Rewind seek -60
|
||||||
Mute cycle mute
|
Mute cycle mute
|
||||||
Volume_Up add volume 10
|
Volume_Up add volume 10
|
||||||
Volume_Down add volume -10
|
Volume_Down add volume -10
|
||||||
Wheel_Up add volume 10
|
Wheel_Up add volume 10
|
||||||
Wheel_Down add volume -10
|
Wheel_Down add volume -10
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
# mpv manual: https://mpv.io/manual/master/
|
|
||||||
|
# mpv manual: https://mpv.io/manual/master/
|
||||||
|
|
||||||
# mpv.net mpv.conf defaults: https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/mpv.conf.txt
|
# mpv.net mpv.conf defaults: https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/mpv.conf.txt
|
||||||
|
|
||||||
input-ar-delay = 500
|
input-ar-delay = 500
|
||||||
input-ar-rate = 20
|
input-ar-rate = 20
|
||||||
volume = 50
|
volume = 50
|
||||||
hwdec = yes
|
hwdec = yes
|
||||||
vo = direct3d
|
|
||||||
keep-open = yes
|
keep-open = yes
|
||||||
keep-open-pause = no
|
keep-open-pause = no
|
||||||
osd-playing-msg = ${filename}
|
osd-playing-msg = ${filename}
|
||||||
|
|||||||
439
mpv.net/mp.cs
@@ -11,6 +11,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
using VBNET;
|
||||||
using static mpvnet.libmpv;
|
using static mpvnet.libmpv;
|
||||||
using static mpvnet.Native;
|
using static mpvnet.Native;
|
||||||
|
|
||||||
@@ -52,18 +53,23 @@ namespace mpvnet
|
|||||||
public static event Action QueueOverflow; // MPV_EVENT_QUEUE_OVERFLOW
|
public static event Action QueueOverflow; // MPV_EVENT_QUEUE_OVERFLOW
|
||||||
public static event Action Hook; // MPV_EVENT_HOOK
|
public static event Action Hook; // MPV_EVENT_HOOK
|
||||||
|
|
||||||
public static IntPtr MpvHandle;
|
public static IntPtr MpvHandle { get; set; }
|
||||||
public static IntPtr MpvWindowHandle;
|
public static IntPtr MpvWindowHandle { get; set; }
|
||||||
public static Addon Addon;
|
public static Addon Addon { get; set; }
|
||||||
public static List<KeyValuePair<string, Action<bool>>> BoolPropChangeActions = new List<KeyValuePair<string, Action<bool>>>();
|
public static List<KeyValuePair<string, Action<bool>>> BoolPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<bool>>>();
|
||||||
public static Size VideoSize = new Size(1920, 1080);
|
public static List<KeyValuePair<string, Action<int>>> IntPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<int>>>();
|
||||||
public static string mpvConfFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\";
|
public static List<KeyValuePair<string, Action<string>>> StringPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<string>>>();
|
||||||
public static string InputConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\input.conf";
|
public static Size VideoSize { get; set; } = new Size(1920, 1080);
|
||||||
public static string mpvConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpv.conf";
|
public static string MpvConfFolderPath { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\";
|
||||||
public static List<PythonScript> PythonScripts => new List<PythonScript>();
|
public static string InputConfPath { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\input.conf";
|
||||||
public static AutoResetEvent AutoResetEvent = new AutoResetEvent(false);
|
public static string MpvConfPath { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpv.conf";
|
||||||
|
public static string MpvNetConfPath { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpvnet.conf";
|
||||||
|
public static List<PythonScript> PythonScripts { get; set; } = new List<PythonScript>();
|
||||||
|
public static AutoResetEvent AutoResetEvent { get; set; } = new AutoResetEvent(false);
|
||||||
|
public static List<MediaTrack> MediaTracks { get; set; } = new List<MediaTrack>();
|
||||||
|
public static List<KeyValuePair<string, double>> Chapters { get; set; } = new List<KeyValuePair<string, double>>();
|
||||||
|
|
||||||
private static Dictionary<string, string> _mpvConf;
|
static Dictionary<string, string> _mpvConf;
|
||||||
|
|
||||||
public static Dictionary<string, string> mpvConf {
|
public static Dictionary<string, string> mpvConf {
|
||||||
get {
|
get {
|
||||||
@@ -71,8 +77,8 @@ namespace mpvnet
|
|||||||
{
|
{
|
||||||
_mpvConf = new Dictionary<string, string>();
|
_mpvConf = new Dictionary<string, string>();
|
||||||
|
|
||||||
if (File.Exists(mpvConfPath))
|
if (File.Exists(MpvConfPath))
|
||||||
foreach (var i in File.ReadAllLines(mpvConfPath))
|
foreach (var i in File.ReadAllLines(MpvConfPath))
|
||||||
if (i.Contains("=") && ! i.StartsWith("#"))
|
if (i.Contains("=") && ! i.StartsWith("#"))
|
||||||
_mpvConf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
|
_mpvConf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
|
||||||
}
|
}
|
||||||
@@ -80,13 +86,30 @@ namespace mpvnet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Dictionary<string, string> _mpvNetConf;
|
||||||
|
|
||||||
|
public static Dictionary<string, string> mpvNetConf {
|
||||||
|
get {
|
||||||
|
if (_mpvNetConf == null)
|
||||||
|
{
|
||||||
|
_mpvNetConf = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
if (File.Exists(MpvNetConfPath))
|
||||||
|
foreach (string i in File.ReadAllLines(MpvNetConfPath))
|
||||||
|
if (i.Contains("=") && !i.StartsWith("#"))
|
||||||
|
_mpvNetConf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
|
||||||
|
}
|
||||||
|
return _mpvNetConf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Init()
|
public static void Init()
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(mp.mpvConfFolderPath))
|
if (!Directory.Exists(mp.MpvConfFolderPath))
|
||||||
Directory.CreateDirectory(mp.mpvConfFolderPath);
|
Directory.CreateDirectory(mp.MpvConfFolderPath);
|
||||||
|
|
||||||
if (!File.Exists(mp.mpvConfPath))
|
if (!File.Exists(mp.MpvConfPath))
|
||||||
File.WriteAllText(mp.mpvConfPath, Properties.Resources.mpv_conf);
|
File.WriteAllText(mp.MpvConfPath, Properties.Resources.mpv_conf);
|
||||||
|
|
||||||
if (!File.Exists(mp.InputConfPath))
|
if (!File.Exists(mp.InputConfPath))
|
||||||
File.WriteAllText(mp.InputConfPath, Properties.Resources.input_conf);
|
File.WriteAllText(mp.InputConfPath, Properties.Resources.input_conf);
|
||||||
@@ -123,7 +146,7 @@ namespace mpvnet
|
|||||||
if (Path.GetExtension(scriptPath) == ".ps1")
|
if (Path.GetExtension(scriptPath) == ".ps1")
|
||||||
PowerShellScript.Init(scriptPath);
|
PowerShellScript.Init(scriptPath);
|
||||||
|
|
||||||
foreach (var scriptPath in Directory.GetFiles(mp.mpvConfFolderPath + "Scripts"))
|
foreach (var scriptPath in Directory.GetFiles(mp.MpvConfFolderPath + "Scripts"))
|
||||||
if (Path.GetExtension(scriptPath) == ".py")
|
if (Path.GetExtension(scriptPath) == ".py")
|
||||||
PythonScripts.Add(new PythonScript(File.ReadAllText(scriptPath)));
|
PythonScripts.Add(new PythonScript(File.ReadAllText(scriptPath)));
|
||||||
else if (Path.GetExtension(scriptPath) == ".ps1")
|
else if (Path.GetExtension(scriptPath) == ".ps1")
|
||||||
@@ -142,60 +165,61 @@ namespace mpvnet
|
|||||||
|
|
||||||
//Debug.WriteLine(evt.event_id.ToString());
|
//Debug.WriteLine(evt.event_id.ToString());
|
||||||
|
|
||||||
switch (evt.event_id)
|
try
|
||||||
{
|
{
|
||||||
case mpv_event_id.MPV_EVENT_SHUTDOWN:
|
switch (evt.event_id)
|
||||||
Shutdown?.Invoke();
|
{
|
||||||
AutoResetEvent.Set();
|
case mpv_event_id.MPV_EVENT_SHUTDOWN:
|
||||||
return;
|
Shutdown?.Invoke();
|
||||||
case mpv_event_id.MPV_EVENT_LOG_MESSAGE:
|
WriteHistory(null);
|
||||||
LogMessage?.Invoke();
|
AutoResetEvent.Set();
|
||||||
break;
|
return;
|
||||||
case mpv_event_id.MPV_EVENT_GET_PROPERTY_REPLY:
|
case mpv_event_id.MPV_EVENT_LOG_MESSAGE:
|
||||||
GetPropertyReply?.Invoke();
|
LogMessage?.Invoke();
|
||||||
break;
|
break;
|
||||||
case mpv_event_id.MPV_EVENT_SET_PROPERTY_REPLY:
|
case mpv_event_id.MPV_EVENT_GET_PROPERTY_REPLY:
|
||||||
SetPropertyReply?.Invoke();
|
GetPropertyReply?.Invoke();
|
||||||
break;
|
break;
|
||||||
case mpv_event_id.MPV_EVENT_COMMAND_REPLY:
|
case mpv_event_id.MPV_EVENT_SET_PROPERTY_REPLY:
|
||||||
CommandReply?.Invoke();
|
SetPropertyReply?.Invoke();
|
||||||
break;
|
break;
|
||||||
case mpv_event_id.MPV_EVENT_START_FILE:
|
case mpv_event_id.MPV_EVENT_COMMAND_REPLY:
|
||||||
StartFile?.Invoke();
|
CommandReply?.Invoke();
|
||||||
break;
|
break;
|
||||||
case mpv_event_id.MPV_EVENT_END_FILE:
|
case mpv_event_id.MPV_EVENT_START_FILE:
|
||||||
var end_fileData = (mpv_event_end_file)Marshal.PtrToStructure(evt.data, typeof(mpv_event_end_file));
|
StartFile?.Invoke();
|
||||||
EndFile?.Invoke((EndFileEventMode)end_fileData.reason);
|
break;
|
||||||
break;
|
case mpv_event_id.MPV_EVENT_END_FILE:
|
||||||
case mpv_event_id.MPV_EVENT_FILE_LOADED:
|
var end_fileData = (mpv_event_end_file)Marshal.PtrToStructure(evt.data, typeof(mpv_event_end_file));
|
||||||
FileLoaded?.Invoke();
|
EndFile?.Invoke((EndFileEventMode)end_fileData.reason);
|
||||||
LoadFolder();
|
break;
|
||||||
break;
|
case mpv_event_id.MPV_EVENT_FILE_LOADED:
|
||||||
case mpv_event_id.MPV_EVENT_TRACKS_CHANGED:
|
FileLoaded?.Invoke();
|
||||||
TracksChanged?.Invoke();
|
LoadFolder();
|
||||||
break;
|
break;
|
||||||
case mpv_event_id.MPV_EVENT_TRACK_SWITCHED:
|
case mpv_event_id.MPV_EVENT_TRACKS_CHANGED:
|
||||||
TrackSwitched?.Invoke();
|
TracksChanged?.Invoke();
|
||||||
break;
|
break;
|
||||||
case mpv_event_id.MPV_EVENT_IDLE:
|
case mpv_event_id.MPV_EVENT_TRACK_SWITCHED:
|
||||||
Idle?.Invoke();
|
TrackSwitched?.Invoke();
|
||||||
break;
|
break;
|
||||||
case mpv_event_id.MPV_EVENT_PAUSE:
|
case mpv_event_id.MPV_EVENT_IDLE:
|
||||||
Pause?.Invoke();
|
Idle?.Invoke();
|
||||||
break;
|
break;
|
||||||
case mpv_event_id.MPV_EVENT_UNPAUSE:
|
case mpv_event_id.MPV_EVENT_PAUSE:
|
||||||
Unpause?.Invoke();
|
Pause?.Invoke();
|
||||||
break;
|
break;
|
||||||
case mpv_event_id.MPV_EVENT_TICK:
|
case mpv_event_id.MPV_EVENT_UNPAUSE:
|
||||||
Tick?.Invoke();
|
Unpause?.Invoke();
|
||||||
break;
|
break;
|
||||||
case mpv_event_id.MPV_EVENT_SCRIPT_INPUT_DISPATCH:
|
case mpv_event_id.MPV_EVENT_TICK:
|
||||||
ScriptInputDispatch?.Invoke();
|
Tick?.Invoke();
|
||||||
break;
|
break;
|
||||||
case mpv_event_id.MPV_EVENT_CLIENT_MESSAGE:
|
case mpv_event_id.MPV_EVENT_SCRIPT_INPUT_DISPATCH:
|
||||||
if (ClientMessage != null)
|
ScriptInputDispatch?.Invoke();
|
||||||
{
|
break;
|
||||||
try
|
case mpv_event_id.MPV_EVENT_CLIENT_MESSAGE:
|
||||||
|
if (ClientMessage != null)
|
||||||
{
|
{
|
||||||
var client_messageData = (mpv_event_client_message)Marshal.PtrToStructure(evt.data, typeof(mpv_event_client_message));
|
var client_messageData = (mpv_event_client_message)Marshal.PtrToStructure(evt.data, typeof(mpv_event_client_message));
|
||||||
string[] args = NativeUtf8StrArray2ManagedStrArray(client_messageData.args, client_messageData.num_args);
|
string[] args = NativeUtf8StrArray2ManagedStrArray(client_messageData.args, client_messageData.num_args);
|
||||||
@@ -216,61 +240,76 @@ namespace mpvnet
|
|||||||
{
|
{
|
||||||
List<string> names = mpvnet.Command.Commands.Select((item) => item.Name).ToList();
|
List<string> names = mpvnet.Command.Commands.Select((item) => item.Name).ToList();
|
||||||
names.Sort();
|
names.Sort();
|
||||||
MainForm.Instance.ShowMsgBox($"No command '{args[1]}' found. Available commands are:\n\n{string.Join("\n", names)}\n\nHow to bind these commands can be seen in the default input bindings and menu definition located at:\n\nhttps://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt", MessageBoxIcon.Error);
|
Msg.ShowError($"No command '{args[1]}' found.", $"Available commands are:\n\n{string.Join("\n", names)}\n\nHow to bind these commands can be seen in the [https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt default input bindings and menu definition].");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClientMessage?.Invoke(args);
|
ClientMessage?.Invoke(args);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
break;
|
||||||
|
case mpv_event_id.MPV_EVENT_VIDEO_RECONFIG:
|
||||||
|
VideoReconfig?.Invoke();
|
||||||
|
break;
|
||||||
|
case mpv_event_id.MPV_EVENT_AUDIO_RECONFIG:
|
||||||
|
AudioReconfig?.Invoke();
|
||||||
|
break;
|
||||||
|
case mpv_event_id.MPV_EVENT_METADATA_UPDATE:
|
||||||
|
MetadataUpdate?.Invoke();
|
||||||
|
break;
|
||||||
|
case mpv_event_id.MPV_EVENT_SEEK:
|
||||||
|
Seek?.Invoke();
|
||||||
|
break;
|
||||||
|
case mpv_event_id.MPV_EVENT_PROPERTY_CHANGE:
|
||||||
|
var propData = (mpv_event_property)Marshal.PtrToStructure(evt.data, typeof(mpv_event_property));
|
||||||
|
|
||||||
|
if (propData.format == mpv_format.MPV_FORMAT_FLAG)
|
||||||
|
foreach (var i in BoolPropChangeActions)
|
||||||
|
if (i.Key== propData.name)
|
||||||
|
i.Value.Invoke(Marshal.PtrToStructure<int>(propData.data) == 1);
|
||||||
|
|
||||||
|
if (propData.format == mpv_format.MPV_FORMAT_STRING)
|
||||||
|
foreach (var i in StringPropChangeActions)
|
||||||
|
if (i.Key == propData.name)
|
||||||
|
i.Value.Invoke(StringFromNativeUtf8(Marshal.PtrToStructure<IntPtr>(propData.data)));
|
||||||
|
|
||||||
|
if (propData.format == mpv_format.MPV_FORMAT_INT64)
|
||||||
|
foreach (var i in IntPropChangeActions)
|
||||||
|
if (i.Key == propData.name)
|
||||||
|
i.Value.Invoke(Marshal.PtrToStructure<int>(propData.data));
|
||||||
|
break;
|
||||||
|
case mpv_event_id.MPV_EVENT_PLAYBACK_RESTART:
|
||||||
|
PlaybackRestart?.Invoke();
|
||||||
|
Size s = new Size(get_property_int("dwidth"), get_property_int("dheight"));
|
||||||
|
|
||||||
|
if (VideoSize != s && s != Size.Empty)
|
||||||
{
|
{
|
||||||
MainForm.Instance.ShowMsgBox(ex.GetType().Name + "\n\n" + ex.ToString(), MessageBoxIcon.Error);
|
VideoSize = s;
|
||||||
|
VideoSizeChanged?.Invoke();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
|
||||||
case mpv_event_id.MPV_EVENT_VIDEO_RECONFIG:
|
|
||||||
VideoReconfig?.Invoke();
|
|
||||||
break;
|
|
||||||
case mpv_event_id.MPV_EVENT_AUDIO_RECONFIG:
|
|
||||||
AudioReconfig?.Invoke();
|
|
||||||
break;
|
|
||||||
case mpv_event_id.MPV_EVENT_METADATA_UPDATE:
|
|
||||||
MetadataUpdate?.Invoke();
|
|
||||||
break;
|
|
||||||
case mpv_event_id.MPV_EVENT_SEEK:
|
|
||||||
Seek?.Invoke();
|
|
||||||
break;
|
|
||||||
case mpv_event_id.MPV_EVENT_PROPERTY_CHANGE:
|
|
||||||
var event_propertyData = (mpv_event_property)Marshal.PtrToStructure(evt.data, typeof(mpv_event_property));
|
|
||||||
|
|
||||||
if (event_propertyData.format == mpv_format.MPV_FORMAT_FLAG)
|
Task.Run(new Action(() => {
|
||||||
foreach (var i in BoolPropChangeActions)
|
WriteHistory(mp.get_property_string("path"));
|
||||||
if (i.Key== event_propertyData.name)
|
ReadMetaData();
|
||||||
i.Value.Invoke(Marshal.PtrToStructure<int>(event_propertyData.data) == 1);
|
}));
|
||||||
break;
|
break;
|
||||||
case mpv_event_id.MPV_EVENT_PLAYBACK_RESTART:
|
case mpv_event_id.MPV_EVENT_CHAPTER_CHANGE:
|
||||||
PlaybackRestart?.Invoke();
|
ChapterChange?.Invoke();
|
||||||
Size s = new Size(get_property_int("dwidth"), get_property_int("dheight"));
|
break;
|
||||||
|
case mpv_event_id.MPV_EVENT_QUEUE_OVERFLOW:
|
||||||
if (VideoSize != s && s != Size.Empty)
|
QueueOverflow?.Invoke();
|
||||||
{
|
break;
|
||||||
VideoSize = s;
|
case mpv_event_id.MPV_EVENT_HOOK:
|
||||||
VideoSizeChanged?.Invoke();
|
Hook?.Invoke();
|
||||||
}
|
break;
|
||||||
break;
|
}
|
||||||
case mpv_event_id.MPV_EVENT_CHAPTER_CHANGE:
|
}
|
||||||
ChapterChange?.Invoke();
|
catch (Exception ex)
|
||||||
break;
|
{
|
||||||
case mpv_event_id.MPV_EVENT_QUEUE_OVERFLOW:
|
Msg.ShowException(ex);
|
||||||
QueueOverflow?.Invoke();
|
|
||||||
break;
|
|
||||||
case mpv_event_id.MPV_EVENT_HOOK:
|
|
||||||
Hook?.Invoke();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<PythonEventObject> PythonEventObjects = new List<PythonEventObject>();
|
static List<PythonEventObject> PythonEventObjects = new List<PythonEventObject>();
|
||||||
|
|
||||||
public static void register_event(string name, PyRT.PythonFunction pyFunc)
|
public static void register_event(string name, PyRT.PythonFunction pyFunc)
|
||||||
{
|
{
|
||||||
@@ -353,15 +392,23 @@ namespace mpvnet
|
|||||||
|
|
||||||
public static string get_property_string(string name, bool throwOnException = false)
|
public static string get_property_string(string name, bool throwOnException = false)
|
||||||
{
|
{
|
||||||
int err = mpv_get_property(MpvHandle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_STRING, out IntPtr lpBuffer);
|
try
|
||||||
|
{
|
||||||
|
int err = mpv_get_property(MpvHandle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_STRING, out IntPtr lpBuffer);
|
||||||
|
|
||||||
if (err < 0 && throwOnException)
|
if (err < 0 && throwOnException)
|
||||||
throw new Exception($"{name}: {(mpv_error)err}");
|
throw new Exception($"{name}: {(mpv_error)err}");
|
||||||
|
|
||||||
var ret = StringFromNativeUtf8(lpBuffer);
|
string ret = StringFromNativeUtf8(lpBuffer);
|
||||||
mpv_free(lpBuffer);
|
mpv_free(lpBuffer);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (throwOnException) throw ex;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int get_property_int(string name, bool throwOnException = false)
|
public static int get_property_int(string name, bool throwOnException = false)
|
||||||
@@ -404,6 +451,16 @@ namespace mpvnet
|
|||||||
throw new Exception($"{name}: {(mpv_error)err}");
|
throw new Exception($"{name}: {(mpv_error)err}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void observe_property_int(string name, Action<int> action)
|
||||||
|
{
|
||||||
|
int err = mpv_observe_property(MpvHandle, (ulong)action.GetHashCode(), name, mpv_format.MPV_FORMAT_INT64);
|
||||||
|
|
||||||
|
if (err < 0)
|
||||||
|
throw new Exception($"{name}: {(mpv_error)err}");
|
||||||
|
else
|
||||||
|
IntPropChangeActions.Add(new KeyValuePair<string, Action<int>>(name, action));
|
||||||
|
}
|
||||||
|
|
||||||
public static void observe_property_bool(string name, Action<bool> action)
|
public static void observe_property_bool(string name, Action<bool> action)
|
||||||
{
|
{
|
||||||
int err = mpv_observe_property(MpvHandle, (ulong)action.GetHashCode(), name, mpv_format.MPV_FORMAT_FLAG);
|
int err = mpv_observe_property(MpvHandle, (ulong)action.GetHashCode(), name, mpv_format.MPV_FORMAT_FLAG);
|
||||||
@@ -414,16 +471,14 @@ namespace mpvnet
|
|||||||
BoolPropChangeActions.Add(new KeyValuePair<string, Action<bool>>(name, action));
|
BoolPropChangeActions.Add(new KeyValuePair<string, Action<bool>>(name, action));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void unobserve_property_bool(string name, Action<bool> action)
|
public static void observe_property_string(string name, Action<string> action)
|
||||||
{
|
{
|
||||||
foreach (var i in BoolPropChangeActions.ToArray())
|
int err = mpv_observe_property(MpvHandle, (ulong)action.GetHashCode(), name, mpv_format.MPV_FORMAT_STRING);
|
||||||
if (i.Value == action)
|
|
||||||
BoolPropChangeActions.Remove(i);
|
|
||||||
|
|
||||||
int err = mpv_unobserve_property(MpvHandle, (ulong)action.GetHashCode());
|
|
||||||
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
throw new Exception($"{name}: {(mpv_error)err}");
|
throw new Exception($"{name}: {(mpv_error)err}");
|
||||||
|
else
|
||||||
|
StringPropChangeActions.Add(new KeyValuePair<string, Action<string>>(name, action));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void ProcessCommandLine()
|
protected static void ProcessCommandLine()
|
||||||
@@ -478,9 +533,9 @@ namespace mpvnet
|
|||||||
mp.LoadFolder();
|
mp.LoadFolder();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool WasFolderLoaded;
|
static bool WasFolderLoaded;
|
||||||
|
|
||||||
public static void LoadFolder()
|
static void LoadFolder()
|
||||||
{
|
{
|
||||||
if (WasFolderLoaded)
|
if (WasFolderLoaded)
|
||||||
return;
|
return;
|
||||||
@@ -489,6 +544,7 @@ namespace mpvnet
|
|||||||
{
|
{
|
||||||
string[] types = "264 265 3gp aac ac3 avc avi avs bmp divx dts dtshd dtshr dtsma eac3 evo flac flv h264 h265 hevc hvc jpg jpeg m2t m2ts m2v m4a m4v mka mkv mlp mov mp2 mp3 mp4 mpa mpeg mpg mpv mts ogg ogm opus pcm png pva raw rmvb thd thd+ac3 true-hd truehd ts vdr vob vpy w64 wav webm wmv y4m".Split(' ');
|
string[] types = "264 265 3gp aac ac3 avc avi avs bmp divx dts dtshd dtshr dtsma eac3 evo flac flv h264 h265 hevc hvc jpg jpeg m2t m2ts m2v m4a m4v mka mkv mlp mov mp2 mp3 mp4 mpa mpeg mpg mpv mts ogg ogm opus pcm png pva raw rmvb thd thd+ac3 true-hd truehd ts vdr vob vpy w64 wav webm wmv y4m".Split(' ');
|
||||||
string path = get_property_string("path");
|
string path = get_property_string("path");
|
||||||
|
if (!Directory.Exists(Path.GetDirectoryName(path))) return;
|
||||||
List<string> files = Directory.GetFiles(Path.GetDirectoryName(path)).ToList();
|
List<string> files = Directory.GetFiles(Path.GetDirectoryName(path)).ToList();
|
||||||
files = files.Where((file) => types.Contains(Path.GetExtension(file).TrimStart(".".ToCharArray()).ToLower())).ToList();
|
files = files.Where((file) => types.Contains(Path.GetExtension(file).TrimStart(".".ToCharArray()).ToLower())).ToList();
|
||||||
files.Sort(new StringLogicalComparer());
|
files.Sort(new StringLogicalComparer());
|
||||||
@@ -505,7 +561,7 @@ namespace mpvnet
|
|||||||
WasFolderLoaded = true;
|
WasFolderLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IntPtr AllocateUtf8IntPtrArrayWithSentinel(string[] arr, out IntPtr[] byteArrayPointers)
|
static IntPtr AllocateUtf8IntPtrArrayWithSentinel(string[] arr, out IntPtr[] byteArrayPointers)
|
||||||
{
|
{
|
||||||
int numberOfStrings = arr.Length + 1; // add extra element for extra null pointer last (sentinel)
|
int numberOfStrings = arr.Length + 1; // add extra element for extra null pointer last (sentinel)
|
||||||
byteArrayPointers = new IntPtr[numberOfStrings];
|
byteArrayPointers = new IntPtr[numberOfStrings];
|
||||||
@@ -523,7 +579,7 @@ namespace mpvnet
|
|||||||
return rootPointer;
|
return rootPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string[] NativeUtf8StrArray2ManagedStrArray(IntPtr pUnmanagedStringArray, int StringCount)
|
static string[] NativeUtf8StrArray2ManagedStrArray(IntPtr pUnmanagedStringArray, int StringCount)
|
||||||
{
|
{
|
||||||
IntPtr[] pIntPtrArray = new IntPtr[StringCount];
|
IntPtr[] pIntPtrArray = new IntPtr[StringCount];
|
||||||
string[] ManagedStringArray = new string[StringCount];
|
string[] ManagedStringArray = new string[StringCount];
|
||||||
@@ -535,7 +591,7 @@ namespace mpvnet
|
|||||||
return ManagedStringArray;
|
return ManagedStringArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string StringFromNativeUtf8(IntPtr nativeUtf8)
|
static string StringFromNativeUtf8(IntPtr nativeUtf8)
|
||||||
{
|
{
|
||||||
int len = 0;
|
int len = 0;
|
||||||
while (Marshal.ReadByte(nativeUtf8, len) != 0) ++len;
|
while (Marshal.ReadByte(nativeUtf8, len) != 0) ++len;
|
||||||
@@ -544,7 +600,124 @@ namespace mpvnet
|
|||||||
return Encoding.UTF8.GetString(buffer);
|
return Encoding.UTF8.GetString(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] GetUtf8Bytes(string s) => Encoding.UTF8.GetBytes(s + "\0");
|
static byte[] GetUtf8Bytes(string s) => Encoding.UTF8.GetBytes(s + "\0");
|
||||||
|
|
||||||
|
static string LastHistoryPath;
|
||||||
|
static DateTime LastHistoryStartDateTime;
|
||||||
|
|
||||||
|
static void WriteHistory(string filePath)
|
||||||
|
{
|
||||||
|
int totalMinutes = Convert.ToInt32((DateTime.Now - LastHistoryStartDateTime).TotalMinutes);
|
||||||
|
|
||||||
|
if (File.Exists(LastHistoryPath) && totalMinutes > 1)
|
||||||
|
{
|
||||||
|
string historyFilepath = mp.MpvConfFolderPath + "history.txt";
|
||||||
|
|
||||||
|
File.AppendAllText(historyFilepath, DateTime.Now.ToString().Substring(0, 16) +
|
||||||
|
" " + totalMinutes.ToString().PadLeft(3) + " " +
|
||||||
|
Path.GetFileNameWithoutExtension(LastHistoryPath) + "\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
LastHistoryPath = filePath;
|
||||||
|
LastHistoryStartDateTime = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ReadMetaData()
|
||||||
|
{
|
||||||
|
lock (MediaTracks)
|
||||||
|
{
|
||||||
|
MediaTracks.Clear();
|
||||||
|
|
||||||
|
using (MediaInfo mi = new MediaInfo(mp.get_property_string("path")))
|
||||||
|
{
|
||||||
|
int count = mi.GetCount(MediaInfoStreamKind.Video);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
MediaTrack track = new MediaTrack();
|
||||||
|
Add(track, mi.GetVideo(i, "Format"));
|
||||||
|
Add(track, mi.GetVideo(i, "Format_Profile"));
|
||||||
|
Add(track, mi.GetVideo(i, "Width") + "x" + mi.GetVideo(i, "Height"));
|
||||||
|
Add(track, mi.GetVideo(i, "FrameRate") + " FPS");
|
||||||
|
Add(track, mi.GetVideo(i, "Language/String"));
|
||||||
|
Add(track, mi.GetVideo(i, "Forced") == "Yes" ? "Forced" : "");
|
||||||
|
Add(track, mi.GetVideo(i, "Default") == "Yes" ? "Default" : "");
|
||||||
|
Add(track, mi.GetVideo(i, "Title"));
|
||||||
|
track.Text = "V: " + track.Text.Trim(" ,".ToCharArray());
|
||||||
|
track.Type = "v";
|
||||||
|
track.ID = i + 1;
|
||||||
|
MediaTracks.Add(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
count = mi.GetCount(MediaInfoStreamKind.Audio);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
MediaTrack track = new MediaTrack();
|
||||||
|
Add(track, mi.GetAudio(i, "Language/String"));
|
||||||
|
Add(track, mi.GetAudio(i, "Format"));
|
||||||
|
Add(track, mi.GetAudio(i, "Format_Profile"));
|
||||||
|
Add(track, mi.GetAudio(i, "BitRate/String"));
|
||||||
|
Add(track, mi.GetAudio(i, "Channel(s)/String"));
|
||||||
|
Add(track, mi.GetAudio(i, "SamplingRate/String"));
|
||||||
|
Add(track, mi.GetAudio(i, "Forced") == "Yes" ? "Forced" : "");
|
||||||
|
Add(track, mi.GetAudio(i, "Default") == "Yes" ? "Default" : "");
|
||||||
|
Add(track, mi.GetAudio(i, "Title"));
|
||||||
|
track.Text = "A: " + track.Text.Trim(" ,".ToCharArray());
|
||||||
|
track.Type = "a";
|
||||||
|
track.ID = i + 1;
|
||||||
|
MediaTracks.Add(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
count = mi.GetCount(MediaInfoStreamKind.Text);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
MediaTrack track = new MediaTrack();
|
||||||
|
Add(track, mi.GetText(i, "Language/String"));
|
||||||
|
Add(track, mi.GetText(i, "Format"));
|
||||||
|
Add(track, mi.GetText(i, "Format_Profile"));
|
||||||
|
Add(track, mi.GetText(i, "Forced") == "Yes" ? "Forced" : "");
|
||||||
|
Add(track, mi.GetText(i, "Default") == "Yes" ? "Default" : "");
|
||||||
|
Add(track, mi.GetText(i, "Title"));
|
||||||
|
track.Text = "S: " + track.Text.Trim(" ,".ToCharArray());
|
||||||
|
track.Type = "s";
|
||||||
|
track.ID = i + 1;
|
||||||
|
MediaTracks.Add(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
count = get_property_int("edition-list/count");
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
MediaTrack track = new MediaTrack();
|
||||||
|
track.Text = "E: " + get_property_string($"edition-list/{i}/title");
|
||||||
|
track.Type = "e";
|
||||||
|
track.ID = i;
|
||||||
|
MediaTracks.Add(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Add(MediaTrack track, string val)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(val) && !(track.Text != null && track.Text.Contains(val)))
|
||||||
|
track.Text += " " + val + ",";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (Chapters)
|
||||||
|
{
|
||||||
|
Chapters.Clear();
|
||||||
|
int count = get_property_int("chapter-list/count");
|
||||||
|
|
||||||
|
for (int x = 0; x < count; x++)
|
||||||
|
{
|
||||||
|
string text = get_property_string($"chapter-list/{x}/title");
|
||||||
|
double time = get_property_number($"chapter-list/{x}/time");
|
||||||
|
Chapters.Add(new KeyValuePair<string, double>(text, time));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum EndFileEventMode
|
public enum EndFileEventMode
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
<GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>
|
<GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>
|
||||||
|
<LangVersion>7.3</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
@@ -168,6 +169,9 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<None Include="..\README.md">
|
||||||
|
<Link>README.md</Link>
|
||||||
|
</None>
|
||||||
<None Include="app.manifest" />
|
<None Include="app.manifest" />
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
<None Include="Properties\Settings.settings">
|
<None Include="Properties\Settings.settings">
|
||||||
@@ -189,7 +193,12 @@
|
|||||||
<Content Include="screenshot.jpg" />
|
<Content Include="screenshot.jpg" />
|
||||||
<Content Include="Resources\input.conf.txt" />
|
<Content Include="Resources\input.conf.txt" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\VBNET\VBNET.vbproj">
|
||||||
|
<Project>{a1d11294-05bf-4d77-b008-aecf1aa93c9f}</Project>
|
||||||
|
<Name>VBNET</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Application x:Class="DynamicGUI.App"
|
<Application x:Class="mpvConfEdit.App"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:local="clr-namespace:DynamicGUI"
|
xmlns:Controls="clr-namespace:Controls"
|
||||||
StartupUri="MainWindow.xaml">
|
StartupUri="MainWindow.xaml">
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
<Style TargetType="TextBox">
|
<Style TargetType="TextBox">
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
<Setter Property="BorderBrush" TargetName="border" Value="#FF7EB4EA"/>
|
<Setter Property="BorderBrush" TargetName="border" Value="#FF7EB4EA"/>
|
||||||
</Trigger>
|
</Trigger>
|
||||||
<Trigger Property="IsFocused" Value="true">
|
<Trigger Property="IsFocused" Value="true">
|
||||||
<Setter Property="BorderBrush" TargetName="border" Value="{x:Static SystemParameters.WindowGlassBrush}"/>
|
<Setter Property="BorderBrush" TargetName="border" Value="{x:Static Controls:Controls.ThemeBrush}"/>
|
||||||
</Trigger>
|
</Trigger>
|
||||||
</ControlTemplate.Triggers>
|
</ControlTemplate.Triggers>
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
namespace DynamicGUI
|
namespace mpvConfEdit
|
||||||
{
|
{
|
||||||
public partial class App : Application
|
public partial class App : Application
|
||||||
{
|
{
|
||||||
|
|||||||
18
mpvConfEdit/Controls.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace Controls
|
||||||
|
{
|
||||||
|
class Controls
|
||||||
|
{
|
||||||
|
public static Brush ThemeBrush {
|
||||||
|
get {
|
||||||
|
if (Environment.OSVersion.Version.Major < 10)
|
||||||
|
return new SolidColorBrush(Colors.DimGray);
|
||||||
|
else
|
||||||
|
return SystemParameters.WindowGlassBrush;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ namespace DynamicGUI
|
|||||||
baseSetting = optionSetting;
|
baseSetting = optionSetting;
|
||||||
optionSetting.Default = setting["default"];
|
optionSetting.Default = setting["default"];
|
||||||
optionSetting.Value = optionSetting.Default;
|
optionSetting.Value = optionSetting.Default;
|
||||||
|
optionSetting.StartValue = optionSetting.Default;
|
||||||
|
|
||||||
foreach (TomlTable option in setting["options"])
|
foreach (TomlTable option in setting["options"])
|
||||||
{
|
{
|
||||||
@@ -54,7 +55,6 @@ namespace DynamicGUI
|
|||||||
baseSetting.Filter = setting["filter"];
|
baseSetting.Filter = setting["filter"];
|
||||||
if (setting.HasKey("help")) baseSetting.Help = setting["help"];
|
if (setting.HasKey("help")) baseSetting.Help = setting["help"];
|
||||||
if (setting.HasKey("helpurl")) baseSetting.HelpURL = setting["helpurl"];
|
if (setting.HasKey("helpurl")) baseSetting.HelpURL = setting["helpurl"];
|
||||||
if (setting.HasKey("alias")) baseSetting.Alias = setting["alias"];
|
|
||||||
if (setting.HasKey("width")) baseSetting.Width = setting["width"];
|
if (setting.HasKey("width")) baseSetting.Width = setting["width"];
|
||||||
settingsList.Add(baseSetting);
|
settingsList.Add(baseSetting);
|
||||||
}
|
}
|
||||||
@@ -65,8 +65,10 @@ namespace DynamicGUI
|
|||||||
public abstract class SettingBase
|
public abstract class SettingBase
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Alias { get; set; }
|
public string Value { get; set; }
|
||||||
|
public string StartValue { get; set; }
|
||||||
public string Help { get; set; }
|
public string Help { get; set; }
|
||||||
|
public string Default { get; set; }
|
||||||
public string HelpURL { get; set; }
|
public string HelpURL { get; set; }
|
||||||
public string Filter { get; set; }
|
public string Filter { get; set; }
|
||||||
public int Width { get; set; }
|
public int Width { get; set; }
|
||||||
@@ -74,15 +76,11 @@ namespace DynamicGUI
|
|||||||
|
|
||||||
public class StringSetting : SettingBase
|
public class StringSetting : SettingBase
|
||||||
{
|
{
|
||||||
public string Default { get; set; }
|
|
||||||
public string Value { get; set; }
|
|
||||||
public bool IsFolder { get; set; }
|
public bool IsFolder { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OptionSetting : SettingBase
|
public class OptionSetting : SettingBase
|
||||||
{
|
{
|
||||||
public string Default { get; set; }
|
|
||||||
public string Value { get; set; }
|
|
||||||
public List<OptionSettingOption> Options = new List<OptionSettingOption>();
|
public List<OptionSettingOption> Options = new List<OptionSettingOption>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,18 +8,18 @@
|
|||||||
d:DesignHeight="450" d:DesignWidth="800">
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
<Grid Margin="20,0">
|
<Grid Margin="20,0">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBox x:Name="TitleTextBox" FontSize="24" Margin="0,10" BorderThickness="0" IsReadOnly="True" Foreground="{x:Static SystemParameters.WindowGlassBrush}"></TextBox>
|
<TextBox x:Name="TitleTextBox" FontSize="24" Margin="0,10" BorderThickness="0" IsReadOnly="True" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"></TextBox>
|
||||||
<ItemsControl x:Name="ItemsControl">
|
<ItemsControl x:Name="ItemsControl">
|
||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<WrapPanel Orientation="Vertical">
|
<WrapPanel Orientation="Vertical">
|
||||||
<RadioButton x:Name="RadioButton" VerticalContentAlignment="Center" IsChecked="{Binding IsChecked}" GroupName="{Binding OptionSetting.Name}" Content="{Binding Text}" FontSize="16" FontWeight="Normal" VerticalAlignment="Top"></RadioButton>
|
<RadioButton x:Name="RadioButton" VerticalContentAlignment="Center" IsChecked="{Binding IsChecked}" GroupName="{Binding OptionSetting.Name}" Content="{Binding Text}" FontSize="16" FontWeight="Normal" VerticalAlignment="Top" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"></RadioButton>
|
||||||
<TextBox x:Name="ItemHelpTextBox" TextWrapping="WrapWithOverflow" Text="{Binding Help}" Margin="10,0,0,0" BorderThickness="0" IsReadOnly="True" Padding="7,0,0,0" MinHeight="0"></TextBox>
|
<TextBox x:Name="ItemHelpTextBox" TextWrapping="WrapWithOverflow" Text="{Binding Help}" Margin="10,0,0,0" BorderThickness="0" IsReadOnly="True" Padding="7,0,0,0" MinHeight="0" Foreground="{Binding Path=Foreground2, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"></TextBox>
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
<TextBox x:Name="HelpTextBox" TextWrapping="WrapWithOverflow" BorderThickness="0" IsReadOnly="True" Margin="0,10,0,0"></TextBox>
|
<TextBox x:Name="HelpTextBox" TextWrapping="WrapWithOverflow" BorderThickness="0" IsReadOnly="True" Margin="0,10,0,0" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"></TextBox>
|
||||||
<TextBlock x:Name="LinkTextBlock" Margin="0,10">
|
<TextBlock x:Name="LinkTextBlock" Margin="0,10">
|
||||||
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx>
|
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ namespace DynamicGUI
|
|||||||
HelpTextBox.Text = optionSetting.Help;
|
HelpTextBox.Text = optionSetting.Help;
|
||||||
ItemsControl.ItemsSource = optionSetting.Options;
|
ItemsControl.ItemsSource = optionSetting.Options;
|
||||||
Link.SetURL(optionSetting.HelpURL);
|
Link.SetURL(optionSetting.HelpURL);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(optionSetting.HelpURL))
|
if (string.IsNullOrEmpty(optionSetting.HelpURL))
|
||||||
LinkTextBlock.Visibility = Visibility.Collapsed;
|
LinkTextBlock.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,16 +9,16 @@
|
|||||||
d:DesignWidth="800" >
|
d:DesignWidth="800" >
|
||||||
<Grid Margin="20,0">
|
<Grid Margin="20,0">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBox x:Name="TitleTextBox" FontSize="24" Margin="0,10" BorderThickness="0" IsReadOnly="True" Foreground="{x:Static SystemParameters.WindowGlassBrush}"></TextBox>
|
<TextBox x:Name="TitleTextBox" FontSize="24" Margin="0,10" BorderThickness="0" IsReadOnly="True" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"></TextBox>
|
||||||
<Grid Margin="0,0,0,10">
|
<Grid Margin="0,0,0,10">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBox x:Name="ValueTextBox" Text="{Binding Path=Text, ElementName=StringSettingControl1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="150" HorizontalAlignment="Left" Height="20"/>
|
<TextBox x:Name="ValueTextBox" Text="{Binding Path=Text, ElementName=StringSettingControl1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="150" HorizontalAlignment="Left" Height="20" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"/>
|
||||||
<Button x:Name="Button" Height="20" Grid.Column="1" Visibility="{Binding Path=Text, ElementName=StringSettingControl1}" Margin="5,0,0,0" Width="20" Click="Button_Click">...</Button>
|
<Button x:Name="Button" Height="20" Grid.Column="1" Visibility="{Binding Path=Text, ElementName=StringSettingControl1}" Margin="5,0,0,0" Width="20" Click="Button_Click">...</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
<TextBox x:Name="HelpTextBox" TextWrapping="WrapWithOverflow" Margin="0,0,0,10" BorderThickness="0" IsReadOnly="True"></TextBox>
|
<TextBox x:Name="HelpTextBox" TextWrapping="WrapWithOverflow" Margin="0,0,0,10" BorderThickness="0" IsReadOnly="True" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"></TextBox>
|
||||||
<TextBlock x:Name="LinkTextBlock" Margin="0,10">
|
<TextBlock x:Name="LinkTextBlock" Margin="0,10">
|
||||||
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx>
|
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ namespace DynamicGUI
|
|||||||
if (!StringSetting.IsFolder)
|
if (!StringSetting.IsFolder)
|
||||||
Button.Visibility = Visibility.Hidden;
|
Button.Visibility = Visibility.Hidden;
|
||||||
Link.SetURL(StringSetting.HelpURL);
|
Link.SetURL(StringSetting.HelpURL);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(stringSetting.HelpURL))
|
if (string.IsNullOrEmpty(stringSetting.HelpURL))
|
||||||
LinkTextBlock.Visibility = Visibility.Collapsed;
|
LinkTextBlock.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Height="500" Width="700" Loaded="MainWindow1_Loaded">
|
Height="500" Width="700" Loaded="MainWindow1_Loaded" WindowStartupLocation="CenterScreen">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
@@ -14,12 +14,12 @@
|
|||||||
<ColumnDefinition Width="10*" />
|
<ColumnDefinition Width="10*" />
|
||||||
<ColumnDefinition Width="60*" />
|
<ColumnDefinition Width="60*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Controls:SearchTextBoxUserControl x:Name="SearchControl" Width="300" Margin="0,0,0,10" Grid.ColumnSpan="2" />
|
<Controls:SearchTextBoxUserControl x:Name="SearchControl" Width="250" Margin="0,20,0,10" Grid.ColumnSpan="2" />
|
||||||
<ScrollViewer x:Name="MainScrollViewer" VerticalScrollBarVisibility="Auto" Grid.Row="1" Grid.Column="1">
|
<ScrollViewer x:Name="MainScrollViewer" VerticalScrollBarVisibility="Auto" Grid.Row="1" Grid.Column="1" Margin="0,0,0,10">
|
||||||
<StackPanel x:Name="MainStackPanel"></StackPanel>
|
<StackPanel x:Name="MainStackPanel"></StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
<StackPanel Margin="20,0,0,0" Grid.Row="1">
|
<StackPanel Margin="20,0,0,0" Grid.Row="1">
|
||||||
<ListBox x:Name="FilterListBox" ItemsSource="{Binding FilterStrings}" BorderThickness="0" SelectionChanged="ListBox_SelectionChanged" Foreground="{x:Static SystemParameters.WindowGlassBrush}">
|
<ListBox x:Name="FilterListBox" ItemsSource="{Binding FilterStrings}" BorderThickness="0" SelectionChanged="ListBox_SelectionChanged" Foreground="{x:Static Controls:Controls.ThemeBrush}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
@@ -28,9 +28,10 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
<TextBlock x:Name="OpenSettingsTextBlock" Margin="0,30,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static SystemParameters.WindowGlassBrush}" MouseUp="OpenSettingsTextBlock_MouseUp">Open settings folder</TextBlock>
|
<TextBlock x:Name="OpenSettingsTextBlock" Margin="0,30,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static Controls:Controls.ThemeBrush}" MouseUp="OpenSettingsTextBlock_MouseUp">Open config folder</TextBlock>
|
||||||
<TextBlock x:Name="ShowManualTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static SystemParameters.WindowGlassBrush}" MouseUp="ShowManualTextBlock_MouseUp">Show mpv manual</TextBlock>
|
<TextBlock x:Name="ShowManualTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static Controls:Controls.ThemeBrush}" MouseUp="ShowManualTextBlock_MouseUp">Show mpv manual</TextBlock>
|
||||||
<TextBlock x:Name="SupportTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static SystemParameters.WindowGlassBrush}" MouseUp="SupportTextBlock_MouseUp">Show support forum</TextBlock>
|
<TextBlock x:Name="SupportTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static Controls:Controls.ThemeBrush}" MouseUp="SupportTextBlock_MouseUp">Show support forum</TextBlock>
|
||||||
|
<TextBlock x:Name="ApplyTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static Controls:Controls.ThemeBrush}" MouseUp="ApplyTextBlock_MouseUp">Write config to disk</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
@@ -8,15 +8,21 @@ using System.Reflection;
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
using DynamicGUI;
|
using DynamicGUI;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
|
||||||
namespace mpvConfEdit
|
namespace mpvConfEdit
|
||||||
{
|
{
|
||||||
public partial class MainWindow : Window
|
public partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
public string mpvConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpv.conf";
|
public string MpvConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpv.conf";
|
||||||
private List<SettingBase> DynamicSettings = Settings.LoadSettings(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\mpvConfEdit.toml");
|
public string MpvNetConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpvnet.conf";
|
||||||
|
private List<SettingBase> MpvSettingsDefinitions = Settings.LoadSettings(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\mpvConf.toml");
|
||||||
|
private List<SettingBase> MpvNetSettingsDefinitions = Settings.LoadSettings(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\mpvNetConf.toml");
|
||||||
|
public ObservableCollection<string> FilterStrings { get; } = new ObservableCollection<string>();
|
||||||
|
private Dictionary<string, Dictionary<string, string>> Comments = new Dictionary<string, Dictionary<string, string>>();
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
@@ -24,31 +30,65 @@ namespace mpvConfEdit
|
|||||||
DataContext = this;
|
DataContext = this;
|
||||||
Title = (Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), true)[0] as AssemblyProductAttribute).Product + " " + Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
Title = (Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), true)[0] as AssemblyProductAttribute).Product + " " + Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||||
SearchControl.SearchTextBox.TextChanged += SearchTextBox_TextChanged;
|
SearchControl.SearchTextBox.TextChanged += SearchTextBox_TextChanged;
|
||||||
|
LoadSettings(MpvSettingsDefinitions, MpvConf);
|
||||||
|
LoadSettings(MpvNetSettingsDefinitions, MpvNetConf);
|
||||||
|
SearchControl.Text = (string)Registry.GetValue(@"HKEY_CURRENT_USER\Software\mpv.net", "conf editor search", "");
|
||||||
|
SetDarkTheme();
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var setting in DynamicSettings)
|
public Brush Foreground2 {
|
||||||
|
get { return (Brush)GetValue(Foreground2Property); }
|
||||||
|
set { SetValue(Foreground2Property, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty Foreground2Property =
|
||||||
|
DependencyProperty.Register("Foreground2", typeof(Brush), typeof(MainWindow), new PropertyMetadata(Brushes.DarkSlateGray));
|
||||||
|
|
||||||
|
void SetDarkTheme()
|
||||||
|
{
|
||||||
|
string darkMode = MpvNetSettingsDefinitions.Where(item => item.Name == "dark-mode").First().Value;
|
||||||
|
|
||||||
|
object value = Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", "AppsUseLightTheme", 1);
|
||||||
|
if (value is null) value = 1;
|
||||||
|
bool isDarkTheme = (int)value == 0;
|
||||||
|
|
||||||
|
if (!((darkMode == "system" && isDarkTheme) || darkMode == "always"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Foreground = Brushes.White;
|
||||||
|
Foreground2 = Brushes.Silver;
|
||||||
|
Background = Brushes.Black;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadSettings(List<SettingBase> settingsDefinitions,
|
||||||
|
Dictionary<string, string> confSettings)
|
||||||
|
{
|
||||||
|
foreach (var setting in settingsDefinitions)
|
||||||
{
|
{
|
||||||
if (!FilterStrings.Contains(setting.Filter))
|
if (!FilterStrings.Contains(setting.Filter))
|
||||||
FilterStrings.Add(setting.Filter);
|
FilterStrings.Add(setting.Filter);
|
||||||
foreach (var pair in mpvConf)
|
|
||||||
|
foreach (var pair in confSettings)
|
||||||
{
|
{
|
||||||
if (setting.Name == pair.Key || setting.Alias == pair.Key)
|
if (setting.Name == pair.Key)
|
||||||
switch (setting)
|
{
|
||||||
{
|
setting.Value = pair.Value;
|
||||||
case StringSetting s:
|
setting.StartValue = pair.Value;
|
||||||
s.Value = pair.Value;
|
continue;
|
||||||
continue;
|
}
|
||||||
case OptionSetting s:
|
|
||||||
s.Value = pair.Value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (setting)
|
switch (setting)
|
||||||
{
|
{
|
||||||
case StringSetting s:
|
case StringSetting s:
|
||||||
MainStackPanel.Children.Add(new StringSettingControl(s));
|
var sc = new StringSettingControl(s);
|
||||||
|
sc.TitleTextBox.Foreground = Controls.Controls.ThemeBrush;
|
||||||
|
MainStackPanel.Children.Add(sc);
|
||||||
break;
|
break;
|
||||||
case OptionSetting s:
|
case OptionSetting s:
|
||||||
MainStackPanel.Children.Add(new OptionSettingControl(s));
|
var oc = new OptionSettingControl(s);
|
||||||
|
oc.TitleTextBox.Foreground = Controls.Controls.ThemeBrush;
|
||||||
|
MainStackPanel.Children.Add(oc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,105 +96,107 @@ namespace mpvConfEdit
|
|||||||
|
|
||||||
private Dictionary<string, string> _mpvConf;
|
private Dictionary<string, string> _mpvConf;
|
||||||
|
|
||||||
public Dictionary<string, string> mpvConf {
|
public Dictionary<string, string> MpvConf {
|
||||||
get {
|
get {
|
||||||
if (_mpvConf == null)
|
if (_mpvConf == null) _mpvConf = LoadConf(MpvConfPath);
|
||||||
{
|
|
||||||
_mpvConf = new Dictionary<string, string>();
|
|
||||||
|
|
||||||
if (File.Exists(mpvConfPath))
|
|
||||||
foreach (var i in File.ReadAllLines(mpvConfPath))
|
|
||||||
if (i.Contains("=") && !i.Trim().StartsWith("#"))
|
|
||||||
{
|
|
||||||
int pos = i.IndexOf("=");
|
|
||||||
_mpvConf[i.Substring(0, pos).Trim()] = i.Substring(pos + 1).Trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _mpvConf;
|
return _mpvConf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableCollection<string> FilterStrings { get; } = new ObservableCollection<string>();
|
private Dictionary<string, string> _mpvNetConf;
|
||||||
|
|
||||||
|
public Dictionary<string, string> MpvNetConf {
|
||||||
|
get {
|
||||||
|
if (_mpvNetConf == null) _mpvNetConf = LoadConf(MpvNetConfPath);
|
||||||
|
return _mpvNetConf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, string> LoadConf(string filePath)
|
||||||
|
{
|
||||||
|
Dictionary<string, string> conf = new Dictionary<string, string>();
|
||||||
|
Comments[filePath] = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
if (File.Exists(filePath))
|
||||||
|
{
|
||||||
|
foreach (string i in File.ReadAllLines(filePath))
|
||||||
|
{
|
||||||
|
if (i.Contains("="))
|
||||||
|
{
|
||||||
|
int pos = i.IndexOf("=");
|
||||||
|
string left = i.Substring(0, pos).Replace(" ", "").ToLower();
|
||||||
|
string right = i.Substring(pos + 1).Trim();
|
||||||
|
|
||||||
|
if (left.StartsWith("#"))
|
||||||
|
{
|
||||||
|
Comments[filePath][left.TrimStart("#".ToCharArray())] = right;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left == "fs") left = "fullscreen";
|
||||||
|
if (left == "loop") left = "loop-file";
|
||||||
|
conf[left] = right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return conf;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnClosed(EventArgs e)
|
protected override void OnClosed(EventArgs e)
|
||||||
{
|
{
|
||||||
base.OnClosed(e);
|
base.OnClosed(e);
|
||||||
|
WriteToDisk();
|
||||||
|
Registry.SetValue(@"HKEY_CURRENT_USER\Software\mpv.net", "conf editor search", SearchControl.Text);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var mpvSetting in DynamicSettings)
|
void WriteToDisk()
|
||||||
|
{
|
||||||
|
bool isDirty = false;
|
||||||
|
|
||||||
|
foreach (SettingBase i in MpvSettingsDefinitions)
|
||||||
|
if (i.StartValue != i.Value)
|
||||||
|
isDirty = true;
|
||||||
|
|
||||||
|
foreach (SettingBase i in MpvNetSettingsDefinitions)
|
||||||
|
if (i.StartValue != i.Value)
|
||||||
|
isDirty = true;
|
||||||
|
|
||||||
|
if (!isDirty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
WriteToDisk(MpvConfPath, MpvConf, MpvSettingsDefinitions);
|
||||||
|
WriteToDisk(MpvNetConfPath, MpvNetConf, MpvNetSettingsDefinitions);
|
||||||
|
|
||||||
|
MessageBox.Show("Changes will be available on next startup of mpv(.net).",
|
||||||
|
Title, MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteToDisk(string filePath,
|
||||||
|
Dictionary<string, string> confSettings,
|
||||||
|
List<SettingBase> settings)
|
||||||
|
{
|
||||||
|
string content = "";
|
||||||
|
|
||||||
|
foreach (var i in Comments[filePath])
|
||||||
|
content += $"#{i.Key} = {i.Value}\r\n";
|
||||||
|
|
||||||
|
foreach (var setting in settings)
|
||||||
{
|
{
|
||||||
switch (mpvSetting)
|
if ((setting.Value ?? "") != setting.Default)
|
||||||
|
confSettings[setting.Name] = setting.Value;
|
||||||
|
|
||||||
|
if (confSettings.ContainsKey(setting.Name) &&
|
||||||
|
(setting.Value ?? "") == setting.Default ||
|
||||||
|
(setting.Value ?? "") == "")
|
||||||
{
|
{
|
||||||
case StringSetting s:
|
confSettings.Remove(setting.Name);
|
||||||
if ((s.Value ?? "") != s.Default)
|
|
||||||
mpvConf[s.Name] = s.Value;
|
|
||||||
else
|
|
||||||
mpvConf.Remove(s.Name);
|
|
||||||
break;
|
|
||||||
case OptionSetting s:
|
|
||||||
if ((s.Value ?? "") != s.Default)
|
|
||||||
mpvConf[s.Name] = s.Value;
|
|
||||||
else
|
|
||||||
mpvConf.Remove(s.Name);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!File.Exists(mpvConfPath))
|
foreach (var i in confSettings)
|
||||||
File.WriteAllText(mpvConfPath, "");
|
content = content + $"{i.Key} = {i.Value}\r\n";
|
||||||
|
|
||||||
List<string> lines = File.ReadAllLines(mpvConfPath).ToList();
|
File.WriteAllText(filePath, content);
|
||||||
|
|
||||||
foreach (var mpvSetting in DynamicSettings)
|
|
||||||
{
|
|
||||||
foreach (var line in lines.ToArray())
|
|
||||||
{
|
|
||||||
string test = line.Replace("#", "").Replace(" ", "");
|
|
||||||
if (test.StartsWith(mpvSetting.Alias + "="))
|
|
||||||
{
|
|
||||||
lines.Remove(line);
|
|
||||||
foreach (var pair in mpvConf.ToArray())
|
|
||||||
if (test.StartsWith(pair.Key + "="))
|
|
||||||
mpvConf.Remove(pair.Key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var pair in mpvConf)
|
|
||||||
{
|
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < lines.Count; i++)
|
|
||||||
{
|
|
||||||
if (lines[i].Contains("=") &&
|
|
||||||
lines[i].Substring(0, lines[i].IndexOf("=")).Trim("# ".ToCharArray()) == pair.Key)
|
|
||||||
{
|
|
||||||
lines[i] = pair.Key + " = " + pair.Value;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!changed)
|
|
||||||
lines.Add(pair.Key + " = " + pair.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var mpvSetting in DynamicSettings)
|
|
||||||
{
|
|
||||||
foreach (var line in lines.ToArray())
|
|
||||||
{
|
|
||||||
string test = line.Replace("#", "").Replace(" ", "");
|
|
||||||
|
|
||||||
if (test.StartsWith(mpvSetting.Name + "=") && !mpvConf.ContainsKey(mpvSetting.Name))
|
|
||||||
lines.Remove(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
File.WriteAllText(mpvConfPath, String.Join(Environment.NewLine, lines));
|
|
||||||
|
|
||||||
foreach (Process process in Process.GetProcesses())
|
|
||||||
if (process.ProcessName == "mpvnet")
|
|
||||||
MessageBox.Show("Restart mpv.net in order to apply changed settings.", Title, MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
else if (process.ProcessName == "mpv")
|
|
||||||
MessageBox.Show("Restart mpv in order to apply changed settings.", Title, MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||||
@@ -187,6 +229,7 @@ namespace mpvConfEdit
|
|||||||
|
|
||||||
private void MainWindow1_Loaded(object sender, RoutedEventArgs e)
|
private void MainWindow1_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
SearchControl.SearchTextBox.SelectAll();
|
||||||
Keyboard.Focus(SearchControl.SearchTextBox);
|
Keyboard.Focus(SearchControl.SearchTextBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +241,7 @@ namespace mpvConfEdit
|
|||||||
|
|
||||||
private void OpenSettingsTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
|
private void OpenSettingsTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
Process.Start(Path.GetDirectoryName(mpvConfPath));
|
Process.Start(Path.GetDirectoryName(MpvConfPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowManualTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
|
private void ShowManualTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
|
||||||
@@ -210,5 +253,10 @@ namespace mpvConfEdit
|
|||||||
{
|
{
|
||||||
Process.Start("https://github.com/stax76/mpv.net#Support");
|
Process.Start("https://github.com/stax76/mpv.net#Support");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ApplyTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
WriteToDisk();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,7 @@ using System.Windows;
|
|||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("")]
|
||||||
[assembly: AssemblyProduct("mpv(.net) conf edit")]
|
[assembly: AssemblyProduct("mpv(.net) conf edit")]
|
||||||
[assembly: AssemblyCopyright("Copyright © stax76")]
|
[assembly: AssemblyCopyright("Copyright © 2017-2019 stax76")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
@@ -51,5 +51,5 @@ using System.Windows;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("1.1.0.0")]
|
[assembly: AssemblyVersion("1.8.0.0")]
|
||||||
[assembly: AssemblyFileVersion("1.1.0.0")]
|
[assembly: AssemblyFileVersion("1.8.0.0")]
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800">
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
<Grid x:Name="SearchTextBoxUserControl1" Background="White">
|
<Grid x:Name="SearchTextBoxUserControl1" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
|
||||||
<TextBlock x:Name="SearchTextBlock" Margin="5,2" Text="Find a setting" Foreground="LightSteelBlue" VerticalAlignment="Center" />
|
<TextBlock x:Name="HintTextBlock" Margin="5,2" Text="Find a setting" Foreground="LightSteelBlue" VerticalAlignment="Center" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" />
|
||||||
<TextBox Name="SearchTextBox" Height="25" Padding="1,2,0,0" BorderThickness="2" Background="Transparent" TextChanged="SearchTextBox_TextChanged" />
|
<TextBox Name="SearchTextBox" Height="25" Padding="1,2,0,0" BorderThickness="2" Background="Transparent" TextChanged="SearchTextBox_TextChanged" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" CaretBrush="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" />
|
||||||
<Button x:Name="SearchClearButton" Background="Transparent" HorizontalAlignment="Right" Margin="2,0,4,0" FontSize="5" Width="17" Height="17" Visibility="Hidden" Click="SearchClearButton_Click">╳</Button>
|
<Button x:Name="SearchClearButton" Background="Transparent" HorizontalAlignment="Right" Margin="2,0,4,0" FontSize="10" Width="17" Height="17" Visibility="Hidden" Click="SearchClearButton_Click" FontFamily="Marlett" Foreground="{Binding Path=Foreground2, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">r</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@@ -21,7 +21,7 @@ namespace Controls
|
|||||||
|
|
||||||
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||||
{
|
{
|
||||||
SearchTextBlock.Text = SearchTextBox.Text == "" ? "Find a setting" : "";
|
HintTextBlock.Text = SearchTextBox.Text == "" ? "Find a setting" : "";
|
||||||
|
|
||||||
if (SearchTextBox.Text == "")
|
if (SearchTextBox.Text == "")
|
||||||
SearchClearButton.Visibility = Visibility.Hidden;
|
SearchClearButton.Visibility = Visibility.Hidden;
|
||||||
|
|||||||
38
mpvConfEdit/app.manifest
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<!--
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||||
|
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||||
|
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
||||||
|
-->
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<!-- Windows 7 -->
|
||||||
|
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
|
||||||
|
|
||||||
|
<!-- Windows 8 -->
|
||||||
|
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
|
||||||
|
|
||||||
|
<!-- Windows 8.1 -->
|
||||||
|
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
|
||||||
|
|
||||||
|
<!-- Windows 10 -->
|
||||||
|
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
|
||||||
|
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<windowsSettings>
|
||||||
|
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||||
|
</windowsSettings>
|
||||||
|
</application>
|
||||||
|
</assembly>
|
||||||
@@ -19,6 +19,28 @@ options = [{ name = "no", help = "always use software decoding (Defaul
|
|||||||
{ name = "crystalhd", help = "copies video back to system RAM (Any platform supported by hardware)" },
|
{ name = "crystalhd", help = "copies video back to system RAM (Any platform supported by hardware)" },
|
||||||
{ name = "rkmpp", help = "requires --vo=gpu (some RockChip devices only)" }]
|
{ name = "rkmpp", help = "requires --vo=gpu (some RockChip devices only)" }]
|
||||||
|
|
||||||
|
[[settings]]
|
||||||
|
name = "gpu-api"
|
||||||
|
default = "auto"
|
||||||
|
filter = "Video"
|
||||||
|
help = "--gpu-api=<type> Controls which type of graphics APIs will be accepted."
|
||||||
|
options = [{ name = "auto", help = "Use any available API (Default)" },
|
||||||
|
{ name = "opengl", help = "Allow only OpenGL (requires OpenGL 2.1+ or GLES 2.0+)" },
|
||||||
|
{ name = "vulkan", help = "Allow only Vulkan (requires a valid/working --spirv-compiler)" },
|
||||||
|
{ name = "d3d11", help = "Allow only --gpu-context=d3d11" }]
|
||||||
|
|
||||||
|
[[settings]]
|
||||||
|
name = "gpu-context"
|
||||||
|
default = "auto"
|
||||||
|
filter = "Video"
|
||||||
|
help = "--gpu-context=<sys> The value auto (the default) selects the GPU context. You can also pass help to get a complete list of compiled in backends (sorted by autoprobe order)."
|
||||||
|
options = [{ name = "auto", help = "auto-select (Default)" },
|
||||||
|
{ name = "win", help = "Win32/WGL" },
|
||||||
|
{ name = "winvk", help = "VK_KHR_win32_surface" },
|
||||||
|
{ name = "angle", help = "Direct3D11 through the OpenGL ES translation layer ANGLE. This supports almost everything the win backend does (if the ANGLE build is new enough)." },
|
||||||
|
{ name = "dxinterop", help = "(experimental) Win32, using WGL for rendering and Direct3D 9Ex for presentation. Works on Nvidia and AMD. Newer Intel chips with the latest drivers may also work." },
|
||||||
|
{ name = "d3d11", help = "Win32, with native Direct3D 11 rendering." }]
|
||||||
|
|
||||||
[[settings]]
|
[[settings]]
|
||||||
name = "vo"
|
name = "vo"
|
||||||
default = "gpu"
|
default = "gpu"
|
||||||
@@ -28,18 +50,134 @@ help = "--gpu=<mode> Video output drivers to be used. Default = gpu.\n\nFor more
|
|||||||
options = [{ name = "gpu", help = "General purpose, customizable, GPU-accelerated video output driver. It supports extended scaling methods, dithering, color management, custom shaders, HDR, and more. (Default)" },
|
options = [{ name = "gpu", help = "General purpose, customizable, GPU-accelerated video output driver. It supports extended scaling methods, dithering, color management, custom shaders, HDR, and more. (Default)" },
|
||||||
{ name = "direct3d", help = "Video output driver that uses the Direct3D interface" }]
|
{ name = "direct3d", help = "Video output driver that uses the Direct3D interface" }]
|
||||||
|
|
||||||
|
[[settings]]
|
||||||
|
name = "video-sync"
|
||||||
|
default = "audio"
|
||||||
|
filter = "Video"
|
||||||
|
help = "--video-sync=<audio|...> How the player synchronizes audio and video.\n\nFor more information visit:"
|
||||||
|
helpurl = "https://mpv.io/manual/master/#options-video-sync"
|
||||||
|
options = [{ name = "audio" },
|
||||||
|
{ name = "display-resample" },
|
||||||
|
{ name = "display-resample-vdrop" },
|
||||||
|
{ name = "display-resample-desync" },
|
||||||
|
{ name = "display-vdrop" },
|
||||||
|
{ name = "display-adrop" },
|
||||||
|
{ name = "display-desync" },
|
||||||
|
{ name = "desync" }]
|
||||||
|
|
||||||
|
[[settings]]
|
||||||
|
name = "scale"
|
||||||
|
default = "bilinear"
|
||||||
|
filter = "Video"
|
||||||
|
help = "--scale=<filter> The GPU renderer filter function to use when upscaling video. There are some more filters, but most are not as useful. For a complete list, pass help as value, e.g.: mpv --scale=help"
|
||||||
|
options = [{ name = "bilinear", help = "Bilinear hardware texture filtering (fastest, very low quality). This is the default for compatibility reasons." },
|
||||||
|
{ name = "spline36", help = "Mid quality and speed. This is the default when using gpu-hq." },
|
||||||
|
{ name = "lanczos", help = "Lanczos scaling. Provides mid quality and speed. Generally worse than spline36, but it results in a slightly sharper image which is good for some content types. The number of taps can be controlled with scale-radius, but is best left unchanged. (This filter is an alias for sinc-windowed sinc)" },
|
||||||
|
{ name = "ewa_lanczos", help = "Elliptic weighted average Lanczos scaling. Also known as Jinc. Relatively slow, but very good quality. The radius can be controlled with scale-radius. Increasing the radius makes the filter sharper but adds more ringing. (This filter is an alias for jinc-windowed jinc)" },
|
||||||
|
{ name = "ewa_lanczossharp", help = "A slightly sharpened version of ewa_lanczos, preconfigured to use an ideal radius and parameter. If your hardware can run it, this is probably what you should use by default." },
|
||||||
|
{ name = "mitchell", help = "Mitchell-Netravali. The B and C parameters can be set with --scale-param1 and --scale-param2. This filter is very good at downscaling (see --dscale)." },
|
||||||
|
{ name = "oversample", help = "A version of nearest neighbour that (naively) oversamples pixels, so that pixels overlapping edges get linearly interpolated instead of rounded. This essentially removes the small imperfections and judder artifacts caused by nearest-neighbour interpolation, in exchange for adding some blur. This filter is good at temporal interpolation, and also known as \"smoothmotion\" (see --tscale)." },
|
||||||
|
{ name = "linear", help = "A --tscale filter." }]
|
||||||
|
|
||||||
|
[[settings]]
|
||||||
|
name = "cscale"
|
||||||
|
default = "bilinear"
|
||||||
|
filter = "Video"
|
||||||
|
help = "--cscale=<filter> As --scale, but for interpolating chroma information. If the image is not subsampled, this option is ignored entirely."
|
||||||
|
options = [{ name = "bilinear", help = "Bilinear hardware texture filtering (fastest, very low quality). This is the default for compatibility reasons." },
|
||||||
|
{ name = "spline36", help = "Mid quality and speed. This is the default when using gpu-hq." },
|
||||||
|
{ name = "lanczos", help = "Lanczos scaling. Provides mid quality and speed. Generally worse than spline36, but it results in a slightly sharper image which is good for some content types. The number of taps can be controlled with scale-radius, but is best left unchanged. (This filter is an alias for sinc-windowed sinc)" },
|
||||||
|
{ name = "ewa_lanczos", help = "Elliptic weighted average Lanczos scaling. Also known as Jinc. Relatively slow, but very good quality. The radius can be controlled with scale-radius. Increasing the radius makes the filter sharper but adds more ringing. (This filter is an alias for jinc-windowed jinc)" },
|
||||||
|
{ name = "ewa_lanczossharp", help = "A slightly sharpened version of ewa_lanczos, preconfigured to use an ideal radius and parameter. If your hardware can run it, this is probably what you should use by default." },
|
||||||
|
{ name = "mitchell", help = "Mitchell-Netravali. The B and C parameters can be set with --scale-param1 and --scale-param2. This filter is very good at downscaling (see --dscale)." },
|
||||||
|
{ name = "oversample", help = "A version of nearest neighbour that (naively) oversamples pixels, so that pixels overlapping edges get linearly interpolated instead of rounded. This essentially removes the small imperfections and judder artifacts caused by nearest-neighbour interpolation, in exchange for adding some blur. This filter is good at temporal interpolation, and also known as \"smoothmotion\" (see --tscale)." },
|
||||||
|
{ name = "linear", help = "A --tscale filter." }]
|
||||||
|
|
||||||
|
[[settings]]
|
||||||
|
name = "dscale"
|
||||||
|
default = "bilinear"
|
||||||
|
filter = "Video"
|
||||||
|
help = "--dscale=<filter> Like --scale, but apply these filters on downscaling instead. If this option is unset, the filter implied by --scale will be applied."
|
||||||
|
options = [{ name = "bilinear", help = "Bilinear hardware texture filtering (fastest, very low quality). This is the default for compatibility reasons." },
|
||||||
|
{ name = "spline36", help = "Mid quality and speed. This is the default when using gpu-hq." },
|
||||||
|
{ name = "lanczos", help = "Lanczos scaling. Provides mid quality and speed. Generally worse than spline36, but it results in a slightly sharper image which is good for some content types. The number of taps can be controlled with scale-radius, but is best left unchanged. (This filter is an alias for sinc-windowed sinc)" },
|
||||||
|
{ name = "ewa_lanczos", help = "Elliptic weighted average Lanczos scaling. Also known as Jinc. Relatively slow, but very good quality. The radius can be controlled with scale-radius. Increasing the radius makes the filter sharper but adds more ringing. (This filter is an alias for jinc-windowed jinc)" },
|
||||||
|
{ name = "ewa_lanczossharp", help = "A slightly sharpened version of ewa_lanczos, preconfigured to use an ideal radius and parameter. If your hardware can run it, this is probably what you should use by default." },
|
||||||
|
{ name = "mitchell", help = "Mitchell-Netravali. The B and C parameters can be set with --scale-param1 and --scale-param2. This filter is very good at downscaling (see --dscale)." },
|
||||||
|
{ name = "oversample", help = "A version of nearest neighbour that (naively) oversamples pixels, so that pixels overlapping edges get linearly interpolated instead of rounded. This essentially removes the small imperfections and judder artifacts caused by nearest-neighbour interpolation, in exchange for adding some blur. This filter is good at temporal interpolation, and also known as \"smoothmotion\" (see --tscale)." },
|
||||||
|
{ name = "linear", help = "A --tscale filter." }]
|
||||||
|
|
||||||
|
[[settings]]
|
||||||
|
name = "dither-depth"
|
||||||
|
default = "no"
|
||||||
|
filter = "Video"
|
||||||
|
help = "--dither-depth=<N|no|auto> Set dither target depth to N. Default: no. Note that the depth of the connected video display device cannot be detected. Often, LCD panels will do dithering on their own, which conflicts with this option and leads to ugly output."
|
||||||
|
options = [{ name = "no", help = "Disable any dithering done by mpv." },
|
||||||
|
{ name = "auto", help = "Automatic selection. If output bit depth cannot be detected, 8 bits per component are assumed." },
|
||||||
|
{ name = "8", help = "Dither to 8 bit output." }]
|
||||||
|
|
||||||
|
[[settings]]
|
||||||
|
name = "correct-downscaling"
|
||||||
|
default = "no"
|
||||||
|
filter = "Video"
|
||||||
|
help = "--correct-downscaling When using convolution based filters, extend the filter size when downscaling. Increases quality, but reduces performance while downscaling.\n\nThis will perform slightly sub-optimally for anamorphic video (but still better than without it) since it will extend the size to match only the milder of the scale factors between the axes."
|
||||||
|
options = [{ name = "yes" },
|
||||||
|
{ name = "no" }]
|
||||||
|
|
||||||
|
[[settings]]
|
||||||
|
name = "sigmoid-upscaling"
|
||||||
|
default = "no"
|
||||||
|
filter = "Video"
|
||||||
|
help = "--sigmoid-upscaling When upscaling, use a sigmoidal color transform to avoid emphasizing ringing artifacts. This also implies --linear-scaling."
|
||||||
|
options = [{ name = "yes" },
|
||||||
|
{ name = "no" }]
|
||||||
|
|
||||||
|
[[settings]]
|
||||||
|
name = "deband"
|
||||||
|
default = "no"
|
||||||
|
filter = "Video"
|
||||||
|
help = "--deband Enable the debanding algorithm. This greatly reduces the amount of visible banding, blocking and other quantization artifacts, at the expense of very slightly blurring some of the finest details. In practice, it's virtually always an improvement - the only reason to disable it would be for performance."
|
||||||
|
options = [{ name = "yes" },
|
||||||
|
{ name = "no" }]
|
||||||
|
|
||||||
[[settings]]
|
[[settings]]
|
||||||
name = "volume"
|
name = "volume"
|
||||||
default = "100"
|
default = "100"
|
||||||
filter = "Audio"
|
filter = "Audio"
|
||||||
help = "--volume=<integer> Set the startup volume. 0 means silence, 100 means no volume reduction or amplification. Negative values can be passed for compatibility, but are treated as 0. Since mpv 0.18.1, this always controls the internal mixer (aka \"softvol\"). Default: 100"
|
help = "--volume=<integer> Set the startup volume. 0 means silence, 100 means no volume reduction or amplification. Negative values can be passed for compatibility, but are treated as 0. Since mpv 0.18.1, this always controls the internal mixer (aka \"softvol\"). Default: 100"
|
||||||
|
|
||||||
|
[[settings]]
|
||||||
|
name = "alang"
|
||||||
|
default = ""
|
||||||
|
filter = "Audio"
|
||||||
|
help = "--alang=<languagecode[,languagecode,...]> Specify a priority list of audio languages to use. Different container formats employ different language codes. DVDs use ISO 639-1 two-letter language codes, Matroska, MPEG-TS and NUT use ISO 639-2 three-letter language codes, while OGM uses a free-form identifier. See also --aid.\n\nExamples\n\nmpv dvd://1 --alang=hu,en chooses the Hungarian language track on a DVD and falls back on English if Hungarian is not available.\n\nmpv --alang=jpn example.mkv plays a Matroska file with Japanese audio."
|
||||||
|
|
||||||
|
[[settings]]
|
||||||
|
name = "audio-file-auto"
|
||||||
|
default = "no"
|
||||||
|
filter = "Audio"
|
||||||
|
help = "--audio-file-auto=<no|exact|fuzzy|all>, --no-audio-file-auto Load additional audio files matching the video filename. The parameter specifies how external audio files are matched."
|
||||||
|
options = [{ name = "no", help = "Don't automatically load external audio files (default)." },
|
||||||
|
{ name = "exact", help = "Load the media filename with audio file extension." },
|
||||||
|
{ name = "fuzzy", help = "Load all audio files containing media filename." },
|
||||||
|
{ name = "all", help = "Load all audio files in the current and --audio-file-paths directories." }]
|
||||||
|
|
||||||
[[settings]]
|
[[settings]]
|
||||||
name = "slang"
|
name = "slang"
|
||||||
default = ""
|
default = ""
|
||||||
filter = "Subtitle"
|
filter = "Subtitle"
|
||||||
help = "--slang=<languagecode[,languagecode,...]> Specify a priority list of subtitle languages to use. Different container formats employ different language codes. DVDs use ISO 639-1 two letter language codes, Matroska uses ISO 639-2 three letter language codes while OGM uses a free-form identifier. See also --sid."
|
help = "--slang=<languagecode[,languagecode,...]> Specify a priority list of subtitle languages to use. Different container formats employ different language codes. DVDs use ISO 639-1 two letter language codes, Matroska uses ISO 639-2 three letter language codes while OGM uses a free-form identifier. See also --sid."
|
||||||
|
|
||||||
|
[[settings]]
|
||||||
|
name = "sub-auto"
|
||||||
|
default = "exact"
|
||||||
|
filter = "Subtitle"
|
||||||
|
help = "--sub-auto=<no|exact|fuzzy|all>, --no-sub-auto Load additional subtitle files matching the video filename. The parameter specifies how external subtitle files are matched. exact is enabled by default."
|
||||||
|
options = [{ name = "no", help = "Don't automatically load external subtitle files." },
|
||||||
|
{ name = "exact", help = "Load the media filename with subtitle file extension (Default)." },
|
||||||
|
{ name = "fuzzy", help = "Load all subs containing media filename." },
|
||||||
|
{ name = "all", help = "Load all subs in the current and --sub-file-paths directories." }]
|
||||||
|
|
||||||
[[settings]]
|
[[settings]]
|
||||||
name = "screen"
|
name = "screen"
|
||||||
default = ""
|
default = ""
|
||||||
@@ -51,18 +189,31 @@ name = "osd-playing-msg"
|
|||||||
default = ""
|
default = ""
|
||||||
width = 300
|
width = 300
|
||||||
filter = "Screen"
|
filter = "Screen"
|
||||||
help = "--osd-playing-msg=<value> Show a message on OSD when playback starts. The string is expanded for properties, e.g. --osd-playing-msg='file: ${filename}' will show the message file: followed by a space and the currently played filename.\n\nFor more information visit:"
|
help = "--osd-playing-msg=<value> Show a message on OSD when playback starts. The string is expanded for properties, e.g. --osd-playing-msg='file: ${filename}' will show the message file: followed by a space and the currently played filename. For more information visit:"
|
||||||
helpurl = "https://mpv.io/manual/master/#property-expansion"
|
helpurl = "https://mpv.io/manual/master/#property-expansion"
|
||||||
|
|
||||||
[[settings]]
|
[[settings]]
|
||||||
name = "fullscreen"
|
name = "fullscreen"
|
||||||
alias = "fs"
|
|
||||||
default = "no"
|
default = "no"
|
||||||
filter = "Screen"
|
filter = "Screen"
|
||||||
help = "--fullscreen=<yes|no>, fs=<yes|no> Start the player in fullscreen mode. Default: no."
|
help = "--fullscreen=<yes|no>, fs=<yes|no> Start the player in fullscreen mode. Default: no."
|
||||||
options = [{ name = "yes" },
|
options = [{ name = "yes" },
|
||||||
{ name = "no" }]
|
{ name = "no" }]
|
||||||
|
|
||||||
|
[[settings]]
|
||||||
|
name = "screenshot-directory"
|
||||||
|
default = ""
|
||||||
|
width = 500
|
||||||
|
folder = true
|
||||||
|
filter = "Screen"
|
||||||
|
help = "--screenshot-directory=<value> Store screenshots in this directory. This path is joined with the filename generated by --screenshot-template. If the template filename is already absolute, the directory is ignored.\n\nIf the directory does not exist, it is created on the first screenshot. If it is not a directory, an error is generated when trying to write a screenshot.\n\nThis option is not set by default, and thus will write screenshots to the directory from which mpv was started. In pseudo-gui mode (see PSEUDO GUI MODE), this is set to the desktop."
|
||||||
|
|
||||||
|
[[settings]]
|
||||||
|
name = "autofit"
|
||||||
|
default = "50%"
|
||||||
|
filter = "Screen"
|
||||||
|
help = "--autofit=<percent value> Set the initial window size in percent. Please note that this setting is only partly implemented in mpv.net, accepted are only integer values with percent sign added. Default: 50%."
|
||||||
|
|
||||||
[[settings]]
|
[[settings]]
|
||||||
name = "keep-open-pause"
|
name = "keep-open-pause"
|
||||||
default = "yes"
|
default = "yes"
|
||||||
@@ -82,7 +233,6 @@ options = [{ name = "yes", help = "Don't terminate if the current file is the
|
|||||||
|
|
||||||
[[settings]]
|
[[settings]]
|
||||||
name = "loop-file"
|
name = "loop-file"
|
||||||
alias = "loop"
|
|
||||||
default = ""
|
default = ""
|
||||||
filter = "Playback"
|
filter = "Playback"
|
||||||
help = "--loop-file=<N|inf|no>, loop=<N|inf|no> Loop a single file N times. inf means forever, no means normal playback. For compatibility, --loop-file and --loop-file=yes are also accepted, and are the same as --loop-file=inf.\n\nThe difference to --loop-playlist is that this doesn't loop the playlist, just the file itself. If the playlist contains only a single file, the difference between the two option is that this option performs a seek on loop, instead of reloading the file.\n\n--loop is an alias for this option."
|
help = "--loop-file=<N|inf|no>, loop=<N|inf|no> Loop a single file N times. inf means forever, no means normal playback. For compatibility, --loop-file and --loop-file=yes are also accepted, and are the same as --loop-file=inf.\n\nThe difference to --loop-playlist is that this doesn't loop the playlist, just the file itself. If the playlist contains only a single file, the difference between the two option is that this option performs a seek on loop, instead of reloading the file.\n\n--loop is an alias for this option."
|
||||||
@@ -95,14 +245,6 @@ help = "--save-position-on-quit=<yes|no> Always save the current playback positi
|
|||||||
options = [{ name = "yes" },
|
options = [{ name = "yes" },
|
||||||
{ name = "no" }]
|
{ name = "no" }]
|
||||||
|
|
||||||
[[settings]]
|
|
||||||
name = "screenshot-directory"
|
|
||||||
default = ""
|
|
||||||
width = 500
|
|
||||||
folder = true
|
|
||||||
filter = "Screen"
|
|
||||||
help = "--screenshot-directory=<value> Store screenshots in this directory. This path is joined with the filename generated by --screenshot-template. If the template filename is already absolute, the directory is ignored.\n\nIf the directory does not exist, it is created on the first screenshot. If it is not a directory, an error is generated when trying to write a screenshot.\n\nThis option is not set by default, and thus will write screenshots to the directory from which mpv was started. In pseudo-gui mode (see PSEUDO GUI MODE), this is set to the desktop."
|
|
||||||
|
|
||||||
[[settings]]
|
[[settings]]
|
||||||
name = "input-ar-delay"
|
name = "input-ar-delay"
|
||||||
default = ""
|
default = ""
|
||||||
@@ -115,12 +257,6 @@ default = ""
|
|||||||
filter = "Input"
|
filter = "Input"
|
||||||
help = "--input-ar-rate=<integer> Number of key presses to generate per second on autorepeat."
|
help = "--input-ar-rate=<integer> Number of key presses to generate per second on autorepeat."
|
||||||
|
|
||||||
[[settings]]
|
|
||||||
name = "alang"
|
|
||||||
default = ""
|
|
||||||
filter = "Audio"
|
|
||||||
help = "--alang=<languagecode[,languagecode,...]> Specify a priority list of audio languages to use. Different container formats employ different language codes. DVDs use ISO 639-1 two-letter language codes, Matroska, MPEG-TS and NUT use ISO 639-2 three-letter language codes, while OGM uses a free-form identifier. See also --aid.\n\nExamples\n\nmpv dvd://1 --alang=hu,en chooses the Hungarian language track on a DVD and falls back on English if Hungarian is not available.\n\nmpv --alang=jpn example.mkv plays a Matroska file with Japanese audio."
|
|
||||||
|
|
||||||
[[settings]]
|
[[settings]]
|
||||||
name = "hr-seek"
|
name = "hr-seek"
|
||||||
default = "absolute"
|
default = "absolute"
|
||||||
@@ -144,38 +280,3 @@ name = "loop-playlist"
|
|||||||
default = ""
|
default = ""
|
||||||
filter = "Playback"
|
filter = "Playback"
|
||||||
help = "--loop-playlist=<N|inf|force|no>, --loop-playlist Loops playback N times. A value of 1 plays it one time (default), 2 two times, etc. inf means forever. no is the same as 1 and disables looping. If several files are specified on command line, the entire playlist is looped. --loop-playlist is the same as --loop-playlist=inf.\n\nThe force mode is like inf, but does not skip playlist entries which have been marked as failing. This means the player might waste CPU time trying to loop a file that doesn't exist. But it might be useful for playing webradios under very bad network conditions."
|
help = "--loop-playlist=<N|inf|force|no>, --loop-playlist Loops playback N times. A value of 1 plays it one time (default), 2 two times, etc. inf means forever. no is the same as 1 and disables looping. If several files are specified on command line, the entire playlist is looped. --loop-playlist is the same as --loop-playlist=inf.\n\nThe force mode is like inf, but does not skip playlist entries which have been marked as failing. This means the player might waste CPU time trying to loop a file that doesn't exist. But it might be useful for playing webradios under very bad network conditions."
|
||||||
|
|
||||||
[[settings]]
|
|
||||||
name = "video-sync"
|
|
||||||
default = "audio"
|
|
||||||
filter = "Video"
|
|
||||||
help = "--video-sync=<audio|...> How the player synchronizes audio and video.\n\nFor more information visit:"
|
|
||||||
helpurl = "https://mpv.io/manual/master/#options-video-sync"
|
|
||||||
options = [{ name = "audio" },
|
|
||||||
{ name = "display-resample" },
|
|
||||||
{ name = "display-resample-vdrop" },
|
|
||||||
{ name = "display-resample-desync" },
|
|
||||||
{ name = "display-vdrop" },
|
|
||||||
{ name = "display-adrop" },
|
|
||||||
{ name = "display-desync" },
|
|
||||||
{ name = "desync" }]
|
|
||||||
|
|
||||||
[[settings]]
|
|
||||||
name = "audio-file-auto"
|
|
||||||
default = "no"
|
|
||||||
filter = "Audio"
|
|
||||||
help = "--audio-file-auto=<no|exact|fuzzy|all>, --no-audio-file-auto Load additional audio files matching the video filename. The parameter specifies how external audio files are matched."
|
|
||||||
options = [{ name = "no", help = "Don't automatically load external audio files (default)." },
|
|
||||||
{ name = "exact", help = "Load the media filename with audio file extension." },
|
|
||||||
{ name = "fuzzy", help = "Load all audio files containing media filename." },
|
|
||||||
{ name = "all", help = "Load all audio files in the current and --audio-file-paths directories." }]
|
|
||||||
|
|
||||||
[[settings]]
|
|
||||||
name = "sub-auto"
|
|
||||||
default = "exact"
|
|
||||||
filter = "Subtitle"
|
|
||||||
help = "--sub-auto=<no|exact|fuzzy|all>, --no-sub-auto Load additional subtitle files matching the video filename. The parameter specifies how external subtitle files are matched. exact is enabled by default."
|
|
||||||
options = [{ name = "no", help = "Don't automatically load external subtitle files." },
|
|
||||||
{ name = "exact", help = "Load the media filename with subtitle file extension (Default)." },
|
|
||||||
{ name = "fuzzy", help = "Load all subs containing media filename." },
|
|
||||||
{ name = "all", help = "Load all subs in the current and --sub-file-paths directories." }]
|
|
||||||
@@ -44,9 +44,13 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ApplicationIcon>mpv.ico</ApplicationIcon>
|
<ApplicationIcon>mpv.ico</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
@@ -66,6 +70,7 @@
|
|||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</ApplicationDefinition>
|
</ApplicationDefinition>
|
||||||
|
<Compile Include="Controls.cs" />
|
||||||
<Compile Include="DynamicGUI\DynamicGUI.cs" />
|
<Compile Include="DynamicGUI\DynamicGUI.cs" />
|
||||||
<Compile Include="DynamicGUI\OptionSettingControl.xaml.cs">
|
<Compile Include="DynamicGUI\OptionSettingControl.xaml.cs">
|
||||||
<DependentUpon>OptionSettingControl.xaml</DependentUpon>
|
<DependentUpon>OptionSettingControl.xaml</DependentUpon>
|
||||||
@@ -120,6 +125,10 @@
|
|||||||
<Generator>ResXFileCodeGenerator</Generator>
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<None Include="app.manifest" />
|
||||||
|
<None Include="mpvNetConf.toml">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
<None Include="Properties\Settings.settings">
|
<None Include="Properties\Settings.settings">
|
||||||
<Generator>SettingsSingleFileGenerator</Generator>
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||||
@@ -129,7 +138,7 @@
|
|||||||
<None Include="App.config" />
|
<None Include="App.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="mpvConfEdit.toml">
|
<None Include="mpvConf.toml">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
8
mpvConfEdit/mpvNetConf.toml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[[settings]]
|
||||||
|
name = "dark-mode"
|
||||||
|
default = "system"
|
||||||
|
filter = "mpv.net"
|
||||||
|
help = "Enables a dark theme."
|
||||||
|
options = [{ name = "always" },
|
||||||
|
{ name = "system" , help = "Windows 10+" },
|
||||||
|
{ name = "never" }]
|
||||||
@@ -1,6 +1,41 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<configuration>
|
<configuration>
|
||||||
|
<configSections>
|
||||||
|
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
|
||||||
|
<section name="mpvInputEdit.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
|
||||||
|
</sectionGroup>
|
||||||
|
</configSections>
|
||||||
<startup>
|
<startup>
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||||
</startup>
|
</startup>
|
||||||
|
<userSettings>
|
||||||
|
<mpvInputEdit.Properties.Settings>
|
||||||
|
<setting name="input_conf_help" serializeAs="String">
|
||||||
|
<value> # This file defines the input (keys and mouse) bindings of mpv and mpv.net
|
||||||
|
# and it also defines the context menu of mpv.net. mpv.net has an input
|
||||||
|
# editor and an conf editor as alternatives to editing conf text files.
|
||||||
|
# The input and conf editors can be found in mpv.net's context menu at:
|
||||||
|
|
||||||
|
# Settings > Show Config Editor
|
||||||
|
# Settings > Show Input Editor
|
||||||
|
|
||||||
|
# The defaults of this file can be found at:
|
||||||
|
|
||||||
|
# https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt
|
||||||
|
|
||||||
|
# the defaults of mpv can be found at:
|
||||||
|
|
||||||
|
# https://github.com/mpv-player/mpv/blob/master/etc/input.conf
|
||||||
|
|
||||||
|
# mpv.net's defaults of mpv.conf contain: 'input-default-bindings = no'
|
||||||
|
# which disables mpv's input defaults. Every line in this file begins with a
|
||||||
|
# space character to make it easier to do a text search, so if you want to know
|
||||||
|
# if 'o' has already a binding you can make a text search on ' o '.
|
||||||
|
|
||||||
|
# mpv input commands: https://github.com/stax76/mpv.net/wiki/mpv-input-commands
|
||||||
|
|
||||||
|
# mpv input keys: https://github.com/stax76/mpv.net/wiki/mpv-input-keys</value>
|
||||||
|
</setting>
|
||||||
|
</mpvInputEdit.Properties.Settings>
|
||||||
|
</userSettings>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<Application x:Class="mpvInputEdit.App"
|
<Application x:Class="mpvInputEdit.App"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:local="clr-namespace:mpvInputEdit"
|
xmlns:Controls="clr-namespace:Controls"
|
||||||
StartupUri="MainWindow.xaml">
|
StartupUri="MainWindow.xaml">
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
<Style TargetType="TextBox">
|
<Style TargetType="TextBox">
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
<Setter Property="BorderBrush" TargetName="border" Value="#FF7EB4EA"/>
|
<Setter Property="BorderBrush" TargetName="border" Value="#FF7EB4EA"/>
|
||||||
</Trigger>
|
</Trigger>
|
||||||
<Trigger Property="IsFocused" Value="true">
|
<Trigger Property="IsFocused" Value="true">
|
||||||
<Setter Property="BorderBrush" TargetName="border" Value="{x:Static SystemParameters.WindowGlassBrush}"/>
|
<Setter Property="BorderBrush" TargetName="border" Value="{x:Static Controls:Controls.ThemeBrush}"/>
|
||||||
</Trigger>
|
</Trigger>
|
||||||
</ControlTemplate.Triggers>
|
</ControlTemplate.Triggers>
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ namespace mpvInputEdit
|
|||||||
if (l.StartsWith("#")) continue;
|
if (l.StartsWith("#")) continue;
|
||||||
if (!l.Contains(" ")) continue;
|
if (!l.Contains(" ")) continue;
|
||||||
InputItem item = new InputItem();
|
InputItem item = new InputItem();
|
||||||
item.Key = l.Substring(0, l.IndexOf(" "));
|
item.Input = l.Substring(0, l.IndexOf(" "));
|
||||||
if (item.Key == "") continue;
|
if (item.Input == "") continue;
|
||||||
l = l.Substring(l.IndexOf(" ") + 1);
|
l = l.Substring(l.IndexOf(" ") + 1);
|
||||||
|
|
||||||
if (l.Contains("#menu:"))
|
if (l.Contains("#menu:"))
|
||||||
|
|||||||
18
mpvInputEdit/Controls.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace Controls
|
||||||
|
{
|
||||||
|
class Controls
|
||||||
|
{
|
||||||
|
public static Brush ThemeBrush {
|
||||||
|
get {
|
||||||
|
if (Environment.OSVersion.Version.Major < 10)
|
||||||
|
return new SolidColorBrush(Colors.DarkSlateGray);
|
||||||
|
else
|
||||||
|
return SystemParameters.WindowGlassBrush;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
@@ -10,7 +9,6 @@ namespace mpvInputEdit
|
|||||||
{
|
{
|
||||||
public partial class InputWindow : Window
|
public partial class InputWindow : Window
|
||||||
{
|
{
|
||||||
string InputString = "";
|
|
||||||
public InputItem InputItem { get; set; }
|
public InputItem InputItem { get; set; }
|
||||||
public string NewKey { get; set; } = "";
|
public string NewKey { get; set; } = "";
|
||||||
|
|
||||||
@@ -32,22 +30,21 @@ namespace mpvInputEdit
|
|||||||
|
|
||||||
void OnKeyUp(WF.KeyEventArgs e)
|
void OnKeyUp(WF.KeyEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.KeyCode == WF.Keys.None) return;
|
|
||||||
char c = Convert.ToChar(e.KeyCode);
|
|
||||||
string text = InputString;
|
|
||||||
|
|
||||||
if (e.KeyCode == WF.Keys.ControlKey || e.KeyCode == WF.Keys.ShiftKey ||
|
if (e.KeyCode == WF.Keys.ControlKey || e.KeyCode == WF.Keys.ShiftKey ||
|
||||||
e.KeyCode == WF.Keys.Menu)
|
e.KeyCode == WF.Keys.Menu || e.KeyCode == WF.Keys.None)
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (text == "")
|
return;
|
||||||
{
|
|
||||||
text = e.KeyCode.ToString();
|
string text = "";
|
||||||
if (text.Length == 1)
|
uint charValue = MapVirtualKey((uint)e.KeyCode, 2);
|
||||||
text = text.ToLowerInvariant();
|
|
||||||
}
|
if (charValue == 0 || (charValue & 1 << 31) == 1 << 31)
|
||||||
|
text = e.KeyCode.ToString().Trim();
|
||||||
|
else
|
||||||
|
try {
|
||||||
|
text = Convert.ToChar(charValue).ToString().ToLower().Trim();
|
||||||
|
}
|
||||||
|
catch {}
|
||||||
|
|
||||||
for (int i = 0; i < 13; i++)
|
for (int i = 0; i < 13; i++)
|
||||||
if ("D" + i.ToString() == text)
|
if ("D" + i.ToString() == text)
|
||||||
@@ -90,14 +87,6 @@ namespace mpvInputEdit
|
|||||||
text = "Esc"; break;
|
text = "Esc"; break;
|
||||||
case WF.Keys.PrintScreen:
|
case WF.Keys.PrintScreen:
|
||||||
text = "Print"; break;
|
text = "Print"; break;
|
||||||
case WF.Keys.Right:
|
|
||||||
text = "Right"; break;
|
|
||||||
case WF.Keys.Left:
|
|
||||||
text = "Left"; break;
|
|
||||||
case WF.Keys.Up:
|
|
||||||
text = "Up"; break;
|
|
||||||
case WF.Keys.Down:
|
|
||||||
text = "Down"; break;
|
|
||||||
case WF.Keys.Play:
|
case WF.Keys.Play:
|
||||||
text = "Play"; break;
|
text = "Play"; break;
|
||||||
case WF.Keys.Pause:
|
case WF.Keys.Pause:
|
||||||
@@ -130,20 +119,24 @@ namespace mpvInputEdit
|
|||||||
text = "Cancel"; break;
|
text = "Cancel"; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (text == "#")
|
bool shiftWasHandled = false;
|
||||||
text = "Sharp";
|
|
||||||
|
|
||||||
bool isAlt = GetKeyState(18) < (short)0;
|
bool isAlt = GetKeyState(18) < (short)0;
|
||||||
bool isShift = GetKeyState(16) < (short)0;
|
bool isShift = GetKeyState(16) < (short)0;
|
||||||
bool isCtrl = GetKeyState(17) < (short)0;
|
bool isCtrl = GetKeyState(17) < (short)0;
|
||||||
|
|
||||||
if (!(isAlt && isCtrl && !isShift) && !(isShift && !isAlt && !isCtrl && !int.TryParse(text.Replace("F", ""), out int value)))
|
if (text.Length == 1 && isShift && text[0] != GetModifiedKey(text[0]))
|
||||||
{
|
{
|
||||||
if (isAlt) text = "Alt+" + text;
|
text = GetModifiedKey(text[0]).ToString();
|
||||||
if (isShift) text = "Shift+" + text;
|
shiftWasHandled = true;
|
||||||
if (isCtrl) text = "Ctrl+" + text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (text == "#") text = "Sharp";
|
||||||
|
|
||||||
|
if (isAlt) text = "Alt+" + text;
|
||||||
|
if (isShift && !shiftWasHandled) text = "Shift+" + text;
|
||||||
|
if (isCtrl) text = "Ctrl+" + text;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(text))
|
if (!string.IsNullOrEmpty(text))
|
||||||
SetKey(text);
|
SetKey(text);
|
||||||
}
|
}
|
||||||
@@ -155,13 +148,8 @@ namespace mpvInputEdit
|
|||||||
KeyLabel.Content = key;
|
KeyLabel.Content = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnKeyPress(WF.KeyPressEventArgs e)
|
[DllImport("user32.dll")]
|
||||||
{
|
static extern uint MapVirtualKey(uint uCode, uint uMapType);
|
||||||
if (char.IsControl(e.KeyChar))
|
|
||||||
InputString = "";
|
|
||||||
else
|
|
||||||
InputString = e.KeyChar.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static WF.Keys ModifierKeys {
|
public static WF.Keys ModifierKeys {
|
||||||
get {
|
get {
|
||||||
@@ -176,80 +164,78 @@ namespace mpvInputEdit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static char GetModifiedKey(char c)
|
||||||
|
{
|
||||||
|
short vkKeyScanResult = VkKeyScan(c);
|
||||||
|
|
||||||
|
if (vkKeyScanResult == -1)
|
||||||
|
return c;
|
||||||
|
|
||||||
|
uint code = (uint)vkKeyScanResult & 0xff;
|
||||||
|
byte[] b = new byte[256];
|
||||||
|
b[0x10] = 0x80;
|
||||||
|
uint r;
|
||||||
|
|
||||||
|
if (1 != ToAscii(code, code, b, out r, 0))
|
||||||
|
return c;
|
||||||
|
|
||||||
|
return (char)r;
|
||||||
|
}
|
||||||
|
|
||||||
void ProcessKeyEventArgs(ref WF.Message m)
|
void ProcessKeyEventArgs(ref WF.Message m)
|
||||||
{
|
{
|
||||||
int WM_CHAR = 258, WM_SYSCHAR = 262, /*WM_KEYDOWN = 256, WM_SYSKEYDOWN = 260,*/
|
int WM_KEYUP = 0x0101, WM_SYSKEYUP = 0x0105, WM_APPCOMMAND = 0x0319;
|
||||||
WM_KEYUP = 0x0101, WM_SYSKEYUP = 0x0105, WM_APPCOMMAND = 0x0319;
|
|
||||||
|
|
||||||
IntPtr newWParam = IntPtr.Zero;
|
if (m.Msg == WM_KEYUP || m.Msg == WM_SYSKEYUP)
|
||||||
WF.KeyEventArgs ke = null;
|
OnKeyUp(new WF.KeyEventArgs((WF.Keys)(unchecked((int)(long)m.WParam)) | ModifierKeys));
|
||||||
WF.KeyPressEventArgs kpe = null;
|
else if (m.Msg == WM_APPCOMMAND)
|
||||||
|
|
||||||
if (m.Msg == WM_CHAR || m.Msg == WM_SYSCHAR)
|
|
||||||
{
|
{
|
||||||
kpe = new WF.KeyPressEventArgs(unchecked((char)(long)m.WParam));
|
switch ((AppCommand)(m.LParam.ToInt32() >> 16))
|
||||||
OnKeyPress(kpe);
|
|
||||||
newWParam = (IntPtr)kpe.KeyChar;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ke = new WF.KeyEventArgs((WF.Keys)(unchecked((int)(long)m.WParam)) | ModifierKeys);
|
|
||||||
|
|
||||||
if (m.Msg == WM_KEYUP || m.Msg == WM_SYSKEYUP)
|
|
||||||
OnKeyUp(ke);
|
|
||||||
|
|
||||||
if (m.Msg == WM_APPCOMMAND)
|
|
||||||
{
|
{
|
||||||
switch ((AppCommand)(m.LParam.ToInt32() >> 16))
|
case AppCommand.MEDIA_CHANNEL_DOWN:
|
||||||
{
|
SetKey("Channel_Down");
|
||||||
case AppCommand.MEDIA_CHANNEL_DOWN:
|
break;
|
||||||
SetKey("Channel_Down");
|
case AppCommand.MEDIA_CHANNEL_UP:
|
||||||
break;
|
SetKey("Channel_Up");
|
||||||
case AppCommand.MEDIA_CHANNEL_UP:
|
break;
|
||||||
SetKey("Channel_Up");
|
case AppCommand.MEDIA_FAST_FORWARD:
|
||||||
break;
|
SetKey("Forward");
|
||||||
case AppCommand.MEDIA_FAST_FORWARD:
|
break;
|
||||||
SetKey("Forward");
|
case AppCommand.MEDIA_REWIND:
|
||||||
break;
|
SetKey("Rewind");
|
||||||
case AppCommand.MEDIA_REWIND:
|
break;
|
||||||
SetKey("Rewind");
|
case AppCommand.MEDIA_PAUSE:
|
||||||
break;
|
SetKey("Pause");
|
||||||
case AppCommand.MEDIA_PAUSE:
|
break;
|
||||||
SetKey("Pause");
|
case AppCommand.MEDIA_PLAY:
|
||||||
break;
|
SetKey("Play");
|
||||||
case AppCommand.MEDIA_PLAY:
|
break;
|
||||||
SetKey("Play");
|
case AppCommand.MEDIA_PLAY_PAUSE:
|
||||||
break;
|
SetKey("PlayPause");
|
||||||
case AppCommand.MEDIA_PLAY_PAUSE:
|
break;
|
||||||
SetKey("PlayPause");
|
case AppCommand.MEDIA_NEXTTRACK:
|
||||||
break;
|
SetKey("Next");
|
||||||
case AppCommand.MEDIA_NEXTTRACK:
|
break;
|
||||||
SetKey("Next");
|
case AppCommand.MEDIA_PREVIOUSTRACK:
|
||||||
break;
|
SetKey("Prev");
|
||||||
case AppCommand.MEDIA_PREVIOUSTRACK:
|
break;
|
||||||
SetKey("Prev");
|
case AppCommand.MEDIA_RECORD:
|
||||||
break;
|
SetKey("Record");
|
||||||
case AppCommand.MEDIA_RECORD:
|
break;
|
||||||
SetKey("Record");
|
case AppCommand.MEDIA_STOP:
|
||||||
break;
|
SetKey("Stop");
|
||||||
case AppCommand.MEDIA_STOP:
|
break;
|
||||||
SetKey("Stop");
|
case AppCommand.VolumeUp:
|
||||||
break;
|
SetKey("Volume_Up");
|
||||||
case AppCommand.VolumeUp:
|
break;
|
||||||
SetKey("Volume_Up");
|
case AppCommand.VolumeDown:
|
||||||
break;
|
SetKey("Volume_Down");
|
||||||
case AppCommand.VolumeDown:
|
break;
|
||||||
SetKey("Volume_Down");
|
case AppCommand.VolumeMute:
|
||||||
break;
|
SetKey("Mute");
|
||||||
case AppCommand.VolumeMute:
|
break;
|
||||||
SetKey("Mute");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kpe != null)
|
|
||||||
m.WParam = newWParam;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal enum AppCommand
|
internal enum AppCommand
|
||||||
@@ -273,22 +259,32 @@ namespace mpvInputEdit
|
|||||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||||
public static extern short GetKeyState(int keyCode);
|
public static extern short GetKeyState(int keyCode);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
static extern short VkKeyScan(char c);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
|
static extern int ToAscii(uint uVirtKey,
|
||||||
|
uint uScanCode,
|
||||||
|
byte[] lpKeyState,
|
||||||
|
out uint lpChar,
|
||||||
|
uint flags);
|
||||||
|
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
|
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
|
||||||
source.AddHook(new HwndSourceHook(WndProc));
|
source.AddHook(new HwndSourceHook(WndProc));
|
||||||
SetKey(InputItem.Key);
|
SetKey(InputItem.Input);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConfirmButton_Click(object sender, RoutedEventArgs e)
|
private void ConfirmButton_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
InputItem.Key = NewKey;
|
InputItem.Input = NewKey;
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClearButton_Click(object sender, RoutedEventArgs e)
|
private void ClearButton_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
InputItem.Key = "_";
|
InputItem.Input = "_";
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,18 +8,18 @@
|
|||||||
Loaded="Window_Loaded" Closed="Window_Closed">
|
Loaded="Window_Loaded" Closed="Window_Closed">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="60" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Controls:SearchTextBoxUserControl x:Name="SearchControl" Width="300" Margin="0,0,0,10" Grid.ColumnSpan="2" />
|
<Controls:SearchTextBoxUserControl x:Name="SearchControl" Width="300" Margin="0,20,0,20" Grid.ColumnSpan="2" />
|
||||||
<DataGrid Grid.Row="1" x:Name="DataGrid" AutoGenerateColumns="False" CellStyle="{StaticResource DataGrid_Font_Centering}">
|
<DataGrid Grid.Row="1" x:Name="DataGrid" CommandManager.PreviewCanExecute="DataGrid_PreviewCanExecute" AutoGenerateColumns="False" CellStyle="{StaticResource DataGrid_Font_Centering}">
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
<DataGridTextColumn Header="Context Menu" Binding="{Binding Menu}"/>
|
<DataGridTextColumn Header="Menu" Binding="{Binding Menu}"/>
|
||||||
<DataGridTemplateColumn Header="Input">
|
<DataGridTemplateColumn Header="Input">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Button MinHeight="20" Click="ButtonClick">
|
<Button MinHeight="20" Click="ButtonClick">
|
||||||
<TextBlock Text="{Binding Key}"></TextBlock>
|
<TextBlock Text="{Binding Input}"></TextBlock>
|
||||||
</Button>
|
</Button>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
@@ -34,14 +34,26 @@ namespace mpvInputEdit
|
|||||||
|
|
||||||
bool Filter(InputItem item)
|
bool Filter(InputItem item)
|
||||||
{
|
{
|
||||||
string searchText = SearchControl.SearchTextBox.Text.ToLowerInvariant();
|
string searchText = SearchControl.SearchTextBox.Text.ToLower();
|
||||||
|
if (searchText == "") return true;
|
||||||
|
|
||||||
if (searchText == "")
|
if (searchText.StartsWith("i ") || searchText.StartsWith("i:") || searchText.Length == 1)
|
||||||
return true;
|
{
|
||||||
|
if (searchText.Length > 1)
|
||||||
|
searchText = searchText.Substring(2).Trim();
|
||||||
|
|
||||||
if (item.Command.ToLower().Contains(searchText) ||
|
if (searchText.Length < 3)
|
||||||
|
return item.Input.ToLower().Replace("ctrl+", "").Replace("shift+", "").Replace("alt+", "").Contains(searchText);
|
||||||
|
else
|
||||||
|
return item.Input.ToLower().Contains(searchText);
|
||||||
|
}
|
||||||
|
else if (searchText.StartsWith("m ") || searchText.StartsWith("m:"))
|
||||||
|
return item.Menu.ToLower().Contains(searchText.Substring(2).Trim());
|
||||||
|
else if (searchText.StartsWith("c ") || searchText.StartsWith("c:"))
|
||||||
|
return item.Command.ToLower().Contains(searchText.Substring(2).Trim());
|
||||||
|
else if (item.Command.ToLower().Contains(searchText) ||
|
||||||
item.Menu.ToLower().Contains(searchText) ||
|
item.Menu.ToLower().Contains(searchText) ||
|
||||||
item.Key.ToLower().Contains(searchText))
|
item.Input.ToLower().Contains(searchText))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -56,44 +68,33 @@ namespace mpvInputEdit
|
|||||||
w.Owner = this;
|
w.Owner = this;
|
||||||
w.InputItem = item;
|
w.InputItem = item;
|
||||||
w.ShowDialog();
|
w.ShowDialog();
|
||||||
|
|
||||||
|
var items = new Dictionary<string, InputItem>();
|
||||||
|
|
||||||
|
foreach (InputItem i in App.InputItems)
|
||||||
|
if (items.ContainsKey(i.Input) && i.Input != "_")
|
||||||
|
MessageBox.Show($"Duplicate found:\n\n{i.Input}: {i.Menu}\n\n{items[i.Input].Input}: {items[i.Input].Menu}\n\nPlease note that you can chain multiple commands in the same line by using a semicolon as separator.", "Duplicate Found", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
|
else
|
||||||
|
items[i.Input] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e) => Keyboard.Focus(SearchControl.SearchTextBox);
|
||||||
{
|
|
||||||
Keyboard.Focus(SearchControl.SearchTextBox);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Grid_PreviewCanExecute(object sender, CanExecuteRoutedEventArgs e)
|
|
||||||
{
|
|
||||||
DataGrid grid = (DataGrid)sender;
|
|
||||||
|
|
||||||
if (e.Command == DataGrid.DeleteCommand)
|
|
||||||
{
|
|
||||||
if (MessageBox.Show($"Would you like to delete the selected item?\n\n{(grid.SelectedItem as InputItem).Menu}",
|
|
||||||
"Confirm Delete", MessageBoxButton.OKCancel) != MessageBoxResult.OK)
|
|
||||||
{
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Window_Closed(object sender, EventArgs e)
|
private void Window_Closed(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (MessageBox.Show("Would you like to save changes?", "Confirm Save", MessageBoxButton.OKCancel) != MessageBoxResult.OK)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var backupDir = Path.GetDirectoryName(App.InputConfPath) + "\\backup\\";
|
var backupDir = Path.GetDirectoryName(App.InputConfPath) + "\\backup\\";
|
||||||
|
|
||||||
if (!Directory.Exists(backupDir))
|
if (!Directory.Exists(backupDir))
|
||||||
Directory.CreateDirectory(backupDir);
|
Directory.CreateDirectory(backupDir);
|
||||||
|
|
||||||
File.Copy(App.InputConfPath, backupDir + "input conf " + DateTime.Now.ToString("yyyy-MM-dd HH-mm") + ".conf");
|
if (File.Exists(App.InputConfPath))
|
||||||
|
File.Copy(App.InputConfPath, backupDir + "input conf " + DateTime.Now.ToString("yyyy-MM-dd HH-mm") + ".conf", true);
|
||||||
|
|
||||||
string text = "";
|
string text = "\r\n" + Properties.Settings.Default.input_conf_help + "\r\n\r\n";
|
||||||
|
|
||||||
foreach (InputItem item in App.InputItems)
|
foreach (InputItem item in App.InputItems)
|
||||||
{
|
{
|
||||||
string line = " " + item.Key.PadRight(14);
|
string line = " " + item.Input.PadRight(10);
|
||||||
|
|
||||||
if (item.Command.Trim() == "")
|
if (item.Command.Trim() == "")
|
||||||
line += " ignore";
|
line += " ignore";
|
||||||
@@ -108,11 +109,17 @@ namespace mpvInputEdit
|
|||||||
|
|
||||||
File.WriteAllText(App.InputConfPath, text);
|
File.WriteAllText(App.InputConfPath, text);
|
||||||
|
|
||||||
foreach (Process process in Process.GetProcesses())
|
MessageBox.Show("Changes will be available on next mpv(.net) startup.",
|
||||||
if (process.ProcessName == "mpvnet")
|
Title, MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
MessageBox.Show("Restart mpv.net in order to apply changed input bindings.", Title, MessageBoxButton.OK, MessageBoxImage.Information);
|
}
|
||||||
else if (process.ProcessName == "mpv")
|
|
||||||
MessageBox.Show("Restart mpv in order to apply changed input bindings.", Title, MessageBoxButton.OK, MessageBoxImage.Information);
|
private void DataGrid_PreviewCanExecute(object sender, CanExecuteRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
DataGrid grid = (DataGrid)sender;
|
||||||
|
|
||||||
|
if (e.Command == DataGrid.DeleteCommand)
|
||||||
|
if (MessageBox.Show($"Confirm to delete: {(grid.SelectedItem as InputItem).Input} ({(grid.SelectedItem as InputItem).Menu})", "Confirm Delete", MessageBoxButton.OKCancel, MessageBoxImage.Question) != MessageBoxResult.OK)
|
||||||
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,11 +8,11 @@ using System.Windows;
|
|||||||
// set of attributes. Change these attribute values to modify the information
|
// set of attributes. Change these attribute values to modify the information
|
||||||
// associated with an assembly.
|
// associated with an assembly.
|
||||||
[assembly: AssemblyTitle("mpv(.net) input edit")]
|
[assembly: AssemblyTitle("mpv(.net) input edit")]
|
||||||
[assembly: AssemblyDescription("mpv(.net) key bindings editor")]
|
[assembly: AssemblyDescription("mpv(.net) key and mouse bindings editor")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("")]
|
||||||
[assembly: AssemblyProduct("mpv(.net) input edit")]
|
[assembly: AssemblyProduct("mpv(.net) input edit")]
|
||||||
[assembly: AssemblyCopyright("Copyright © stax76")]
|
[assembly: AssemblyCopyright("Copyright © 2017-2019 stax76")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
@@ -51,5 +51,5 @@ using System.Windows;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("1.1.0.0")]
|
[assembly: AssemblyVersion("1.5.0.0")]
|
||||||
[assembly: AssemblyFileVersion("1.1.0.0")]
|
[assembly: AssemblyFileVersion("1.5.0.0")]
|
||||||
|
|||||||
43
mpvInputEdit/Properties/Settings.Designer.cs
generated
@@ -8,14 +8,12 @@
|
|||||||
// </auto-generated>
|
// </auto-generated>
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
namespace mpvInputEdit.Properties
|
namespace mpvInputEdit.Properties {
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.0.0.0")]
|
||||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||||
{
|
|
||||||
|
|
||||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|
||||||
@@ -24,5 +22,40 @@ namespace mpvInputEdit.Properties
|
|||||||
return defaultInstance;
|
return defaultInstance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute(@" # This file defines the input (keys and mouse) bindings of mpv and mpv.net
|
||||||
|
# and it also defines the context menu of mpv.net. mpv.net has an input
|
||||||
|
# editor and an conf editor as alternatives to editing conf text files.
|
||||||
|
# The input and conf editors can be found in mpv.net's context menu at:
|
||||||
|
|
||||||
|
# Settings > Show Config Editor
|
||||||
|
# Settings > Show Input Editor
|
||||||
|
|
||||||
|
# The defaults of this file can be found at:
|
||||||
|
|
||||||
|
# https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt
|
||||||
|
|
||||||
|
# the defaults of mpv can be found at:
|
||||||
|
|
||||||
|
# https://github.com/mpv-player/mpv/blob/master/etc/input.conf
|
||||||
|
|
||||||
|
# mpv.net's defaults of mpv.conf contain: 'input-default-bindings = no'
|
||||||
|
# which disables mpv's input defaults. Every line in this file begins with a
|
||||||
|
# space character to make it easier to do a text search, so if you want to know
|
||||||
|
# if 'o' has already a binding you can make a text search on ' o '.
|
||||||
|
|
||||||
|
# mpv input commands: https://github.com/stax76/mpv.net/wiki/mpv-input-commands
|
||||||
|
|
||||||
|
# mpv input keys: https://github.com/stax76/mpv.net/wiki/mpv-input-keys")]
|
||||||
|
public string input_conf_help {
|
||||||
|
get {
|
||||||
|
return ((string)(this["input_conf_help"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["input_conf_help"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,32 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
|
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="mpvInputEdit.Properties" GeneratedClassName="Settings">
|
||||||
<Profiles>
|
<Profiles />
|
||||||
<Profile Name="(Default)" />
|
<Settings>
|
||||||
</Profiles>
|
<Setting Name="input_conf_help" Type="System.String" Scope="User">
|
||||||
<Settings />
|
<Value Profile="(Default)"> # This file defines the input (keys and mouse) bindings of mpv and mpv.net
|
||||||
|
# and it also defines the context menu of mpv.net. mpv.net has an input
|
||||||
|
# editor and an conf editor as alternatives to editing conf text files.
|
||||||
|
# The input and conf editors can be found in mpv.net's context menu at:
|
||||||
|
|
||||||
|
# Settings > Show Config Editor
|
||||||
|
# Settings > Show Input Editor
|
||||||
|
|
||||||
|
# The defaults of this file can be found at:
|
||||||
|
|
||||||
|
# https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt
|
||||||
|
|
||||||
|
# the defaults of mpv can be found at:
|
||||||
|
|
||||||
|
# https://github.com/mpv-player/mpv/blob/master/etc/input.conf
|
||||||
|
|
||||||
|
# mpv.net's defaults of mpv.conf contain: 'input-default-bindings = no'
|
||||||
|
# which disables mpv's input defaults. Every line in this file begins with a
|
||||||
|
# space character to make it easier to do a text search, so if you want to know
|
||||||
|
# if 'o' has already a binding you can make a text search on ' o '.
|
||||||
|
|
||||||
|
# mpv input commands: https://github.com/stax76/mpv.net/wiki/mpv-input-commands
|
||||||
|
|
||||||
|
# mpv input keys: https://github.com/stax76/mpv.net/wiki/mpv-input-keys</Value>
|
||||||
|
</Setting>
|
||||||
|
</Settings>
|
||||||
</SettingsFile>
|
</SettingsFile>
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800">
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
<Grid x:Name="SearchTextBoxUserControl1" Background="White">
|
<Grid x:Name="SearchTextBoxUserControl1" Background="White">
|
||||||
<TextBlock x:Name="SearchTextBlock" Margin="5,2" Text="Search" Foreground="LightSteelBlue" VerticalAlignment="Center" />
|
<TextBlock x:Name="SearchHintTextBlock" Margin="5,2" Text="Type ? to get help." Foreground="LightSteelBlue" VerticalAlignment="Center" />
|
||||||
<TextBox Name="SearchTextBox" Height="25" Padding="1,2,0,0" BorderThickness="2" Background="Transparent" TextChanged="SearchTextBox_TextChanged" />
|
<TextBox Name="SearchTextBox" Height="25" Padding="1,2,0,0" BorderThickness="2" Background="Transparent" TextChanged="SearchTextBox_TextChanged" />
|
||||||
<Button x:Name="SearchClearButton" Background="Transparent" HorizontalAlignment="Right" Margin="2,0,4,0" FontSize="5" Width="17" Height="17" Visibility="Hidden" Click="SearchClearButton_Click">╳</Button>
|
<Button x:Name="SearchClearButton" Background="Transparent" HorizontalAlignment="Right" Margin="2,0,4,0" FontSize="5" Width="17" Height="17" Visibility="Hidden" Click="SearchClearButton_Click">╳</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -21,12 +21,15 @@ namespace Controls
|
|||||||
|
|
||||||
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||||
{
|
{
|
||||||
SearchTextBlock.Text = SearchTextBox.Text == "" ? "Search" : "";
|
SearchHintTextBlock.Text = SearchTextBox.Text == "" ? "Type ? to get help." : "";
|
||||||
|
|
||||||
if (SearchTextBox.Text == "")
|
if (SearchTextBox.Text == "")
|
||||||
SearchClearButton.Visibility = Visibility.Hidden;
|
SearchClearButton.Visibility = Visibility.Hidden;
|
||||||
else
|
else
|
||||||
SearchClearButton.Visibility = Visibility.Visible;
|
SearchClearButton.Visibility = Visibility.Visible;
|
||||||
|
|
||||||
|
if (SearchTextBox.Text == "?")
|
||||||
|
MessageBox.Show("Filtering works by searching in the Input, Menu and Command but it's possible to reduce the filter scope to either of Input, Menu or Command by prefixing as follows:\n\ni <input search>\ni: <input search>\n\nm <menu search>\nm: <menu search>\n\nc <command search>\nc: <command search>\n\nIf only one character is entered the search will be performed only in the input.", "Filtering", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
38
mpvInputEdit/app.manifest
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<!--
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||||
|
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||||
|
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
||||||
|
-->
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<!-- Windows 7 -->
|
||||||
|
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
|
||||||
|
|
||||||
|
<!-- Windows 8 -->
|
||||||
|
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
|
||||||
|
|
||||||
|
<!-- Windows 8.1 -->
|
||||||
|
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
|
||||||
|
|
||||||
|
<!-- Windows 10 -->
|
||||||
|
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
|
||||||
|
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<windowsSettings>
|
||||||
|
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||||
|
</windowsSettings>
|
||||||
|
</application>
|
||||||
|
</assembly>
|
||||||
@@ -21,14 +21,12 @@ namespace mpvInputEdit
|
|||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private string _Key = "";
|
private string _Input = "";
|
||||||
|
|
||||||
public string Key {
|
public string Input {
|
||||||
get {
|
get => _Input;
|
||||||
return _Key;
|
|
||||||
}
|
|
||||||
set {
|
set {
|
||||||
_Key = value;
|
_Input = value;
|
||||||
NotifyPropertyChanged();
|
NotifyPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,9 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ApplicationIcon>mpv.ico</ApplicationIcon>
|
<ApplicationIcon>mpv.ico</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
@@ -60,6 +63,7 @@
|
|||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</ApplicationDefinition>
|
</ApplicationDefinition>
|
||||||
|
<Compile Include="Controls.cs" />
|
||||||
<Compile Include="SearchTextBoxUserControl.xaml.cs">
|
<Compile Include="SearchTextBoxUserControl.xaml.cs">
|
||||||
<DependentUpon>SearchTextBoxUserControl.xaml</DependentUpon>
|
<DependentUpon>SearchTextBoxUserControl.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
@@ -106,6 +110,10 @@
|
|||||||
<Generator>ResXFileCodeGenerator</Generator>
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<None Include="..\README.md">
|
||||||
|
<Link>README.md</Link>
|
||||||
|
</None>
|
||||||
|
<None Include="app.manifest" />
|
||||||
<None Include="Properties\Settings.settings">
|
<None Include="Properties\Settings.settings">
|
||||||
<Generator>SettingsSingleFileGenerator</Generator>
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||||
|
|||||||
19
mpvnet.iss
@@ -1,6 +1,7 @@
|
|||||||
#define MyAppName "mpv.net"
|
#define MyAppName "mpv.net"
|
||||||
#define MyAppVersion GetFileVersion("mpv.net\bin\mpvnet.exe")
|
#define MyAppVersion GetFileVersion("mpv.net\bin\mpvnet.exe")
|
||||||
#define MyAppExeName "mpvnet.exe"
|
#define MyAppExeName "mpvnet.exe"
|
||||||
|
#define MyAppSourceDir "mpv.net\bin"
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
AppId={{9AA2B100-BEF3-44D0-B819-D8FC3C4D557D}}
|
AppId={{9AA2B100-BEF3-44D0-B819-D8FC3C4D557D}}
|
||||||
@@ -9,19 +10,21 @@ AppVersion={#MyAppVersion}
|
|||||||
AppPublisher=stax76
|
AppPublisher=stax76
|
||||||
ArchitecturesInstallIn64BitMode=x64
|
ArchitecturesInstallIn64BitMode=x64
|
||||||
Compression=lzma2
|
Compression=lzma2
|
||||||
DefaultDirName={commonpf}\{#MyAppName}
|
DefaultDirName={pf}\{#MyAppName}
|
||||||
DisableProgramGroupPage=yes
|
|
||||||
OutputBaseFilename=mpvnet-{#MyAppVersion}
|
OutputBaseFilename=mpvnet-{#MyAppVersion}
|
||||||
OutputDir=C:\Users\frank\Desktop
|
OutputDir=C:\Users\frank\Desktop
|
||||||
ChangesAssociations=yes
|
DefaultGroupName={#MyAppName}
|
||||||
|
|
||||||
|
[Icons]
|
||||||
|
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
||||||
|
|
||||||
[Files]
|
[Files]
|
||||||
Source: "C:\Users\frank\Daten\Projekte\CS\mpv.net\mpv.net\bin\mpvnet.exe"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "{#MyAppSourceDir}\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
Source: "C:\Users\frank\Daten\Projekte\CS\mpv.net\mpv.net\bin\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Excludes: "System.Management.Automation.xml"
|
Source: "{#MyAppSourceDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Excludes: "System.Management.Automation.xml"
|
||||||
|
|
||||||
[Run]
|
[Run]
|
||||||
Filename: "{app}\defapp.exe"; Description: "Associate video file extensions?"; Flags: postinstall unchecked runascurrentuser runhidden nowait; Parameters: """{app}\{#MyAppExeName}"" mpg avi vob mp4 mkv avs 264 mov wmv flv h264 asf webm mpeg mpv y4m avc hevc 265 h265 m2v m2ts vpy mts webm m4v"
|
Filename: "{app}\{#MyAppExeName}"; Description: "Associate video file extensions?"; Flags: postinstall unchecked runascurrentuser runhidden nowait; Parameters: "--reg-file-assoc video"
|
||||||
Filename: "{app}\defapp.exe"; Description: "Associate audio file extensions?"; Flags: postinstall unchecked runascurrentuser runhidden nowait; Parameters: """{app}\{#MyAppExeName}"" mp2 mp3 ac3 wav w64 m4a dts dtsma dtshr dtshd eac3 thd thd+ac3 ogg mka aac opus flac mpa"
|
Filename: "{app}\{#MyAppExeName}"; Description: "Associate audio file extensions?"; Flags: postinstall unchecked runascurrentuser runhidden nowait; Parameters: "--reg-file-assoc audio"
|
||||||
|
|
||||||
[UninstallRun]
|
[UninstallRun]
|
||||||
Filename: "{app}\defapp.exe"; Flags: runascurrentuser runhidden nowait; Parameters: """{app}\{#MyAppExeName}"""
|
Filename: "{app}\{#MyAppExeName}"; Flags: runascurrentuser runhidden; Parameters: "--reg-file-assoc unregister"
|
||||||
|
Before Width: | Height: | Size: 214 KiB After Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 194 KiB After Width: | Height: | Size: 171 KiB |
|
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 2.9 MiB |
BIN
screenshots/mpvnetContextMenu.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |