Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
Signed-off-by: James Knight <james.d.knight@live.com>
  • Loading branch information
jdknight committed Feb 18, 2024
0 parents commit fa42ccf
Show file tree
Hide file tree
Showing 12 changed files with 181 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# ignore cmake output directories
/out*/
15 changes: 15 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright jdknight

cmake_minimum_required(VERSION 3.11)
project(capsblock)

set(BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(INC_DIR ${BASE_DIR}/src)
set(SRC_DIR ${BASE_DIR}/src/capsblock)
include(${BASE_DIR}/support.cmake)

include(${BASE_DIR}/sources.cmake)
include_directories(${INC_DIR})

add_executable(capsblock WIN32 ${CAPSBLOCK_SRCS})
install (TARGETS capsblock RUNTIME DESTINATION bin)
22 changes: 22 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Copyright jdknight

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Caps Block

## Overview

Provides the ability in Windows to help force the Caps Lock key in a toggled
off state while still allowing programs to use the key.

This application was created with the goal of supporting the Caps Lock key
as a voice key for various voice-supporting applications. Users can use the
key to trigger a voice event, but also reduce the chance that the Caps Lock
key is left enabled.
2 changes: 2 additions & 0 deletions scripts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# ignore built executable if dropped here
capsblock.exe
16 changes: 16 additions & 0 deletions scripts/install.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@echo off
setlocal enabledelayedexpansion

set script_path=%~dp0
set base_path=%script_path:~0,-1%
set exe_path="%base_path%\capsblock.exe"

if exist %exe_path% (
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run /t REG_SZ ^
/v "Caps Block" /d "%exe_path%" /f >NUL
if !ERRORLEVEL! neq 0 exit /b !ERRORLEVEL!

echo Caps Block has been configured to startup.
) else (
echo Caps Block executable is missing!
)
2 changes: 2 additions & 0 deletions scripts/shutdown.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@echo off
taskkill /f /im capsblock.exe
3 changes: 3 additions & 0 deletions scripts/uninstall.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@echo off
reg delete HKCU\Software\Microsoft\Windows\CurrentVersion\Run ^
/v "Caps Block" /f >NUL
6 changes: 6 additions & 0 deletions sources.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright jdknight

set(CAPSBLOCK_SRCS
${SRC_DIR}/capsblock.rc
${SRC_DIR}/main.c
)
21 changes: 21 additions & 0 deletions src/capsblock/capsblock.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright jdknight

#include "winres.h"

VS_VERSION_INFO VERSIONINFO
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "jdknight"
VALUE "FileDescription", "Caps Block"
VALUE "LegalCopyright", "Copyright (C) jdknight"
VALUE "ProductName", "Caps Block"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
68 changes: 68 additions & 0 deletions src/capsblock/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright jdknight

#include <stdbool.h>
#include <stdio.h>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>

// state to suppress hook events when generating new caps-lock events
volatile bool gSkip = false;

// invoked when a low-level keyboard event occurs
LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM msg, LPARAM ctx)
{
// listen for key-up events of the caps-lock key
if (!gSkip && !code >= 0 && msg == WM_KEYUP) {
KBDLLHOOKSTRUCT* kbd = (KBDLLHOOKSTRUCT*)ctx;
if (kbd->vkCode == VK_CAPITAL) {
// check if we have caps-lock enabled in our current state
bool hasCapsLock = ((GetKeyState(VK_CAPITAL) & 0x0001) != 0);
if (hasCapsLock) {
// before we attempt to toggle off the caps-lock state,
// flag our hook as disabled, to ensure we do not attempt
// to process the state of any caps-lock keys issued from
// our hook
gSkip = true;

// generate two additional key events:
///
// 1) a key-up event to "complete" the toggled on state
// 2) a key-down event to trigger a new caps-lock event
//
// do not consume this active event, to complete the final
// key-up event
INPUT input[2] = {0};
input[0].type = input[1].type = INPUT_KEYBOARD;
input[0].ki.wVk = input[1].ki.wVk = VK_CAPITAL;
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(2, input, sizeof(INPUT));

// after issuing our key changes, re-enable this hook
gSkip = false;
}
}
}

return CallNextHookEx(NULL, code, msg, ctx);
}

#pragma warning(disable: 4100)
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR pCmdLine, int nCmdShow)
{
// create a hook to listen for keyboard events
HHOOK hook = SetWindowsHookEx(
WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0);
if (!hook) {
fprintf(stderr, "unable to create keyboard hook\n");
return 1;
}

// consume all messages
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) != 0);

return 0;
}
13 changes: 13 additions & 0 deletions support.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright jdknight

# targeting c11
set(CMAKE_C_STANDARD 11)

# force c support (ensures MSVC has been processed)
enable_language(C)

# enable warnings
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")

# force unicode
add_definitions(-DUNICODE -D_UNICODE)

0 comments on commit fa42ccf

Please sign in to comment.