主頁 >  其他 > <2021SC@SDUSC>開源游戲引擎Overload代碼分析三(OvWindowing結束):OvWindowing——Dialogs

<2021SC@SDUSC>開源游戲引擎Overload代碼分析三(OvWindowing結束):OvWindowing——Dialogs

2021-10-19 08:04:11 其他

2021SC@SDUSC

Overload代碼分析三:OvWindowing——Dialogs

  • 前言
  • Dialogs
    • 一、FileDialog
      • FileDialog.h
      • FileDialog.cpp
    • 二、MessageBox
      • MessageBox.h
      • MessageBox.cpp
    • 三、OpenFileDialog
      • OpenFileDialog.h
      • OpenFileDialog.cpp
    • 四、SaveFileDialog
      • SaveFileDialog.h
      • SaveFileDialog.cpp
  • Inputs
    • 一、EKey.h
    • 二、EKeyState.h
    • 三、EMouseButton.h
    • 四、EMouseButtonState.h
    • 五、InputManager
      • InputManager.h
      • InputManager.cpp
  • 一些剩下的檔案
    • 一、DeviceSettings.h
    • 二、Window.h
  • 總結

前言

這是Overload引擎相關的第五篇文章,同時也是OvWindowing分析的第三篇,Overload引擎的Github主頁在這里,
本篇文章主要會介紹OvWindowing中Dialogs檔案夾所包含的h和cpp檔案,同時會把內容比較少,比較簡單Inputs檔案夾內的檔案一并介紹,就算是把OvWindowing中剩余的內容全部講完了,

Dialogs

首先我們來講Dialogs,顧名思義,這個檔案夾下的檔案都是和對話框有關的,我們把h檔案和cpp檔案一對一的講,

一、FileDialog

FileDialog.h

我們先看頭檔案,頭檔案代碼如下:

	/**
	* Some flags that can be passed to FileDialog instances
	*/
	enum class EExplorerFlags
	{
		READONLY                 = 0x00000001,
		OVERWRITEPROMPT          = 0x00000002,
		HIDEREADONLY             = 0x00000004,
		NOCHANGEDIR              = 0x00000008,
		SHOWHELP                 = 0x00000010,
		ENABLEHOOK               = 0x00000020,
		ENABLETEMPLATE           = 0x00000040,
		ENABLETEMPLATEHANDLE     = 0x00000080,
		NOVALIDATE               = 0x00000100,
		ALLOWMULTISELECT         = 0x00000200,
		EXTENSIONDIFFERENT       = 0x00000400,
		PATHMUSTEXIST            = 0x00000800,
		FILEMUSTEXIST            = 0x00001000,
		CREATEPROMPT             = 0x00002000,
		SHAREAWARE               = 0x00004000,
		NOREADONLYRETURN         = 0x00008000,
		NOTESTFILECREATE         = 0x00010000,
		NONETWORKBUTTON          = 0x00020000,
		NOLONGNAMES              = 0x00040000,	// force no long names for 4.x modules
		EXPLORER                 = 0x00080000,	// new look commdlg
		NODEREFERENCELINKS       = 0x00100000,	
		LONGNAMES                = 0x00200000,	// force long names for 3.x modules
		ENABLEINCLUDENOTIFY      = 0x00400000,	// send include message to callback
		ENABLESIZING             = 0x00800000,	
		DONTADDTORECENT          = 0x02000000,	
		FORCESHOWHIDDEN          = 0x10000000	// Show All files including System and hidden files
	};

	inline EExplorerFlags operator~ (EExplorerFlags a) { return (EExplorerFlags)~(int)a; }
	inline EExplorerFlags operator| (EExplorerFlags a, EExplorerFlags b) { return (EExplorerFlags)((int)a | (int)b); }
	inline EExplorerFlags operator& (EExplorerFlags a, EExplorerFlags b) { return (EExplorerFlags)((int)a & (int)b); }
	inline EExplorerFlags operator^ (EExplorerFlags a, EExplorerFlags b) { return (EExplorerFlags)((int)a ^ (int)b); }
	inline EExplorerFlags& operator|= (EExplorerFlags& a, EExplorerFlags b) { return (EExplorerFlags&)((int&)a |= (int)b); }
	inline EExplorerFlags& operator&= (EExplorerFlags& a, EExplorerFlags b) { return (EExplorerFlags&)((int&)a &= (int)b); }
	inline EExplorerFlags& operator^= (EExplorerFlags& a, EExplorerFlags b) { return (EExplorerFlags&)((int&)a ^= (int)b); }

	/**
	* FileDialog is the base class for any dialog window that asks the user to select/save a file from/to the disk
	*/
	class FileDialog
	{
	public:
		/**
		* Constructor
		* @param p_callback
		* @param p_dialogTitle
		*/
		FileDialog(std::function<int(tagOFNA*)> p_callback, const std::string& p_dialogTitle);

		/**
		* Defines the initial directory (Where the FileDialog will open)
		* @param p_initalDirectory
		*/
		void SetInitialDirectory(const std::string& p_initialDirectory);

		/**
		* Show the file dialog
		* @param p_flags
		*/
		virtual void Show(EExplorerFlags p_flags = EExplorerFlags::DONTADDTORECENT | EExplorerFlags::FILEMUSTEXIST | EExplorerFlags::HIDEREADONLY | EExplorerFlags::NOCHANGEDIR);

		/**
		* Returns true if the file action succeeded
		*/
		bool HasSucceeded() const;

		/**
		* Returns the selected file name (Make sur that HasSucceeded() returned true before calling this method)
		*/
		std::string GetSelectedFileName();

		/**
		* Returns the selected file path (Make sur that HasSucceeded() returned true before calling this method)
		*/
		std::string GetSelectedFilePath();

		/**
		* Returns some information about the last error (Make sur that HasSucceeded() returned false before calling this method)
		*/
		std::string GetErrorInfo();

		/**
		* Returns true if the selected file exists
		*/
		bool IsFileExisting() const;

	private:
		void HandleError();

	protected:
		std::function<int(tagOFNA*)> m_callback;
		const std::string m_dialogTitle;
		std::string m_initialDirectory;
		std::string m_filter;
		std::string m_error;
		std::string m_filename;
		std::string m_filepath;
		bool m_succeeded;
	};

上來首先是一個列舉定義,事實上表示了對話框的性質,比如第一個READONLY就表示只讀,這個看名字很明白了,不容易理解的還有注釋,因為定義的比較多,所以我就不一一說明意思了,總之知道它是對話框性質就好了,

接下來一系列的行內函式都是對運算子的多載,需要知道EExplorerFlags實際上就是一個數,所以做運算是很正常的,而多載運算子最后又把運算結果轉換成了EExplorerFlags型別,所以這些運算子多載后的作用就是改變對話框的性質,

接著它定義了FileDialog類這就是咱們檔案相關的對話框的基類了,具體的函式作用在這有注釋,我們到cpp檔案中實作的時候再細說,

FileDialog.cpp

因為檔案并不是很長,函式實作也并不算復雜,所以咱們把整個檔案放在一起講了,先上代碼:

OvWindowing::Dialogs::FileDialog::FileDialog(std::function<int(tagOFNA*)> p_callback, const std::string & p_dialogTitle) :
	m_callback(p_callback),
	m_dialogTitle(p_dialogTitle),
	m_initialDirectory("")
{
}

void OvWindowing::Dialogs::FileDialog::SetInitialDirectory(const std::string & p_initialDirectory)
{
	m_initialDirectory = p_initialDirectory;
}

void OvWindowing::Dialogs::FileDialog::Show(EExplorerFlags p_flags)
{
	OPENFILENAME ofn;

	if (!m_initialDirectory.empty())
		m_filepath = m_initialDirectory;

	m_filepath.resize(MAX_PATH);

	ZeroMemory(&ofn, sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = NULL;  // If you have a window to center over, put its HANDLE here
	ofn.lpstrFilter = m_filter.c_str();
	ofn.lpstrFile = m_filepath.data();
	ofn.nMaxFile = MAX_PATH;
	ofn.lpstrTitle = m_dialogTitle.c_str();

	if (!m_initialDirectory.empty())
		ofn.lpstrInitialDir = m_initialDirectory.c_str();

	ofn.Flags = static_cast<DWORD>(p_flags);

	m_succeeded = m_callback(&ofn);

	if (!m_succeeded)
		HandleError();
	else
		m_filepath = m_filepath.c_str();

	/* Extract filename from filepath */
	m_filename.clear();
	for (auto it = m_filepath.rbegin(); it != m_filepath.rend() && *it != '\\' && *it != '/'; ++it)
		m_filename += *it;
	std::reverse(m_filename.begin(), m_filename.end());
}

bool OvWindowing::Dialogs::FileDialog::HasSucceeded() const
{
	return m_succeeded;
}

std::string OvWindowing::Dialogs::FileDialog::GetSelectedFileName()
{
	return m_filename;
}

std::string OvWindowing::Dialogs::FileDialog::GetSelectedFilePath()
{
	return m_filepath;
}

std::string OvWindowing::Dialogs::FileDialog::GetErrorInfo()
{
	return m_error;
}

bool OvWindowing::Dialogs::FileDialog::IsFileExisting() const
{
	return std::filesystem::exists(m_filepath);
}

void OvWindowing::Dialogs::FileDialog::HandleError()
{
	switch (CommDlgExtendedError())
	{
	case CDERR_DIALOGFAILURE:	m_error = "CDERR_DIALOGFAILURE";   break;
	case CDERR_FINDRESFAILURE:	m_error = "CDERR_FINDRESFAILURE";  break;
	case CDERR_INITIALIZATION:	m_error = "CDERR_INITIALIZATION";  break;
	case CDERR_LOADRESFAILURE:	m_error = "CDERR_LOADRESFAILURE";  break;
	case CDERR_LOADSTRFAILURE:	m_error = "CDERR_LOADSTRFAILURE";  break;
	case CDERR_LOCKRESFAILURE:	m_error = "CDERR_LOCKRESFAILURE";  break;
	case CDERR_MEMALLOCFAILURE: m_error = "CDERR_MEMALLOCFAILURE"; break;
	case CDERR_MEMLOCKFAILURE:	m_error = "CDERR_MEMLOCKFAILURE";  break;
	case CDERR_NOHINSTANCE:		m_error = "CDERR_NOHINSTANCE";     break;
	case CDERR_NOHOOK:			m_error = "CDERR_NOHOOK";          break;
	case CDERR_NOTEMPLATE:		m_error = "CDERR_NOTEMPLATE";      break;
	case CDERR_STRUCTSIZE:		m_error = "CDERR_STRUCTSIZE";      break;
	case FNERR_BUFFERTOOSMALL:	m_error = "FNERR_BUFFERTOOSMALL";  break;
	case FNERR_INVALIDFILENAME: m_error = "FNERR_INVALIDFILENAME"; break;
	case FNERR_SUBCLASSFAILURE: m_error = "FNERR_SUBCLASSFAILURE"; break;
	default:					m_error = "You cancelled.";
	}
}

首先是建構式,只做了屬性的賦值,p_callback型別中可以看到tagOFNA,這是OPENFILENAME相關的內部結構,比較復雜,咱們真的用到再講,m_dialogTitle是對話框的標題,

接下來的SetInitialDirectory()就是普通的賦值,更改m_initialDirectory,就是初始目錄的位置,

再下來是一個稍微復雜點的Show()函式,函式先定義了一個OPENFILENAME型別的變數,事實上是OPENFILENAMEA型別,而OPENFILENAMEA就是tagOFNA結構,接下來函式確認是否有初始路徑,如果有就把這個初始路徑賦值給當前檔案路徑,之后給當前檔案路徑分配更多的空間,也給ofn分配了一塊新的空間,接下來就是對ofn的屬性進行賦值,我們來講一下它的屬性,實際就是tagOFNA的屬性:

lStructSize是當前結構的大小,單位是位元組;
hwndOwner是所有者對話框視窗的句柄;
lpstrFilter是指定檔案名篩選字串,決定了對話框中“檔案型別”下拉式串列框中的內容,賦值比較復雜;
lpstrFile應指向一個包含檔案名的緩沖區;
nMaxFile指定lpstrFile引數指向的緩沖區的長度,單位為TCHARs;
lpstrTitle應當指向一個緩沖區,用來接收用戶選擇的檔案的檔案名和擴展名;
lpstrInitialDir是一個指向對話框的初始化目錄的以空字符結束的字串,在咱們的Show()函式里只有有初始路徑時才賦值;
Flags這個標志欄位決定了對話框的不同行為,
這就是我們在函式里提到的所有的屬性,想要全面了解tagOFNA的屬性的話,可以去看這篇文章,當然也可以看windows官方的說明,

在對ofn操作完成后,會用m_succeeded來接收一下回呼,確認是否創建賦值成功,如果失敗了,那么我們會回傳一個錯誤,如果成功的話,我們就把真實的檔案路徑賦給咱們當前實體的屬性,

再往下,就是如果咱們指定讀取了一個路徑,就會先清空已保存的當前路徑,然后讀取我們指定的路徑,

接下來的函式是HasSucceeded(),GetSelectedFileName(),GetSelectedFilePath(),GetErrorInfo(),IsFileExisting(),都是一行就結束的函式,我們在一起講,分別是用于讀取屬性m_succeeded,來確定是否成功生成;讀取選中檔案名,讀取選中檔案路徑,獲得報錯資訊,以及判斷我們選中的檔案是否存在,

最后是HandleError(),用于先從CommDlgExtendedError獲取錯誤型別,然后對不同的錯誤型別報不同的錯誤,

二、MessageBox

接下來講MessageBox這個檔案夾,先講頭檔案:

MessageBox.h

	/**
	* Displays a modal dialog box that contains a system icon,
	* a set of buttons, and a brief application-specific message,
	* such as status or error information
	*/
	class MessageBox
	{
	public:
		/**
		* Defines some severity levels for MessageBox instances
		*/
		enum class EMessageType
		{
			QUESTION	= 0x00000020L,
			INFORMATION = 0x00000040L,
			WARNING		= 0x00000030L,
			ERROR		= 0x00000010L
		};

		/**
		* Defines some button layouts for MessageBox instances
		*/
		enum class EButtonLayout
		{
			OK							= 0x00000000L,
			OK_CANCEL					= 0x00000001L,
			YES_NO						= 0x00000004L,
			YES_NO_CANCEL				= 0x00000003L,
			RETRY_CANCEL				= 0x00000005L,
			ABORT_RETRY_IGNORE			= 0x00000002L,
			CANCEL_TRYAGAIN_CONTINUE	= 0x00000006L,
			HELP						= 0x00004000L
		};

		/**
		* Defines some actions that the MessageBox should provide
		*/
		enum class EUserAction
		{
			OK			= 1,
			CANCEL		= 2,
			YES			= 6,
			NO			= 7,
			CONTINUE	= 11,
			IGNORE		= 5,
			RETRY		= 4,
			TRYAGAIN	= 10
		};

		/**
		* Create the MessageBox
		* @param p_title
		* @param p_message
		* @param p_messageType
		* @param p_buttonLayout
		* @param p_autoSpawn
		*/
		MessageBox(std::string p_title, std::string p_message, EMessageType p_messageType = EMessageType::INFORMATION, EButtonLayout p_buttonLayout = EButtonLayout::OK, bool p_autoSpawn = true);

		/**
		* Show the MessageBox on the screen
		*/
		void Spawn();

		/**
		* Return the user action
		*/
		const EUserAction& GetUserAction() const;

	private:
		std::string		m_title;
		std::string		m_message;
		EButtonLayout	m_buttonLayout;
		EMessageType	m_messageType;
		EUserAction		m_userResult;
	};

這個頭檔案定義了MessageBox,其實和咱們windows的MessageBox差不多,我們可以看到它有三個列舉:EMessageType是定義這個box的級別,是問題、資訊、警告還是錯誤;EButtonLayout則是咱們的按鈕型別;EUserAction則是用戶做出的選擇,其他的函式實作,我們在cpp檔案中講:

MessageBox.cpp

OvWindowing::Dialogs::MessageBox::MessageBox(std::string p_title, std::string p_message, EMessageType p_messageType, EButtonLayout p_buttonLayout, bool p_autoSpawn) :
	m_title(p_title),
	m_message(p_message),
	m_buttonLayout(p_buttonLayout),
	m_messageType(p_messageType)
{
	if (p_autoSpawn)
		Spawn();
}

const OvWindowing::Dialogs::MessageBox::EUserAction& OvWindowing::Dialogs::MessageBox::GetUserAction() const
{
	return m_userResult;
}

void OvWindowing::Dialogs::MessageBox::Spawn()
{
	int msgboxID = MessageBoxA
	(
		nullptr,
		static_cast<LPCSTR>(m_message.c_str()),
		static_cast<LPCSTR>(m_title.c_str()),
		static_cast<UINT>(m_messageType) | static_cast<UINT>(m_buttonLayout) | MB_DEFBUTTON2
	);

	m_userResult = static_cast<EUserAction>(msgboxID);
}

首先是建構式,同樣也是比較簡單的賦值,唯一的一個判斷是是否自動顯現,如果是的話就顯現視窗,

GetUserAction()只是回傳一個屬性,這個屬性是用于記錄用戶的動作結果,

Spawn()是用于顯示視窗的,其實就是呼叫了windows的函式MessageBoxA(),這個函式會顯示一個對話框,之后會回傳的整數表示用戶所點擊的按鈕,所以我們會把那個得到的整數值存入m_userResult,也就是GetUserAction()回傳的屬性,

三、OpenFileDialog

接下來是OpenFileDialog檔案夾內的檔案,

OpenFileDialog.h

	/**
	* Dialog window that asks the user to select a file from the disk
	*/
	class OpenFileDialog : public FileDialog
	{
	public:
		/**
		* Constructor
		* @param p_dialogTitle
		*/
		OpenFileDialog(const std::string& p_dialogTitle);

		/**
		* Add a supported file type to the dialog window
		* @param p_label
		* @param p_filter
		*/
		void AddFileType(const std::string& p_label, const std::string& p_filter);
	};

這個頭檔案很短,定義了一個OpenFileDialog類,是讓用戶從磁盤選擇一個檔案的對話框,具體的函式實作在cpp檔案中說明:

OpenFileDialog.cpp

OvWindowing::Dialogs::OpenFileDialog::OpenFileDialog(const std::string & p_dialogTitle) : FileDialog(GetOpenFileNameA, p_dialogTitle)
{
}

void OvWindowing::Dialogs::OpenFileDialog::AddFileType(const std::string & p_label, const std::string & p_filter)
{
	m_filter += p_label + '\0' + p_filter + '\0';
}

這個實作實際上也很簡單,建構式就是呼叫繼承的FileDialog類的建構式,而AddFileType()也就是往我們的檔案過濾器添加了一種型別,讓我們能支持新的檔案格式罷了,

四、SaveFileDialog

這里是SaveFileDialog檔案夾內的檔案:

SaveFileDialog.h

	/**
	* Dialog window that asks the user to save a file to the disk
	*/
	class SaveFileDialog : public FileDialog
	{
	public:
		/**
		* Constructor
		* @param p_dialogTitle
		*/
		SaveFileDialog(const std::string& p_dialogTitle);

		/**
		* Show the file dialog
		* @param p_flags
		*/
		virtual void Show(EExplorerFlags p_flags = EExplorerFlags::DONTADDTORECENT | EExplorerFlags::FILEMUSTEXIST | EExplorerFlags::HIDEREADONLY | EExplorerFlags::NOCHANGEDIR) override;

		/**
		* Define the extension of the saved file
		* @param p_label
		* @param p_extension
		*/
		void DefineExtension(const std::string& p_label, const std::string& p_extension);

	private:
		void AddExtensionToFilePathAndName();

	private:
		std::string m_extension;
	};

這個頭檔案也比較簡單,定義了一個SaveFileDialog類,是保存檔案到磁盤的對話框,具體函式實作看下面:

SaveFileDialog.cpp

OvWindowing::Dialogs::SaveFileDialog::SaveFileDialog(const std::string & p_dialogTitle) : FileDialog(GetSaveFileNameA, p_dialogTitle)
{
}

void OvWindowing::Dialogs::SaveFileDialog::Show(EExplorerFlags p_flags)
{
	FileDialog::Show(p_flags);

	if (m_succeeded)
		AddExtensionToFilePathAndName();
}

void OvWindowing::Dialogs::SaveFileDialog::DefineExtension(const std::string & p_label, const std::string & p_extension)
{
	m_filter = p_label + '\0' + '*' + p_extension + '\0';
	m_extension = p_extension;
}

void OvWindowing::Dialogs::SaveFileDialog::AddExtensionToFilePathAndName()
{
	if (m_filename.size() >= m_extension.size())
	{
		std::string fileEnd(m_filename.data() + m_filename.size() - m_extension.size(), m_filename.data() + m_filename.size());

		if (fileEnd != m_extension)
		{
			m_filepath += m_extension;
			m_filename += m_extension;
		}
	}
	else
	{
		m_filepath += m_extension;
		m_filename += m_extension;
	}
}

首先,建構式還是直接呼叫繼承的FileDialog類的建構式;

Show()函式實際上也是呼叫FileDialog類中的同名函式,但是添加了一句,用處是如果成功加載,就呼叫我們下面的一個函式AddExtensionToFilePathAndName(),作用在下面再講;

DefineExtension()是定義我們要保存檔案的型別,事實上就是后綴名;

AddExtensionToFilePathAndName()是添加我們的后綴名到檔案路徑和檔案名,如果咱們的檔案已經有名字了,那就看看拓展名對不對的上,不行就換掉當前的拓展名,如果沒有名字,就直接加上我們給定的拓展名就好了,

Inputs

接下來我們講Inputs檔案夾內的檔案,這里面的檔案很簡單,就是普通的輸入相關的各種檔案,我們先把各個頭檔案中的定義講完了,再去看cpp檔案,

一、EKey.h

	/**
	* Keyboard keys
	*/
	enum class EKey
	{
		KEY_UNKNOWN			= -1,
		KEY_SPACE			= 32,
		KEY_APOSTROPHE		= 39,
		KEY_COMMA			= 44,
		KEY_MINUS			= 45,
		KEY_PERIOD			= 46,
		KEY_SLASH			= 47,
		KEY_0				= 48,
		KEY_1				= 49,
		KEY_2				= 50,
		KEY_3				= 51,
		KEY_4				= 52,
		KEY_5				= 53,
		KEY_6				= 54,
		KEY_7				= 55,
		KEY_8				= 56,
		KEY_9				= 57,
		KEY_SEMICOLON		= 59,
		KEY_EQUAL			= 61,
		KEY_A				= 65,
		KEY_B				= 66,
		KEY_C				= 67,
		KEY_D				= 68,
		KEY_E				= 69,
		KEY_F				= 70,
		KEY_G				= 71,
		KEY_H				= 72,
		KEY_I				= 73,
		KEY_J				= 74,
		KEY_K				= 75,
		KEY_L				= 76,
		KEY_M				= 77,
		KEY_N				= 78,
		KEY_O				= 79,
		KEY_P				= 80,
		KEY_Q				= 81,
		KEY_R				= 82,
		KEY_S				= 83,
		KEY_T				= 84,
		KEY_U				= 85,
		KEY_V				= 86,
		KEY_W				= 87,
		KEY_X				= 88,
		KEY_Y				= 89,
		KEY_Z				= 90,
		KEY_LEFT_BRACKET	= 91,
		KEY_BACKSLASH		= 92,
		KEY_RIGHT_BRACKET	= 93,
		KEY_GRAVE_ACCENT	= 96,
		KEY_WORLD_1			= 61,
		KEY_WORLD_2			= 62,
		KEY_ESCAPE			= 256,
		KEY_ENTER			= 257,
		KEY_TAB				= 258,
		KEY_BACKSPACE		= 259,
		KEY_INSERT			= 260,
		KEY_DELETE			= 261,
		KEY_RIGHT			= 262,
		KEY_LEFT			= 263,
		KEY_DOWN			= 264,
		KEY_UP				= 265,
		KEY_PAGE_UP			= 266,
		KEY_PAGE_DOWN		= 267,
		KEY_HOME			= 268,
		KEY_END				= 269,
		KEY_CAPS_LOCK		= 280,
		KEY_SCROLL_LOCK		= 281,
		KEY_NUM_LOCK		= 282,
		KEY_PRINT_SCREEN	= 283,
		KEY_PAUSE			= 284,
		KEY_F1				= 290,
		KEY_F2				= 291,
		KEY_F3				= 292,
		KEY_F4				= 293,
		KEY_F5				= 294,
		KEY_F6				= 295,
		KEY_F7				= 296,
		KEY_F8				= 297,
		KEY_F9				= 298,
		KEY_F10				= 299,
		KEY_F11				= 300,
		KEY_F12				= 301,
		KEY_F13				= 302,
		KEY_F14				= 303,
		KEY_F15				= 304,
		KEY_F16				= 305,
		KEY_F17				= 306,
		KEY_F18				= 307,
		KEY_F19				= 308,
		KEY_F20				= 309,
		KEY_F21				= 310,
		KEY_F22				= 311,
		KEY_F23				= 312,
		KEY_F24				= 313,
		KEY_F25				= 314,
		KEY_KP_0			= 320,
		KEY_KP_1			= 321,
		KEY_KP_2			= 322,
		KEY_KP_3			= 323,
		KEY_KP_4			= 324,
		KEY_KP_5			= 325,
		KEY_KP_6			= 326,
		KEY_KP_7			= 327,
		KEY_KP_8			= 328,
		KEY_KP_9			= 329,
		KEY_KP_DECIMAL		= 330,
		KEY_KP_DIVIDE		= 331,
		KEY_KP_MULTIPLY		= 332,
		KEY_KP_SUBTRACT		= 333,
		KEY_KP_ADD			= 334,
		KEY_KP_ENTER		= 335,
		KEY_KP_EQUAL		= 336,
		KEY_LEFT_SHIFT		= 340,
		KEY_LEFT_CONTROL	= 341,
		KEY_LEFT_ALT		= 342,
		KEY_LEFT_SUPER		= 343,
		KEY_RIGHT_SHIFT		= 344,
		KEY_RIGHT_CONTROL	= 345,
		KEY_RIGHT_ALT		= 346,
		KEY_RIGHT_SUPER		= 347,
		KEY_MENU			= 348
	};

這個列舉是把鍵盤上的按鍵都給了個序號用于對應,非常明了,

二、EKeyState.h

	/**
	* Defines some states that can be applied to keyboard keys
	*/
	enum class EKeyState
	{
		KEY_UP		= 0,
		KEY_DOWN	= 1
	};

這個列舉定義了按鍵的狀態,是否被按下,

三、EMouseButton.h

	/**
	* Mouse buttons
	*/
	enum class EMouseButton
	{
		MOUSE_BUTTON_1		= 0,
		MOUSE_BUTTON_2		= 1,
		MOUSE_BUTTON_3		= 2,
		MOUSE_BUTTON_4		= 3,
		MOUSE_BUTTON_5		= 4,
		MOUSE_BUTTON_6		= 5,
		MOUSE_BUTTON_7		= 6,
		MOUSE_BUTTON_8		= 7,
		MOUSE_BUTTON_LEFT	= 0,
		MOUSE_BUTTON_RIGHT	= 1,
		MOUSE_BUTTON_MIDDLE = 2
	};

和EKey一樣,這個列舉定義了滑鼠的按鍵映射,

四、EMouseButtonState.h

	/**
	* Defines some states that can be applied to mouse buttons
	*/
	enum class EMouseButtonState
	{
		MOUSE_UP	= 0,
		MOUSE_DOWN	= 1
	};

和EKeyState一樣,用于標識滑鼠按鍵的狀態,是否被按下,

五、InputManager

接下來這個類有頭檔案和cpp檔案,

InputManager.h

	/**
	* Handles inputs (Mouse and keyboard)
	*/
	class InputManager
	{
	public:
		/**
		* Create the window
		* @param p_windowSettings
		*/
		InputManager(Window& p_window);

		/**
		* Destroy the input manager by removing listeners on the window
		*/
		~InputManager();

		/**
		* Return the current state of the given key
		* @param p_key
		*/
		EKeyState GetKeyState(EKey p_key) const;

		/**
		* Return the current state of the given mouse button
		* @param p_button
		*/
		EMouseButtonState GetMouseButtonState(EMouseButton p_button) const;

		/**
		* Return true if the given key has been pressed during the frame
		* @param p_key
		*/
		bool IsKeyPressed(EKey p_key) const;

		/**
		* Return true if the given key has been released during the frame
		* @param p_key
		*/
		bool IsKeyReleased(EKey p_key) const;

		/**
		* Return true if the given mouse button has been pressed during the frame
		* @param p_button
		*/
		bool IsMouseButtonPressed(EMouseButton p_button) const;

		/**
		* Return true if the given mouse button has been released during the frame
		* @param p_button
		*/
		bool IsMouseButtonReleased(EMouseButton p_button) const;

		/**
		* Return the current mouse position relative to the window
		*/
		std::pair<double, double> GetMousePosition() const;

		/**
		* Clear any event occured
		* @note Should be called at the end of every game tick
		*/
		void ClearEvents();

	private:
		void OnKeyPressed(int p_key);
		void OnKeyReleased(int p_key);
		void OnMouseButtonPressed(int p_button);
		void OnMouseButtonReleased(int p_button);

	private:
		Window& m_window;

		OvTools::Eventing::ListenerID m_keyPressedListener;
		OvTools::Eventing::ListenerID m_keyReleasedListener;
		OvTools::Eventing::ListenerID m_mouseButtonPressedListener;
		OvTools::Eventing::ListenerID m_mouseButtonReleasedListener;

		std::unordered_map<EKey, EKeyState>					m_keyEvents;
		std::unordered_map<EMouseButton, EMouseButtonState>	m_mouseButtonEvents;
	};

具體函式實作在分析cpp檔案的時候說,

InputManager.cpp

OvWindowing::Inputs::InputManager::InputManager(Window& p_window) : m_window(p_window)
{
	m_keyPressedListener = m_window.KeyPressedEvent.AddListener(std::bind(&InputManager::OnKeyPressed, this, std::placeholders::_1));
	m_keyReleasedListener = m_window.KeyReleasedEvent.AddListener(std::bind(&InputManager::OnKeyReleased, this, std::placeholders::_1));
	m_mouseButtonPressedListener = m_window.MouseButtonPressedEvent.AddListener(std::bind(&InputManager::OnMouseButtonPressed, this, std::placeholders::_1));
	m_mouseButtonReleasedListener = m_window.MouseButtonReleasedEvent.AddListener(std::bind(&InputManager::OnMouseButtonReleased, this, std::placeholders::_1));
}

OvWindowing::Inputs::InputManager::~InputManager()
{
	m_window.KeyPressedEvent.RemoveListener(m_keyPressedListener);
	m_window.KeyReleasedEvent.RemoveListener(m_keyReleasedListener);
	m_window.MouseButtonPressedEvent.RemoveListener(m_mouseButtonPressedListener);
	m_window.MouseButtonReleasedEvent.RemoveListener(m_mouseButtonReleasedListener);
}

OvWindowing::Inputs::EKeyState OvWindowing::Inputs::InputManager::GetKeyState(EKey p_key) const
{
	switch (glfwGetKey(m_window.GetGlfwWindow(), static_cast<int>(p_key)))
	{
		case GLFW_PRESS:	return EKeyState::KEY_DOWN;
		case GLFW_RELEASE:	return EKeyState::KEY_UP;
	}

	return EKeyState::KEY_UP;
}

OvWindowing::Inputs::EMouseButtonState OvWindowing::Inputs::InputManager::GetMouseButtonState(EMouseButton p_button) const
{
	switch (glfwGetMouseButton(m_window.GetGlfwWindow(), static_cast<int>(p_button)))
	{
		case GLFW_PRESS:	return EMouseButtonState::MOUSE_DOWN;
		case GLFW_RELEASE:	return EMouseButtonState::MOUSE_UP;
	}

	return EMouseButtonState::MOUSE_UP;
}

bool OvWindowing::Inputs::InputManager::IsKeyPressed(EKey p_key) const
{
	return m_keyEvents.find(p_key) != m_keyEvents.end() && m_keyEvents.at(p_key) == EKeyState::KEY_DOWN;
}

bool OvWindowing::Inputs::InputManager::IsKeyReleased(EKey p_key) const
{
	return m_keyEvents.find(p_key) != m_keyEvents.end() && m_keyEvents.at(p_key) == EKeyState::KEY_UP;
}

bool OvWindowing::Inputs::InputManager::IsMouseButtonPressed(EMouseButton p_button) const
{
	return m_mouseButtonEvents.find(p_button) != m_mouseButtonEvents.end() && m_mouseButtonEvents.at(p_button) == EMouseButtonState::MOUSE_DOWN;
}

bool OvWindowing::Inputs::InputManager::IsMouseButtonReleased(EMouseButton p_button) const
{
	return m_mouseButtonEvents.find(p_button) != m_mouseButtonEvents.end() && m_mouseButtonEvents.at(p_button) == EMouseButtonState::MOUSE_UP;
}

std::pair<double, double> OvWindowing::Inputs::InputManager::GetMousePosition() const
{
	std::pair<double, double> result;
	glfwGetCursorPos(m_window.GetGlfwWindow(), &result.first, &result.second);
	return result;
}

void OvWindowing::Inputs::InputManager::ClearEvents()
{
	m_keyEvents.clear();
	m_mouseButtonEvents.clear();
}

void OvWindowing::Inputs::InputManager::OnKeyPressed(int p_key)
{
	m_keyEvents[static_cast<EKey>(p_key)] = EKeyState::KEY_DOWN;
}

void OvWindowing::Inputs::InputManager::OnKeyReleased(int p_key)
{
	m_keyEvents[static_cast<EKey>(p_key)] = EKeyState::KEY_UP;
}

void OvWindowing::Inputs::InputManager::OnMouseButtonPressed(int p_button)
{
	m_mouseButtonEvents[static_cast<EMouseButton>(p_button)] = EMouseButtonState::MOUSE_DOWN;
}

void OvWindowing::Inputs::InputManager::OnMouseButtonReleased(int p_button)
{
	m_mouseButtonEvents[static_cast<EMouseButton>(p_button)] = EMouseButtonState::MOUSE_UP;
}

我們一個個說:

首先建構式,除了把p_window賦給m_window外,還創造了多個監聽,用于得知鍵盤和滑鼠的按鍵是按下了還是釋放了,

解構式則是把咱們之前創建的監聽給移除了,

GetKeyState()用于獲得給定鍵盤按鍵的狀態,內部實作是呼叫了glfw的函式,看當前按鍵在glfw下的狀態,之后轉換到我們定義的狀態,如果這個glfw的狀態在我們的定義中沒有對應,就當作沒有按下按鍵,

GetMouseButtonState()內部實作和作用都和GetKeyState()幾乎一樣,只是一個對鍵盤用,一個對滑鼠用,

IsKeyPressed(),IsKeyReleased(),IsMouseButtonPressed(),IsMouseButtonReleased()這幾個的實作也差不多,功能一看就知,判斷按鍵是被按下還是被釋放,實作都是在我們的事件序列中尋找對應按鍵并和我們需要判斷的狀態作比較,如果既能找到這個按鍵的事件又能和我們希望的狀態匹配,就回傳真值,

GetMousePosition()很簡單,就是獲得當前滑鼠位置,實作依靠glfw,

ClearEvents()是清空全部事件,實作就是把我們保存的鍵盤按鍵事件序列和滑鼠按鍵序列清空,

OnKeyPressed(),OnKeyReleased(),OnMouseButtonPressed(),OnMouseButtonReleased()又是一組類似的函式,用于實時更新按鍵的狀態,當監聽給出回呼時呼叫此函式,把對應按鍵在事件序列中更改狀態,

一些剩下的檔案

我們到這已經把OvWindowing中的檔案基本講完了,但是還有一些我們以前并未提到的檔案,我在此做個收尾作業,

一、DeviceSettings.h

	/**
	* Contains device settings
	*/
	struct DeviceSettings
	{
		/**
		* specifies whether to create a debug OpenGL context, which may have additional error and
		* performance issue reporting functionality. If OpenGL ES is requested, this hint is ignored
		*/
		bool debugProfile = false;

		/**
		* Specifies whether the OpenGL context should be forward-compatible, i.e. one where all functionality
		* deprecated in the requested version of OpenGL is removed. This must only be used if the requested OpenGL
		* version is 3.0 or above. If OpenGL ES is requested, this hint is ignored.
		*/
		bool forwardCompatibility = false;

		/**
		* Specify the client API major version that the created context must be compatible with. The exact
		* behavior of these hints depend on the requested client API
		*/
		uint8_t contextMajorVersion = 3;

		/**
		* Specify the client API minor version that the created context must be compatible with. The exact
		* behavior of these hints depend on the requested client API
		*/
		uint8_t contextMinorVersion = 2;

		/**
		* Defines the amount of samples to use (Requiered for multi-sampling)
		*/
		uint8_t samples = 4;
	};

這些是視窗的一些環境設定,比如是否開啟除錯,是否向前兼容,當前版本號,以及采樣數(用于MSAA),一般這些都是定死的,修改的意義不是很大,我們只要知道有這些,可以改就行了,

二、Window.h

	/**
	* A simple OS-based window.
	* It needs a Device (GLFW) to work
	*/
	class Window
	{
	public:
		/* Inputs relatives */
		OvTools::Eventing::Event<int> KeyPressedEvent;
		OvTools::Eventing::Event<int> KeyReleasedEvent;
		OvTools::Eventing::Event<int> MouseButtonPressedEvent;
		OvTools::Eventing::Event<int> MouseButtonReleasedEvent;

		/* Window events */
		OvTools::Eventing::Event<uint16_t, uint16_t> ResizeEvent;
		OvTools::Eventing::Event<uint16_t, uint16_t> FramebufferResizeEvent;
		OvTools::Eventing::Event<int16_t, int16_t> MoveEvent;
		OvTools::Eventing::Event<int16_t, int16_t> CursorMoveEvent;
		OvTools::Eventing::Event<> MinimizeEvent;
		OvTools::Eventing::Event<> MaximizeEvent;
		OvTools::Eventing::Event<> GainFocusEvent;
		OvTools::Eventing::Event<> LostFocusEvent;
		OvTools::Eventing::Event<> CloseEvent;

		/**
		* Create the window
		* @param p_device
		* @param p_windowSettings
		*/
		Window(const Context::Device& p_device, const Settings::WindowSettings& p_windowSettings);

		/**
		* Destructor of the window, responsible of the GLFW window memory free
		*/
		~Window();

		/**
		* Set Icon
		* @param p_filePath
		*/
		void SetIcon(const std::string& p_filePath);

		/**
		* Set Icon from memory
		* @param p_data
		* @param p_width
		* @param p_height
		*/
		void SetIconFromMemory(uint8_t* p_data, uint32_t p_width, uint32_t p_height);

		/**
		* Find an instance of window with a given GLFWwindow
		* @param p_glfwWindow
		*/
		static Window* FindInstance(GLFWwindow* p_glfwWindow);

		/**
		* Resize the window
		* @param p_width
		* @param p_height
		*/
		void SetSize(uint16_t p_width, uint16_t p_height);

		/**
		* Defines a minimum size for the window
		* @param p_minimumWidth
		* @param p_minimumHeight
		* @note -1 (WindowSettings::DontCare) value means no limitation
		*/
		void SetMinimumSize(int16_t p_minimumWidth, int16_t p_minimumHeight);

		/**
		* Defines a maximum size for the window
		* @param p_maximumWidth
		* @param p_maximumHeight
		* @note -1 (WindowSettings::DontCare) value means no limitation
		*/
		void SetMaximumSize(int16_t p_maximumWidth, int16_t p_maximumHeight);

		/**
		* Define a position for the window
		* @param p_x
		* @param p_y
		*/
		void SetPosition(int16_t p_x, int16_t p_y);

		/**
		* Minimize the window
		*/
		void Minimize() const;

		/**
		* Maximize the window
		*/
		void Maximize() const;

		/**
		* Restore the window
		*/
		void Restore() const;

		/**
		* Hides the specified window if it was previously visible
		*/
		void Hide() const;

		/**
		* Show the specified window if it was previously hidden
		*/
		void Show() const;

		/**
		* Focus the window
		*/
		void Focus() const;

		/**
		* Set the should close flag of the window to true
		* @param p_value
		*/
		void SetShouldClose(bool p_value) const;

		/**
		* Return true if the window should close
		*/
		bool ShouldClose() const;

		/**
		* Set the window in fullscreen or windowed mode
		* @param p_value (True for fullscreen mode, false for windowed)
		*/
		void SetFullscreen(bool p_value);

		/**
		* Switch the window to fullscreen or windowed mode depending
		* on the current state
		*/
		void ToggleFullscreen();

		/**
		* Return true if the window is fullscreen
		*/
		bool IsFullscreen() const;

		/**
		* Return true if the window is hidden
		*/
		bool IsHidden() const;

		/**
		* Return true if the window is visible
		*/
		bool IsVisible() const;

		/**
		* Return true if the windows is maximized
		*/
		bool IsMaximized() const;

		/**
		* Return true if the windows is minimized
		*/
		bool IsMinimized() const;

		/**
		* Return true if the windows is focused
		*/
		bool IsFocused() const;

		/**
		* Return true if the windows is resizable
		*/
		bool IsResizable() const;

		/**
		* Return true if the windows is decorated
		*/
		bool IsDecorated() const;

		/**
		* Define the window as the current context
		*/
		void MakeCurrentContext() const;

		/**
		* Handle the buffer swapping with the current window
		*/
		void SwapBuffers() const;

		/**
		* Define a mode for the mouse cursor
		* @param p_cursorMode
		*/
		void SetCursorMode(Cursor::ECursorMode p_cursorMode);

		/**
		* Define a shape to apply to the current cursor
		* @param p_cursorShape
		*/
		void SetCursorShape(Cursor::ECursorShape p_cursorShape);

		/**
		* Move the cursor to the given position
		*/
		void SetCursorPosition(int16_t p_x, int16_t p_y);

		/**
		* Define a title for the window
		* @param p_title
		*/
		void SetTitle(const std::string& p_title);

		/**
		* Defines a refresh rate (Use WindowSettings::DontCare to use the highest available refresh rate)
		* @param p_refreshRate
		* @note You need to switch to fullscreen mode to apply this effect (Or leave fullscreen and re-apply)
		*/
		void SetRefreshRate(int32_t p_refreshRate);

		/**
		* Return the title of the window
		*/
		std::string GetTitle() const;

		/**
		* Return the current size of the window
		*/
		std::pair<uint16_t, uint16_t> GetSize() const;

		/**
		* Return the current minimum size of the window
		* @note -1 (WindowSettings::DontCare) values means no limitation
		*/
		std::pair<int16_t, int16_t> GetMinimumSize() const;

		/**
		* Return the current maximum size of the window
		* @note -1 (WindowSettings::DontCare) values means no limitation
		*/
		std::pair<int16_t, int16_t> GetMaximumSize() const;

		/**
		* Return the current position of the window
		*/
		std::pair<int16_t, int16_t> GetPosition() const;

		/**
		* Return the framebuffer size (Viewport size)
		*/
		std::pair<uint16_t, uint16_t> GetFramebufferSize() const;

		/**
		* Return the current cursor mode
		*/
		Cursor::ECursorMode GetCursorMode() const;

		/**
		* Return the current cursor shape
		*/
		Cursor::ECursorShape GetCursorShape() const;

		/**
		* Return the current refresh rate (Only applied to the fullscreen mode).
		* If the value is -1 (WindowSettings::DontCare) the highest refresh rate will be used
		*/
		int32_t GetRefreshRate() const;

		/**
		* Return GLFW window
		*/
		GLFWwindow* GetGlfwWindow() const;

	private:
		void CreateGlfwWindow(const Settings::WindowSettings& p_windowSettings);

		/* Callbacks binding */
		void BindKeyCallback() const;
		void BindMouseCallback() const;
		void BindResizeCallback() const;
		void BindFramebufferResizeCallback() const;
		void BindCursorMoveCallback() const;
		void BindMoveCallback() const;
		void BindIconifyCallback() const;
		void BindFocusCallback() const;
		void BindCloseCallback() const;

		/* Event listeners */
		void OnResize(uint16_t p_width, uint16_t p_height);
		void OnMove(int16_t p_x, int16_t p_y);

		/* Internal helpers */
		void UpdateSizeLimit() const;

	private:
		/* This map is used by callbacks to find a "Window" instance out of a "GLFWwindow" instnace*/
		static std::unordered_map<GLFWwindow*, Window*> __WINDOWS_MAP;

		const Context::Device& m_device;
		GLFWwindow* m_glfwWindow;

		/* Window settings */
		std::string m_title;
		std::pair<uint16_t, uint16_t> m_size;
		std::pair<int16_t, int16_t> m_minimumSize;
		std::pair<int16_t, int16_t> m_maximumSize;
		std::pair<int16_t, int16_t> m_position;
		bool m_fullscreen;
		int32_t m_refreshRate;
		Cursor::ECursorMode m_cursorMode;
		Cursor::ECursorShape m_cursorShape;
	};

這個雖說我之前沒有直接提過,但是這里面的函式其實已經全部講過了,就在講Window.cpp的時候,所以我在這就不說了,需要的可以看代碼分析一,

總結

這樣的話,我們已經把Overload其中的一個模塊——OvWindowing給講完了,可喜可賀,之后咱會開始講OvEditor,也就是Overload的主體部分,加油!

Diana

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/323248.html

標籤:其他

上一篇:C語言練習2---猜數字小游戲

下一篇:強化學習筆記3---policy gradient基本概念

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more