J2TEAM Security: A must-have extension for Chrome users. Install now!

Làm thế nào để đi ngủ sớm?

Hướng dẫn học lập trình AutoIt: Khoảng 3, 4 tuần gần đây tớ bắt đầu đi ngủ muộn hơn... Thường thì vào khoảng 3-4 giờ sáng, có hôm là 5 giờ.
sleep
Wow, ngạc nhiên chưa? Một đứa chuyên ngủ muộn viết bài về việc ngủ sớm, haha. Nhưng đúng là tớ, Juno đây. Lâu rồi mới viết blog, hehe!!

Khoảng 3, 4 tuần gần đây tớ bắt đầu đi ngủ muộn hơn... Thường thì vào 3-4 giờ sáng, có hôm là 5 giờ. Trước đây tớ cũng không ngủ sớm nhưng cũng không đến mức muộn như vậy. Và điều tệ nhất là việc ngủ muộn đang bắt đầu ảnh hưởng tới hiệu quả làm việc của cả ngày hôm đó.

Việc tự nói với bản thân "Tôi sẽ đi ngủ sớm!!" có vẻ như không có tác dụng, vậy nên tớ nghĩ mình cần "mạnh tay" hơn... Đúng rồi, xách bàn phím lên và code nào!

coding

Xác định nguyên nhân gây ngủ muộn


Hừm, con trai + cái máy tính thì làm gì mà ngủ muộn nhỉ?

- Xem JAV chứ làm gì!!?

Hầy, toàn nghĩ bậy không à =.=

Sau khi tự theo dõi bản thân thì tớ thấy có hai thứ khiến tớ thức vào khoảng giờ đó:

Code

Có điều chắc chắn là không phải riêng gì tớ mà nhiều bạn dev khác cũng nhận thấy việc code vào ban đêm sẽ tập trung hơn và (thường) có hiệu quả tốt hơn do môi trường làm việc yên tĩnh và thời điểm đó thì thường không có ai quấy rầy bạn. Đó cũng là lý do mà chúng ta hay bị gọi là đám "cú đêm".
lap-trinh-vien

Facebook

Về Facebook, không biết tớ nên vui hay nên buồn khi mà từ lúc J2TEAM Community trở nên phát triển hơn thì cũng là lúc tớ cảm thấy mình đang dần bị... "nghiện Facebook". Đọc thông báo thường xuyên hơn, dành thời gian để duyệt bài cũng như trả lời câu hỏi trong nhóm nhiều hơn,...

Xây dựng chương trình "chống ngủ muộn"


Đã xác định được nguyên nhân rồi thì bắt tay vào code thôi! Tớ sẽ dùng AutoIt vì chương trình này sẽ không quá phức tạp, một ngôn ngữ kịch bản như AutoIt hay AutoHotkey là quá đủ.

Chương trình sẽ bao gồm một vòng lặp với 4 hàm chính như sau:

Diagram

checkTime() sẽ đảm nhận nhiệm vụ kiểm tra xem thời gian hiện tại có thuộc khung giờ mà tớ cần phải... đang nằm ngủ hay không.

Func checkTime()
 Local $h = @HOUR
 Return $h > 0 And $h < 7
EndFunc   ;==>checkTime

Nếu trong khung giờ này, chương trình sẽ gọi tới hàm closeApps() và kiểm tra qua toàn bộ danh sách ứng dụng mà tớ đã khai báo, nếu ứng dụng nào đang mở thì đóng ứng dụng đó.

Func closeApps()
 For $app In $apps
  If WinExists($app) Then WinClose($app)
 Next
EndFunc   ;==>closeApps

Để chắc chắn các ứng dụng này đã ngừng hoạt động, chương trình gọi tiếp hàm closeProcesses(), tìm và đóng các tiến trình của ứng dụng (nếu vẫn đang chạy).

Func closeProcesses()
 For $process In $processes
  _ProcessCloseEx($process)
 Next
EndFunc   ;==>closeProcesses

Khi đã đảm bảo là không còn gì cản trở, chương trình gọi hàm shutdown() để thực hiện tắt máy tính.

Shutdown(5)

Tham số 5 mà tớ truyền vào là sự kết hợp của 2 flag:

  • 1: sử dụng chế độ tắt máy.
  • 4: ép toàn bộ ứng dụng đang chạy phải đóng để không ảnh hưởng tới quá trình tắt máy.

Các bạn sẽ nhận ra việc gọi shutdown(5) hoàn toàn tương đương với việc chạy lệnh sau trong Command Prompt (CMD) của Windows:

shutdown -s -f

Cuối cùng, một hàm main() để liên kết toàn bộ các hàm trên với nhau:

Func main()
 If checkTime() Then
  closeApps()
  Sleep(10000)
  closeProcesses()
  Sleep(5000)
  Shutdown(5) ; Shudown + Force
 EndIf
EndFunc   ;==>main

Khoan đã... Tại sao lại phải dùng những 2 hàm khác nhau với cùng một mục đích là đóng ứng dụng?

Lý do là hàm WinClose() sẽ đóng cửa sổ đúng như cách mà chúng ta nhấn vào nút X ở góc trên cùng bên phải cửa sổ. Đây là cách đóng ứng dụng an toàn, tuy nhiên nếu trong trường hợp người dùng đang viết lách hoặc sử dụng một trang web nào đó chưa lưu xong dữ liệu thì cái hộp thoại xác nhận này sẽ hiện lên:

xac-nhan-thoat


Với 50% khả năng người dùng sẽ nhấn nút "Ở lại" thì chúng ta cần phải kiểm tra lại thêm lần nữa bằng cách đóng tiến trình với hàm _ProcessCloseEx(). Đóng tiến trình là cách tắt ứng dụng một cách ép buộc, nó tương tự với việc chúng ta sử dụng Task Manager để tắt mấy cái ứng dụng bị treo vậy.

Và lưu ý đây là cách tắt ứng dụng không an toàn nên dữ liệu có thể bị mất trong trường hợp người dùng chưa kịp lưu. Đây cũng là một lý do mà vì sao hàm này nên được sử dụng sau WinClose() như một biện pháp dự phòng.

Có vẻ ổn rồi, nhưng tớ cần đăng ký chương trình vào Startup của Windows, điều đó sẽ giúp chương trình tự hoạt động hằng ngày mà mình không cần phải mở thủ công. Có hai cách để thực hiện điều này:

  • Copy file thực thi của chương trình vào thư mục Startup, thường nằm ở đường dẫn: C:\Users\<NAME>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\
  • Đăng ký đường dẫn tới file thực thi của chương trình vào Registry: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run

Thật may, thành viên guinness từ diễn đàn AutoIt đã viết sẵn một UDF sử dụng cả 2 cách trên và chúng ta chỉ việc đơn giản là gọi hàm ra: _StartupFolder_Install() hoặc _StartupRegistry_Install()

Và đây là toàn bộ code của chương trình:

#Region AutoIt3Wrapper directives section
#AutoIt3Wrapper_Icon=juno_okyo.ico
#AutoIt3Wrapper_Compression=4
#AutoIt3Wrapper_UseUpx=Y
#AutoIt3Wrapper_Res_Comment=Developed by Juno_okyo
#AutoIt3Wrapper_Res_Description=Developed by Juno_okyo
#AutoIt3Wrapper_Res_Fileversion=1.0.0.0
#AutoIt3Wrapper_Res_FileVersion_AutoIncrement=Y
#AutoIt3Wrapper_Res_ProductVersion=1.0.0.0
#AutoIt3Wrapper_Res_LegalCopyright=(C) 2017 Juno_okyo. All rights reserved.
#AutoIt3Wrapper_Res_Field=CompanyName|J2TeaM
#AutoIt3Wrapper_Res_Field=Website|https://junookyo.blogspot.com/
#EndRegion AutoIt3Wrapper directives section

#NoTrayIcon
#include <Misc.au3>
#include '_Startup.au3'

Opt('MustDeclareVars', 1)
Opt('WinTitleMatchMode', 2)

_Singleton(@ScriptName)
_StartupRegistry_Install()

Global $apps = ['Google Chrome', 'Sublime Text']
Global $processes = ['chrome.exe', 'sublime_text.exe']

While 1
 Sleep(60000)
 main()
WEnd

Func main()
 If checkTime() Then
  closeApps()
  Sleep(10000)
  closeProcesses()
  Sleep(5000)
  Shutdown(5) ; Shudown + Force
 EndIf
EndFunc   ;==>main

Func checkTime()
 Local $h = @HOUR
 Return $h > 0 And $h < 7
EndFunc   ;==>checkTime

Func _ProcessCloseEx($sPID) ; Author: rasim
 If IsString($sPID) Then $sPID = ProcessExists($sPID)
 If Not $sPID Then Return SetError(1, 0, 0)

 Return RunWait(@ComSpec & ' /c taskkill /F /PID ' & $sPID & ' /T', @SystemDir, @SW_HIDE)
EndFunc   ;==>_ProcessCloseEx

Func closeApps()
 For $app In $apps
  If WinExists($app) Then WinClose($app)
 Next
EndFunc   ;==>closeApps

Func closeProcesses()
 For $process In $processes
  _ProcessCloseEx($process)
 Next
EndFunc   ;==>closeProcesses

Tổng kết


Vì dùng cho mục đích cá nhân nên hiện tại chương trình này khá đơn giản. Sau đây là một số gợi ý cho bạn nào muốn phát triển nó:

  • Tạo thêm GUI (giao diện người dùng) cho phép dễ dàng chọn mốc thời gian đi ngủ cũng như những chương trình nào cần tắt.
  • (*) So sánh với thời gian từ một máy chủ khác thay vì dùng Macro của AutoIt để tránh người dùng thay đổi giờ  trên máy tính > ảnh hưởng tới kết quả chương trình.
  • Phát một bản nhạc gây buồn ngủ khi gần tới giờ chẳng hạn :v
  • Tự động chặn kết nối tới Facebook, Youtube,... sau 12 giờ đêm và mở lại vào sáng hôm sau.
  • ... (tùy sức sáng tạo)

(*) Có lẽ bạn sẽ thắc mắc tại sao tớ không làm luôn phần kiểm tra thời gian? Vì đơn giản với một chương trình được tạo ra để cải thiện bản thân thì nếu mình đã không thích thì sẽ không chạy nó ngay từ đầu chứ không cần phải cheat.

Không biết là chương trình này sẽ có tác dụng hay không, tớ sẽ cập nhật kết quả sau vài hôm nữa. Dù sao thì cũng hi vọng là bài viết này có ích đối với các bạn đang muốn học AutoIt và muốn thử sức tạo ra một vài chương trình nho nhỏ hữu ích cho bản thân.
Leader at J2TEAM. Website: https://j2team.dev/