fakekey.c (1805B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* fakekey.c 3 * Functions for simulating key presses. 4 * 5 * Copyright (C) 2010 the Speakup Team 6 */ 7#include <linux/types.h> 8#include <linux/slab.h> 9#include <linux/preempt.h> 10#include <linux/percpu.h> 11#include <linux/input.h> 12 13#include "speakup.h" 14 15#define PRESSED 1 16#define RELEASED 0 17 18static DEFINE_PER_CPU(int, reporting_keystroke); 19 20static struct input_dev *virt_keyboard; 21 22int speakup_add_virtual_keyboard(void) 23{ 24 int err; 25 26 virt_keyboard = input_allocate_device(); 27 28 if (!virt_keyboard) 29 return -ENOMEM; 30 31 virt_keyboard->name = "Speakup"; 32 virt_keyboard->id.bustype = BUS_VIRTUAL; 33 virt_keyboard->phys = "speakup/input0"; 34 virt_keyboard->dev.parent = NULL; 35 36 __set_bit(EV_KEY, virt_keyboard->evbit); 37 __set_bit(KEY_DOWN, virt_keyboard->keybit); 38 39 err = input_register_device(virt_keyboard); 40 if (err) { 41 input_free_device(virt_keyboard); 42 virt_keyboard = NULL; 43 } 44 45 return err; 46} 47 48void speakup_remove_virtual_keyboard(void) 49{ 50 if (virt_keyboard) { 51 input_unregister_device(virt_keyboard); 52 virt_keyboard = NULL; 53 } 54} 55 56/* 57 * Send a simulated down-arrow to the application. 58 */ 59void speakup_fake_down_arrow(void) 60{ 61 unsigned long flags; 62 63 /* disable keyboard interrupts */ 64 local_irq_save(flags); 65 /* don't change CPU */ 66 preempt_disable(); 67 68 __this_cpu_write(reporting_keystroke, true); 69 input_report_key(virt_keyboard, KEY_DOWN, PRESSED); 70 input_report_key(virt_keyboard, KEY_DOWN, RELEASED); 71 input_sync(virt_keyboard); 72 __this_cpu_write(reporting_keystroke, false); 73 74 /* reenable preemption */ 75 preempt_enable(); 76 /* reenable keyboard interrupts */ 77 local_irq_restore(flags); 78} 79 80/* 81 * Are we handling a simulated key press on the current CPU? 82 * Returns a boolean. 83 */ 84bool speakup_fake_key_pressed(void) 85{ 86 return this_cpu_read(reporting_keystroke); 87}