vim 常用快捷鍵

本篇記錄一下 Linux vim 文字編輯器的常用快捷鍵,特別是trace code時,善用快捷鍵會快很多,效率大幅提升。

名稱 Linux 備註
Go to Definition Ctrl+] 跳至定義處(要配合用ctags)
Navigate Back Ctrl+t 返回
Retrace your movements in file in backwards Ctrl+o 往後
Retrace your movements in file in forwards. Ctrl+i 往前
Find Usage / Find Reference :cs find s 要配合用cscope

參考
In vim, how do I go back to where I was before a search? - Stack Overflow
https://stackoverflow.com/questions/53911/in-vim-how-do-i-go-back-to-where-i-was-before-a-search
VIM: Jump Back To Previous or Last Cursor Position - nixCraft
https://www.cyberciti.biz/faq/unix-linux-vim-go-back-to-last-cursor-position/

其它相關文章推薦
Visual Studio Code 常用快捷鍵
Qt Creator 常用快捷鍵

Python 多重繼承 multiple inheritance

本篇介紹 Python 多重繼承 multiple inheritance 的寫法,

Python 多重繼承(Multiple Inheritance)的寫法

Python multiple inheritance 最簡單的多重繼承寫法如下,
有 BaseClass1, BaseClass2, DerivedClass 三個類別
DerivedClass 多重繼承 BaseClass1 和 BaseClass2

python-multiple-inheritance.py
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

class BaseClass1:
pass

class BaseClass2:
pass

class DerivedClass(BaseClass1, BaseClass2):
pass

derived = DerivedClass()

方法覆寫(Method Overriding)

Dog3 多重繼承了 Dog1 和 Dog2,如果沒有覆寫父類的 eat,呼叫子類 Dog3.eat() 時會繼承的前面/左邊父類(Dog1)方法優先,

python-multiple-inheritance2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

class Dog1:
def eat(self):
print("Dog1 class eat method is called.")

class Dog2:
def eat(self):
print("Dog2 class eat method is called.")

class Dog3(Dog1, Dog2):
pass

dog = Dog3()
dog.eat()

結果輸出如下,

1
Dog1 class eat method is called.

子類建構子(Constructor)傳遞參數到父類建構子

在多重繼承的情況下,子類建構子又是如何傳遞參數到父類的建構子,這邊來介紹一下,
呼叫

python-multiple-inheritance3.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

class Dog1:
def __init__(self, name):
print("Dog1 ", name)

def eat(self):
print("Dog1 class eat method is called.")

class Dog2:
def __init__(self, sex):
print("Dog2 ", sex)

def eat(self):
print("Dog2 class eat method is called.")

class Dog3(Dog2):
def __init__(self, sex):
print("Dog3 ", sex)
Dog2.__init__(self, sex)

def eat(self):
print("Dog3 class eat method is called.")

class Dog4(Dog1, Dog3):
def __init__(self, name, sex):
Dog1.__init__(self, name)
Dog3.__init__(self, sex)

#dog = Dog4(name="Harry", sex="female")
dog = Dog4("Harry", "female")
dog.eat()

結果輸出如下,

1
2
3
4
Dog1  Harry
Dog3 female
Dog2 female
Dog1 class eat method is called.

參考
Classes — Python 3.9.0 documentation
https://docs.python.org/3/tutorial/classes.html#multiple-inheritance
Python 速查手冊 - 6.9 多重繼承
http://kaiching.org/pydoing/py/python-multiple-inheritance.html
程式語言教學誌 FB, YouTube: PYDOING: Python 3.1 快速導覽 - 類別 多重繼承
https://pydoing.blogspot.com/2011/01/python-multiple.html
Python-QA/Python多重繼承屬性問題.md at master · dokelung/Python-QA
https://github.com/dokelung/Python-QA/blob/master/questions/object/Python%E5%A4%9A%E9%87%8D%E7%B9%BC%E6%89%BF%E5%B1%AC%E6%80%A7%E5%95%8F%E9%A1%8C.md

其它相關文章推薦
如果你想學習 Python 相關技術,可以參考看看下面的文章,
Python 繼承
Python 新手入門教學懶人包
Python str 字串用法與範例
Python list 串列用法與範例
Python set 集合用法與範例
Python dict 字典用法與範例
Python tuple 元組用法與範例
Python 字串分割 split
Python 取代字元或取代字串 replace
Python 讓程式 sleep 延遲暫停時間

Ecslipse C++ 參考其他專案符號的設定方式

本篇紀錄在 Ecslipse C++ 專案裡要參考到其他專案的符號定義的設定方式,
在原專案中的選項裡,

1
C/C++ General -> Paths and Symbols -> References

選擇要參考哪些專案(被參考的專案一定要是open project的狀態,不能 close 的狀態),
按下確定索引完後回到原專案中在外部專案的符號定義裡使用跳至定義處便能跳至被參考的專案符號定義了。

參考
What is the difference between “Project References” and “Paths and Symbols -> References” in Eclipse CDT? - Stack Overflow
https://stackoverflow.com/questions/12701633/what-is-the-difference-between-project-references-and-paths-and-symbols-re

相關主題
C/C++ 新手入門教學懶人包
Eclipse 啟用 C++11 語法高亮與解析
Eclipse 索引(index)額外的定義
Eclipse 常用快捷鍵

Python 繼承 inheritance

本篇介紹 Python 繼承 inheritance 的寫法,物件導向程式設計 OOP 中繼承是很重要的觀念,學習正確的觀念有助於在軟體設計中重複利用程式碼與維護性。

Python 繼承(Inheritance)的寫法

Python inheritance 最簡單的繼承寫法如下,
有 BaseClass1, BaseClass2, DerivedClass 兩個類別
DerivedClass 繼承 BaseClass,
並且實例化

python-inheritance.py
1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

class BaseClass:
pass

class DerivedClass(BaseClass):
pass

derived = DerivedClass()

方法覆寫(Method Overriding)

這邊介紹子類如何去覆寫父類的方法,
Dog2 繼承了 Dog1,呼叫子類 Dog2.eat() 時會有下列兩種情形,
如果子類有覆寫會以子類方法為優先,如本範例一樣,
如果子類沒覆寫會繼承父類方法為優先,

python-inheritance2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

class Dog1:
def eat(self):
print("Dog1 class eat method is called.")

class Dog2(Dog1):
def eat(self):
print("Dog2 class eat method is called.")

dog = Dog2()
dog.eat()

Dog2 繼承 Dog1,Dog2 子類覆寫 Dog1 父類的 eat 方法,
結果輸出如下,

1
Dog2 class eat method is called.

子類建構子(Constructor)傳遞參數到父類建構子

這邊介紹子類建構子如何傳遞參數到父類的建構子,
子類呼叫父類的建構子有兩種方式,
一種是使用 super()
另一種是直接指定呼叫父類的建構子,
這邊兩種方法都會介紹到,

python-inheritance3.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

class Dog1:
def __init__(self, name):
print("Dog1 ", name)

def eat(self):
print("Dog1 class eat method is called.")

class Dog2(Dog1):
def __init__(self, name): # 跟父類一樣的參數
print("Dog2 ", name)
super().__init__(name)

def eat(self):
print("Dog2 class eat method is called.")

class Dog3(Dog1):
def __init__(self, name, sex): # 比父類多一個參數
print("Dog3 ", name, sex)
Dog1.__init__(self, name) # 也可以指定呼叫父類的建構子

dog = Dog2("Jimmy")
dog.eat()

dog = Dog3("Harry", "female")
dog.eat()

Dog2 繼承 Dog1,Dog2 建構時使用 super() 來呼叫父類建構子,
Dog3 繼承 Dog1,Dog3 建構時是直接指定呼叫 Dog1 父類的建構子,
結果輸出如下,

1
2
3
4
5
6
Dog2  Jimmy
Dog1 Jimmy
Dog2 class eat method is called.
Dog3 Harry female
Dog1 Harry
Dog1 class eat method is called.

以上就是 Python inheritance 繼承的基本觀念與用法的介紹,下一篇會來介紹 Python 多重繼承

參考
Classes — Python 3.9.0 documentation
https://docs.python.org/3/tutorial/classes.html#inheritance
Python 繼承 543. 相信寫 OOP 的人對於繼承這個概念應該不陌生,Python 身為一個支援… | by Dboy Liao | Medium
https://medium.com/@dboyliao/python-%E7%B9%BC%E6%89%BF-543-bc3d8ef51d6d
[Python物件導向]Python繼承(Inheritance)實用教學
https://www.learncodewithmike.com/2020/01/python-inheritance.html

其它相關文章推薦
如果你想學習 Python 相關技術,可以參考看看下面的文章,
Python 多重繼承
Python 新手入門教學懶人包
Python str 字串用法與範例
Python list 串列用法與範例
Python set 集合用法與範例
Python dict 字典用法與範例
Python tuple 元組用法與範例
Python 字串分割 split
Python 取代字元或取代字串 replace
Python 讓程式 sleep 延遲暫停時間

Qt Creator 常用快捷鍵

本篇記錄一下 Qt 常用快捷鍵,在trace code時善用快捷鍵會快很多,效率大幅提升。

以下快捷鍵以 Qt 5.12.2 為主,其他版本應該大同小異,

名稱 Windows macOS Linux 備註
跳至定義處 (Follow Symbol Under Cursor) F2 F2 F2 Go to Definition
返回 (Go Back) Alt+ Alt+ 試不出來 Alt+
前進 (Go Forward) Alt + Alt + Alt +
查看誰有使用到它 (Find References to Symbol Under Cursor Ctrl+Shift+U Ctrl+Shift+U 舊版叫Find Usage
左右括號之間跳轉 (Go to Bracket)

透過下列路徑可以搜尋查詢更多的快捷鍵或更換,

1
Tools > Options > Environment > Keyboard > Keyboard Shortcuts

其它相關文章推薦
Visual Studio Code 常用快捷鍵
vim 常用快捷鍵
[Qt] 讀檔,讀取 txt 文字檔
[Qt] 寫檔,寫入 txt 文字檔

Linux kill 指令砍掉指定的 process name

本篇介紹如何使用 kill 指令來砍掉特定的應用程式名稱 process name,
kill 指令用法是後面是接 process id,例如:kill <pid>,或者kill -9 <pid>
但通常我們都只知道應用程式的名稱,所以通常一般直接使用killall <process_name>pkill -f <process_name>就可砍掉 process,

但假設今天有個情況非得要用 kill 來砍 process name 要怎麼做?

所以通常會用先用 ps 列出所有 process 再 grep 該 process name 才知道 pid 是多少,
今天來個組合技搭配 awk 讓這件事在一行指令就完成,假設我們要砍的應用程式名稱為 a.out,
最後要串接kill <pid>指令如下,

1
$ ps -A | grep a.out | awk '{print $2}' | xargs kill

或者使用kill -9 <pid>的形式

1
$ ps -A | grep a.out | awk '{print $2}' | xargs kill -9

其他參考
Linux 使用 應用程式名稱 來砍掉 Process | Tsung’s Blog
https://blog.longwin.com.tw/2012/06/linux-kill-process-by-name-2012/
linux - How can I kill a process by name instead of PID? - Stack Overflow
https://stackoverflow.com/questions/160924/how-can-i-kill-a-process-by-name-instead-of-pid
在 Linux 中使用 kill、killall 與 xkill 等指令強迫關閉程式 - G. T. Wang
https://blog.gtwang.org/linux/linux-kill-killall-xkill/

其它相關文章推薦
Linux 常用指令教學懶人包
Linux find 尋找檔案/尋找資料夾用法與範例
Linux sed 字串取代用法與範例
Linux cut 字串處理用法與範例
Linux tail 持續監看檔案輸出用法與範例
Linux ag 搜尋字串用法與範例(比 grep 還快)

開源專案scrcpy-讓Android投影/鏡射到電腦,還可鍵盤滑鼠操控

今天介紹Github上開源專案scrcpy,可以讓Android手機平板投影/鏡射到電腦,還可鍵盤滑鼠操控,scrcpy是一個免費開源的螢幕鏡像應用程式,scrcpy允許從Windows,macOS或Linux電腦端控制Android裝置。該軟體由Genymobile公司開發。

Android裝置與電腦之間的通訊主要透過USB連線和adb(Android Debug Bridge)執行。該軟體透過在Android裝置上執行服務器,然後通過ADB通道上的套接字與服務器通信來運行。scrcpy它不需要在Android裝置上root或安裝App軟體。Android裝置螢幕的內容將會編碼成H.264視訊串流傳輸給電腦端,然後由電腦端解碼並顯示畫面出來。該軟體也將鍵盤和滑鼠輸入透過過服務器推送到Android裝置裡。

Genymobile/scrcpy

Github:https://github.com/Genymobile/scrcpy
星星數:37.9kstars
技術:ClientC,Makefile,SDL, Server端Java
目前最新版為1.16,只有Windows有提供預編譯的版本,macOS可透過brew下載安裝,
Ubuntu 20.04可用apt安裝否則其他Linux需要自行編譯,

特色

  • 輕量(僅顯示裝置的螢幕)
  • 性能(30~60FPS)
  • 畫質(1920 x 1080含以上)
  • 低延遲(35ms~70ms)
  • 啟動時間短(不到1秒就能顯示第一張影像)
  • 無須安裝任何應用

設備最低要求

  • Android 5.0(API 21)以上
  • 需開啟USB除錯模式
  • 在部分裝置需開啟其他選項

操作說明

windows可以參考
https://junyou.tw/scrcpy/
https://www.playpcesor.com/2019/08/scrcpy-app-android.html
macOS可以參考
https://pjchender.blogspot.com/2020/05/mobile-android-mac-pc-scrcpy.html

其它相關文章推薦
開源專案CursorJail-滑鼠鎖定工具
開源專案-2048
開源專案-tetris俄羅斯方塊
開源專案-數獨sudoku
開源專案-金庸群俠傳
開源專案-仙劍奇俠傳

macOS 用 Homebrew 安裝 git 指令

本篇紀錄在 macOS 下用 Homebrew 安裝 git 指令與 git gui (gitk),macOS 內建沒有 git 指令所以需要自行安裝,
macOS 請先安裝 Homebrew,請參考官網教學安裝,macOS 有安裝過 Homebrew 也請更新,

1
brew update

Homebrew最新的版本為2.4.16

1
2
3
4
$ brew --version
Homebrew 2.4.16-39-g48c6dc8
Homebrew/homebrew-core (git revision 158ad0; last commit 2020-09-01)
Homebrew/homebrew-cask (git revision c1c3f; last commit 2020-09-01)

macOS 安裝 git 指令

接下來透過 Homebrew 安裝 git 指令

1
$ brew install git

如果之前已經透過 Homebrew 安裝 git 過,他應該會提示你用brew upgrade升級的指令,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ brew install git
Updating Homebrew...
==> Downloading https://homebrew.bintray.com/bottles/pcre2-10.35.high_sierra.bot
==> Downloading from https://d29vzk4ow07wi7.cloudfront.net/69c4fb400d19d1910df33
######################################################################## 100.0%
==> Downloading https://homebrew.bintray.com/bottles/git-2.28.0.high_sierra.bott
==> Downloading from https://d29vzk4ow07wi7.cloudfront.net/5095b064dfafb8cf4cabd
######################################################################## 100.0%
Error: git 2.2.0 is already installed
To upgrade to 2.28.0, run `brew upgrade git`.
$ brew upgrade git
Updating Homebrew...
==> Upgrading 1 outdated package:
git 2.2.0 -> 2.28.0
==> Upgrading git 2.2.0 -> 2.28.0
==> Downloading https://homebrew.bintray.com/bottles/pcre2-10.35.high_sierra.bot
...

查看一下安裝 git 的版本,本次升級完 git 的版本為 2.28

1
2
$ git version
git version 2.28.0

which 指令檢查一下 git 指令是位在 /usr/local/bin/git
且軟連結到/usr/local/Cellar/git/2.28.0/bin/git

1
2
3
4
$ which git
/usr/local/bin/git
$ ls -al /usr/local/bin/git
lrwxr-xr-x 1 shengyu admin 28 9 1 22:35 /usr/local/bin/git -> ../Cellar/git/2.28.0/bin/git

macOS 安裝 gitk / git-gui

接下來透過 Homebrew 安裝 gitk 指令,安裝完後就可以使用 gitk 指令了

1
$ brew install git-gui

which 指令檢查一下 gitk 指令是位在 /usr/local/bin/gitk
且軟連結到/usr/local/Cellar/git-gui/2.28.0/bin/gitk

1
2
3
4
$ which gitk
/usr/local/bin/gitk
$ ls -al /usr/local/bin/gitk
lrwxr-xr-x 1 shengyu admin 33 9 1 22:37 /usr/local/bin/gitk -> ../Cellar/git-gui/2.28.0/bin/gitk

之前 git 2.2.0 時使用 gitk 明顯地畫質還沒跟上高解析度的螢幕,
經過這次的升級到 2.28.0 後,這 gitk 畫質不足問題已經獲得改善。

C++ std::function 用法與範例

本篇介紹 C++ 的 std::function 的用法教學,std::function 是 C++11 中加入的一個通用函數包裝器,它能夠將函數、函數物件(可調用物件)以及 Lambda 表達式等作為參數,儲存到一個物件中,並隨時調用這個函數。本文將說明 std::function 的基本用法及範例,詳情請繼續往下閱讀。

要使用 std::function 需要引入的標頭檔<functional>

std::function 基本用法

以下是 std::function 的基本用法及範例,在這個範例中,我們首先定義了一個名為 add 的函數,它接受兩個整數參數並回傳它們的總和。然後我們使用 std::function 來定義了一個函數物件 func,並將其初始化為指向 add 函數的指標。最後,我們通過函數物件 func 來調用 add 函數,傳遞兩個整數參數,並輸出它們的總和。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <functional>

// 定義一個函數,接受兩個 int 參數並回傳它們的總和
int add(int a, int b) {
return a + b;
}

int main() {
// 定義一個 std::function 物件,指向 add 函數
std::function<int(int, int)> func = add;

// 使用函數物件調用 add 函數
std::cout << "Sum: " << func(3, 4) << std::endl;

return 0;
}

結果輸入如下,

1
Sum: 7

使用 Lambda 表達式

在這個範例中,我們定義了一個匿名 Lambda 函數,它接受兩個整數參數並回傳它們的積。然後,我們使用 std::function 來定義了一個函數物件 func,並將其初始化為這個 Lambda 函數。最後,我們通過函數物件 func 來調用 Lambda 函數,傳遞兩個整數參數,並輸出它們的相乘結果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <functional>

int main() {
// 定義一個 std::function 物件,使用 Lambda 表達式
std::function<int(int, int)> func = [](int a, int b) {
return a * b;
};

// 使用函數物件調用 Lambda 函數
std::cout << "Product: " << func(3, 4) << std::endl;

return 0;
}

結果輸入如下,

1
Product: 12

std::function 作為函數參數傳遞

在這個範例中,我們定義了一個名為 process 的函數,它接受一個 std::function 物件作為參數,以及兩個整數參數 ab。在 main 函數中,我們使用 Lambda 表達式來建立一個函數物件,並將其作為參數傳遞給 process 函數。在 process 函數內部,我們通過傳入的函數物件來執行相應的操作,並輸出結果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <functional>

// 函數接受一個函數物件作為參數
void process(std::function<int(int, int)> func, int a, int b) {
std::cout << "Result: " << func(a, b) << std::endl;
}

int main() {
// 使用 Lambda 表達式作為函數參數
process([](int a, int b) { return a / b; }, 6, 2);

return 0;
}

結果輸入如下,

1
Result: 3

std::function 提供了一個方便的方法來處理函數指標、函數物件和 Lambda 表達式,使得 C++ 中的函數操作更加靈活和方便。

在實務上也常用到 std::function 來做 callback 回調函式的的,詳細請見下範例,

用 std::function 取代傳統的 function pointer

讓我們先來看看一段使用傳統的 function pointer 的範例,

function-pointer-callback.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// g++ function-pointer-callback.cpp -o a.out
#include <iostream>
#include <string>
using namespace std;

void keyevent(int keycode, int status) {
cout << "keycode = " << keycode << " status = " << status << endl;
}

int main() {
void (*callback_keyevent)(int, int) = NULL;
callback_keyevent = keyevent;

if (callback_keyevent)
callback_keyevent(1, 0);

return 0;
}

改成 std::function 後變成這樣

std-function-callback.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// g++ std-function-callback.cpp -o a.out -std=c++11
#include <iostream>
#include <string>
#include <functional>
using namespace std;

void keyevent(int keycode, int status) {
cout << "keycode = " << keycode << " status = " << status << endl;
}

int main() {
std::function<void(int, int)> callback_keyevent = nullptr;
callback_keyevent = keyevent;

if (callback_keyevent)
callback_keyevent(1, 0);

return 0;
}

使用 std::function 的優點

使用 std::function 取代傳統的函數指標(function pointer)有幾個優點:

  1. 可讀性佳:使用 std::function 可以使程式碼更易讀和理解。當你看到一個 std::function 物件時,你立即知道它是一個函數物件,並且可以通過調用該物件來執行相應的操作。這比看到函數指標或其他較為抽象的函數表示形式更直觀。

  2. 可接受 Lambda 函式std::function 可以輕鬆地接受 Lambda 表達式,這使得程式碼更加現代化和易於閱讀。Lambda 表達式通常用於定義簡單的、局部的函數行為,而 std::function 的能力可以讓你將這些 Lambda 表達式作為函數物件使用,從而使程式碼更加簡潔和易於理解。

  3. 更靈活的函數封裝std::function 可以封裝函數指標、函數物件、Lambda 表達式等,使得函數的使用更加靈活。這意味著你可以使用 std::function 來處理更多類型的函數。

  4. 更容易進行函數替換:由於 std::function 可以接受不同類型的函數物件,因此當你需要替換函數時,只需要將新的函數賦值給 std::function 物件即可,而無需修改函數指標的類型。

  5. 不受函數簽名限制:使用函數指標時,你必須確保函數指標的類型與所指向函數的簽名完全匹配。但是,使用 std::function 可以輕鬆地接受不同簽名的函數,從而提供了更大的彈性。

  6. 提供了函數物件的拷貝和賦值能力std::function 物件可以被拷貝和賦值,這使得函數的傳遞和儲存更加方便。

總體來說,std::function 提供了一個更加現代化、靈活且安全的方法來處理函數,並且在許多場景下更加方便和易於使用。

以上就是 C++ std::function 用法與範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其他參考
[1] std::function - cppreference.com
https://en.cppreference.com/w/cpp/utility/functional/function
[2] function::function - C++ Reference
http://www.cplusplus.com/reference/functional/function/function/
[3] C++11 std::function的用法 - 滴酱的个人空间 - OSCHINA
https://my.oschina.net/u/2274890/blog/499159
[4] C++11 std::function用法-码农场
https://www.hankcs.com/program/cpp/c11-std-function-usage.html
[5] Cocos2d-x 的 onKeyPressed 與 onKeyReleased
https://github.com/cocos2d/cocos2d-x/blob/e3438ed3fd10a304b7ca2cd3dad9b29fead818d2/cocos/base/CCEventListenerKeyboard.h
https://github.com/cocos2d/cocos2d-x/blob/e3438ed3fd10a304b7ca2cd3dad9b29fead818d2/cocos/base/CCEventListenerKeyboard.cpp
https://github.com/cocos2d/cocos2d-x/blob/e3438ed3fd10a304b7ca2cd3dad9b29fead818d2/tests/performance-tests/Classes/tests/PerformanceEventDispatcherTest.cpp
cocos2d-x 在 PerformanceEventDispatcherTest.cpp 的 KeyboardEventDispatchingPerfTest::generateTestFunctions 使用 onKeyPressed 接收一個 lambda 函式
[6] 邁向王者的旅途: 簡介 std::function (C++11 後的新功能)
https://shininglionking.blogspot.com/2017/01/stdfunction-c11.html
[7] Should I use std::function or a function pointer in C++? - Stack Overflow
https://stackoverflow.com/questions/25848690/should-i-use-stdfunction-or-a-function-pointer-in-c
這篇討論提到應該盡量使用 std::function 來取代 function pointer,除非有什麼其他特殊原因
[8] 在 C++ 裡傳遞、儲存函式 Part 3:Function Object in TR1 – Heresy’s Space
https://kheresy.wordpress.com/2010/11/12/function_object_tr1/

其它相關文章推薦
C/C++ 新手入門教學懶人包
std::thread 用法與範例
C++ std::sort 排序用法與範例完整介紹
std::queue 用法與範例
C++ virtual 的兩種用法
C/C++ 判斷檔案是否存在
C++ 設計模式 - 單例模式 Singleton Pattern
C/C++ call by value傳值, call by pointer傳址, call by reference傳參考 的差別

Ubuntu 安裝 TP-Link Archer T4U Driver 筆記

本篇紀錄 Ubuntu 安裝 TP-Link Archer T4U Driver 筆記與心得,最近買了一隻 wireless dongle,升級成5G(802.11ac)網速,當然家中還要搭配 AP 也是要支援到5G,但之前我早已把家裡網路上升級成 Giga 等級以及具備有 5G 的 AP 了,但我常用環境為 Ubuntu,但這隻 dongle 似乎還沒被預設的 Ubuntu 系統支援,我試了Ubuntu 16.04、18.04、20.04 內建驅動都無法支援,雖然當初在買的時候就從外包裝盒發現沒有 linux 的圖示,只有 windows 與 macOS 圖示,但憑著一股熱情,只好自己手動來編譯安裝了。

查詢 wireless dongle 的 chipset

接下來要首先需要確定的是這隻 wireless dongle 用的是什麼 chipset,這對於曾經在網通廠工作經驗豐富的我不算什麼問題,

  1. 找一下該 wireless dongle 是第幾版,我購買的 TP-Link Archer T4U 的版本是 v3.20,通常在外盒上可以找到或者 dongle 本體上的標籤,為什麼要查詢版本呢?因為有時候同型號,廠商可能後來改用不同的 chipset,通常都是 costdown,也有可能是其他因素。

  2. 在網路上 Google 一下,即可發現 TP-Link Archer T4U V3 用的 chipset 為 Realtek 的 RTL8812BU,
    而 TP-Link Archer T4U V2 以前都是使用 RTL8812AU,
    所以要找的驅動是要找 RTL8812BU 而不是 RTL8812AU,不然就會安裝後也無法使用,
    http://en.techinfodepot.shoutwiki.com/wiki/TP-LINK_Archer_T4U_v3

編譯驅動並安裝

我是參考 https://askubuntu.com/questions/802205/how-to-install-tp-link-archer-t4u-driver
這篇的第二個方法,適用於 RTL8812BU chipset,
第一個方法是 RTL8812AU

這裡就順便記錄一下我的步驟
以下步驟我在 Ubuntu 18.04, 16.04 編譯後安裝後都是可以成功連線的,

1
2
3
4
5
6
git clone https://github.com/EntropicEffect/rtl8822bu
sudo apt-get install build-essential dkms # 安裝編譯所需套件
cd rtl8822bu
make # 編譯
sudo make install # 安裝至系統
sudo modprobe 88x2bu # 載入驅動模組

到這裡以上的步驟就可以連線了,可以發現網路管理員已經可以掃描的到其他 WiFi 的 SSID 了,
不論是 2.4G 或 5G 都掃得到了,也可以成功連線~YA!

輸入下列指令完善一下整個安裝,
其目的是讓 Linux 核心升級也自動重新編譯一下該驅動程式,
否則之後 Linux 核心升級後該驅動不匹配就會無法使用,

1
2
sudo dkms add . # 將驅動程式加入 DKMS 管理表中
sudo dkms install -m 88x2bu -v 1.1

其他未驗證的參考
https://itectec.com/ubuntu/ubuntu-cant-install-tp-link-archer-t4u-v3-driver-on-19-04/
https://gist.github.com/tchelit/289881a73df5189431cd6070b72f3f61

其他補充

查看目前 dkms 內有什麼

1
sudo dkms status

安裝驅動模組

1
sudo dkms install -m 88x2bu -v 1.1

解除安裝驅動模組

1
sudo dkms uninstall -m 88x2bu -v 1.1

完整移除整個驅動程式模組

1
sudo dkms remove 88x2bu/1.1 --all

modprobe 指令

1
2
sudo modprobe 88x2bu # 載入模組
sudo modprobe -r 88x2bu # 卸載模組

insmod、rmmod 與 lsmod

1
2
3
insmod 88x2bu.ko # 載入模組
rmmod 88x2bu # 卸載模組
lsmod # 查看載入的模組

其他參考
核心模組的載入與移除: insmod, modprobe, rmmod
http://mingyi-ulinux.blogspot.com/2009/01/insmod-modprobe-rmmod.html
Linux DKMS 機制導入筆記 - 石頭閒語
http://rocksaying.tw/archives/2015/Linux_DKMS_%E6%A9%9F%E5%88%B6%E5%B0%8E%E5%85%A5%E7%AD%86%E8%A8%98.html
DKMS简介 - wwang - 博客园
https://www.cnblogs.com/wwang/archive/2011/06/21/2085571.html
DKMS的流程圖邏輯很清晰

其它相關文章推薦
使用 Unetbootin 建立 Ubuntu Live USB 且可以儲存資料
Ubuntu apt update 的一堆 error 問題與解決方法